security/nss/lib/base/utf8.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/base/utf8.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,726 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * utf8.c
    1.10 + *
    1.11 + * This file contains some additional utility routines required for
    1.12 + * handling UTF8 strings.
    1.13 + */
    1.14 +
    1.15 +#ifndef BASE_H
    1.16 +#include "base.h"
    1.17 +#endif /* BASE_H */
    1.18 +
    1.19 +#include "plstr.h"
    1.20 +
    1.21 +/*
    1.22 + * NOTES:
    1.23 + *
    1.24 + * There's an "is hex string" function in pki1/atav.c.  If we need
    1.25 + * it in more places, pull that one out.
    1.26 + */
    1.27 +
    1.28 +/*
    1.29 + * nssUTF8_CaseIgnoreMatch
    1.30 + * 
    1.31 + * Returns true if the two UTF8-encoded strings pointed to by the 
    1.32 + * two specified NSSUTF8 pointers differ only in typcase.
    1.33 + *
    1.34 + * The error may be one of the following values:
    1.35 + *  NSS_ERROR_INVALID_POINTER
    1.36 + *
    1.37 + * Return value:
    1.38 + *  PR_TRUE if the strings match, ignoring case
    1.39 + *  PR_FALSE if they don't
    1.40 + *  PR_FALSE upon error
    1.41 + */
    1.42 +
    1.43 +NSS_IMPLEMENT PRBool
    1.44 +nssUTF8_CaseIgnoreMatch
    1.45 +(
    1.46 +  const NSSUTF8 *a,
    1.47 +  const NSSUTF8 *b,
    1.48 +  PRStatus *statusOpt
    1.49 +)
    1.50 +{
    1.51 +#ifdef NSSDEBUG
    1.52 +  if( ((const NSSUTF8 *)NULL == a) ||
    1.53 +      ((const NSSUTF8 *)NULL == b) ) {
    1.54 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
    1.55 +    if( (PRStatus *)NULL != statusOpt ) {
    1.56 +      *statusOpt = PR_FAILURE;
    1.57 +    }
    1.58 +    return PR_FALSE;
    1.59 +  }
    1.60 +#endif /* NSSDEBUG */
    1.61 +
    1.62 +  if( (PRStatus *)NULL != statusOpt ) {
    1.63 +    *statusOpt = PR_SUCCESS;
    1.64 +  }
    1.65 +
    1.66 +  /*
    1.67 +   * XXX fgmr
    1.68 +   *
    1.69 +   * This is, like, so wrong!
    1.70 +   */
    1.71 +  if( 0 == PL_strcasecmp((const char *)a, (const char *)b) ) {
    1.72 +    return PR_TRUE;
    1.73 +  } else {
    1.74 +    return PR_FALSE;
    1.75 +  }
    1.76 +}
    1.77 +
    1.78 +/*
    1.79 + * nssUTF8_PrintableMatch
    1.80 + *
    1.81 + * Returns true if the two Printable strings pointed to by the 
    1.82 + * two specified NSSUTF8 pointers match when compared with the 
    1.83 + * rules for Printable String (leading and trailing spaces are 
    1.84 + * disregarded, extents of whitespace match irregardless of length, 
    1.85 + * and case is not significant), then PR_TRUE will be returned.
    1.86 + * Otherwise, PR_FALSE will be returned.  Upon failure, PR_FALSE
    1.87 + * will be returned.  If the optional statusOpt argument is not
    1.88 + * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that
    1.89 + * location.
    1.90 + *
    1.91 + * The error may be one of the following values:
    1.92 + *  NSS_ERROR_INVALID_POINTER
    1.93 + *
    1.94 + * Return value:
    1.95 + *  PR_TRUE if the strings match, ignoring case
    1.96 + *  PR_FALSE if they don't
    1.97 + *  PR_FALSE upon error
    1.98 + */
    1.99 +
   1.100 +NSS_IMPLEMENT PRBool
   1.101 +nssUTF8_PrintableMatch
   1.102 +(
   1.103 +  const NSSUTF8 *a,
   1.104 +  const NSSUTF8 *b,
   1.105 +  PRStatus *statusOpt
   1.106 +)
   1.107 +{
   1.108 +  PRUint8 *c;
   1.109 +  PRUint8 *d;
   1.110 +
   1.111 +#ifdef NSSDEBUG
   1.112 +  if( ((const NSSUTF8 *)NULL == a) ||
   1.113 +      ((const NSSUTF8 *)NULL == b) ) {
   1.114 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.115 +    if( (PRStatus *)NULL != statusOpt ) {
   1.116 +      *statusOpt = PR_FAILURE;
   1.117 +    }
   1.118 +    return PR_FALSE;
   1.119 +  }
   1.120 +#endif /* NSSDEBUG */
   1.121 +
   1.122 +  if( (PRStatus *)NULL != statusOpt ) {
   1.123 +    *statusOpt = PR_SUCCESS;
   1.124 +  }
   1.125 +
   1.126 +  c = (PRUint8 *)a;
   1.127 +  d = (PRUint8 *)b;
   1.128 +
   1.129 +  while( ' ' == *c ) {
   1.130 +    c++;
   1.131 +  }
   1.132 +
   1.133 +  while( ' ' == *d ) {
   1.134 +    d++;
   1.135 +  }
   1.136 +
   1.137 +  while( ('\0' != *c) && ('\0' != *d) ) {
   1.138 +    PRUint8 e, f;
   1.139 +
   1.140 +    e = *c;
   1.141 +    f = *d;
   1.142 +    
   1.143 +    if( ('a' <= e) && (e <= 'z') ) {
   1.144 +      e -= ('a' - 'A');
   1.145 +    }
   1.146 +
   1.147 +    if( ('a' <= f) && (f <= 'z') ) {
   1.148 +      f -= ('a' - 'A');
   1.149 +    }
   1.150 +
   1.151 +    if( e != f ) {
   1.152 +      return PR_FALSE;
   1.153 +    }
   1.154 +
   1.155 +    c++;
   1.156 +    d++;
   1.157 +
   1.158 +    if( ' ' == *c ) {
   1.159 +      while( ' ' == *c ) {
   1.160 +        c++;
   1.161 +      }
   1.162 +      c--;
   1.163 +    }
   1.164 +
   1.165 +    if( ' ' == *d ) {
   1.166 +      while( ' ' == *d ) {
   1.167 +        d++;
   1.168 +      }
   1.169 +      d--;
   1.170 +    }
   1.171 +  }
   1.172 +
   1.173 +  while( ' ' == *c ) {
   1.174 +    c++;
   1.175 +  }
   1.176 +
   1.177 +  while( ' ' == *d ) {
   1.178 +    d++;
   1.179 +  }
   1.180 +
   1.181 +  if( *c == *d ) {
   1.182 +    /* And both '\0', btw */
   1.183 +    return PR_TRUE;
   1.184 +  } else {
   1.185 +    return PR_FALSE;
   1.186 +  }
   1.187 +}
   1.188 +
   1.189 +/*
   1.190 + * nssUTF8_Duplicate
   1.191 + *
   1.192 + * This routine duplicates the UTF8-encoded string pointed to by the
   1.193 + * specified NSSUTF8 pointer.  If the optional arenaOpt argument is
   1.194 + * not null, the memory required will be obtained from that arena;
   1.195 + * otherwise, the memory required will be obtained from the heap.
   1.196 + * A pointer to the new string will be returned.  In case of error,
   1.197 + * an error will be placed on the error stack and NULL will be 
   1.198 + * returned.
   1.199 + *
   1.200 + * The error may be one of the following values:
   1.201 + *  NSS_ERROR_INVALID_POINTER
   1.202 + *  NSS_ERROR_INVALID_ARENA
   1.203 + *  NSS_ERROR_NO_MEMORY
   1.204 + */
   1.205 +
   1.206 +NSS_IMPLEMENT NSSUTF8 *
   1.207 +nssUTF8_Duplicate
   1.208 +(
   1.209 +  const NSSUTF8 *s,
   1.210 +  NSSArena *arenaOpt
   1.211 +)
   1.212 +{
   1.213 +  NSSUTF8 *rv;
   1.214 +  PRUint32 len;
   1.215 +
   1.216 +#ifdef NSSDEBUG
   1.217 +  if( (const NSSUTF8 *)NULL == s ) {
   1.218 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.219 +    return (NSSUTF8 *)NULL;
   1.220 +  }
   1.221 +
   1.222 +  if( (NSSArena *)NULL != arenaOpt ) {
   1.223 +    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
   1.224 +      return (NSSUTF8 *)NULL;
   1.225 +    }
   1.226 +  }
   1.227 +#endif /* NSSDEBUG */
   1.228 +
   1.229 +  len = PL_strlen((const char *)s);
   1.230 +#ifdef PEDANTIC
   1.231 +  if( '\0' != ((const char *)s)[ len ] ) {
   1.232 +    /* must have wrapped, e.g., too big for PRUint32 */
   1.233 +    nss_SetError(NSS_ERROR_NO_MEMORY);
   1.234 +    return (NSSUTF8 *)NULL;
   1.235 +  }
   1.236 +#endif /* PEDANTIC */
   1.237 +  len++; /* zero termination */
   1.238 +
   1.239 +  rv = nss_ZAlloc(arenaOpt, len);
   1.240 +  if( (void *)NULL == rv ) {
   1.241 +    return (NSSUTF8 *)NULL;
   1.242 +  }
   1.243 +
   1.244 +  (void)nsslibc_memcpy(rv, s, len);
   1.245 +  return rv;
   1.246 +}
   1.247 +
   1.248 +/*
   1.249 + * nssUTF8_Size
   1.250 + *
   1.251 + * This routine returns the length in bytes (including the terminating
   1.252 + * null) of the UTF8-encoded string pointed to by the specified
   1.253 + * NSSUTF8 pointer.  Zero is returned on error.
   1.254 + *
   1.255 + * The error may be one of the following values:
   1.256 + *  NSS_ERROR_INVALID_POINTER
   1.257 + *  NSS_ERROR_VALUE_TOO_LARGE
   1.258 + *
   1.259 + * Return value:
   1.260 + *  0 on error
   1.261 + *  nonzero length of the string.
   1.262 + */
   1.263 +
   1.264 +NSS_IMPLEMENT PRUint32
   1.265 +nssUTF8_Size
   1.266 +(
   1.267 +  const NSSUTF8 *s,
   1.268 +  PRStatus *statusOpt
   1.269 +)
   1.270 +{
   1.271 +  PRUint32 sv;
   1.272 +
   1.273 +#ifdef NSSDEBUG
   1.274 +  if( (const NSSUTF8 *)NULL == s ) {
   1.275 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.276 +    if( (PRStatus *)NULL != statusOpt ) {
   1.277 +      *statusOpt = PR_FAILURE;
   1.278 +    }
   1.279 +    return 0;
   1.280 +  }
   1.281 +#endif /* NSSDEBUG */
   1.282 +
   1.283 +  sv = PL_strlen((const char *)s) + 1;
   1.284 +#ifdef PEDANTIC
   1.285 +  if( '\0' != ((const char *)s)[ sv-1 ] ) {
   1.286 +    /* wrapped */
   1.287 +    nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
   1.288 +    if( (PRStatus *)NULL != statusOpt ) {
   1.289 +      *statusOpt = PR_FAILURE;
   1.290 +    }
   1.291 +    return 0;
   1.292 +  }
   1.293 +#endif /* PEDANTIC */
   1.294 +
   1.295 +  if( (PRStatus *)NULL != statusOpt ) {
   1.296 +    *statusOpt = PR_SUCCESS;
   1.297 +  }
   1.298 +
   1.299 +  return sv;
   1.300 +}
   1.301 +
   1.302 +/*
   1.303 + * nssUTF8_Length
   1.304 + *
   1.305 + * This routine returns the length in characters (not including the
   1.306 + * terminating null) of the UTF8-encoded string pointed to by the
   1.307 + * specified NSSUTF8 pointer.
   1.308 + *
   1.309 + * The error may be one of the following values:
   1.310 + *  NSS_ERROR_INVALID_POINTER
   1.311 + *  NSS_ERROR_VALUE_TOO_LARGE
   1.312 + *  NSS_ERROR_INVALID_STRING
   1.313 + *
   1.314 + * Return value:
   1.315 + *  length of the string (which may be zero)
   1.316 + *  0 on error
   1.317 + */
   1.318 +
   1.319 +NSS_IMPLEMENT PRUint32
   1.320 +nssUTF8_Length
   1.321 +(
   1.322 +  const NSSUTF8 *s,
   1.323 +  PRStatus *statusOpt
   1.324 +)
   1.325 +{
   1.326 +  PRUint32 l = 0;
   1.327 +  const PRUint8 *c = (const PRUint8 *)s;
   1.328 +
   1.329 +#ifdef NSSDEBUG
   1.330 +  if( (const NSSUTF8 *)NULL == s ) {
   1.331 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.332 +    goto loser;
   1.333 +  }
   1.334 +#endif /* NSSDEBUG */
   1.335 +
   1.336 +  /*
   1.337 +   * From RFC 2044:
   1.338 +   *
   1.339 +   * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
   1.340 +   * 0000 0000-0000 007F   0xxxxxxx
   1.341 +   * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
   1.342 +   * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx
   1.343 +   * 0001 0000-001F FFFF   11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   1.344 +   * 0020 0000-03FF FFFF   111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   1.345 +   * 0400 0000-7FFF FFFF   1111110x 10xxxxxx ... 10xxxxxx
   1.346 +   */  
   1.347 +
   1.348 +  while( 0 != *c ) {
   1.349 +    PRUint32 incr;
   1.350 +    if( (*c & 0x80) == 0 ) {
   1.351 +      incr = 1;
   1.352 +    } else if( (*c & 0xE0) == 0xC0 ) {
   1.353 +      incr = 2;
   1.354 +    } else if( (*c & 0xF0) == 0xE0 ) {
   1.355 +      incr = 3;
   1.356 +    } else if( (*c & 0xF8) == 0xF0 ) {
   1.357 +      incr = 4;
   1.358 +    } else if( (*c & 0xFC) == 0xF8 ) {
   1.359 +      incr = 5;
   1.360 +    } else if( (*c & 0xFE) == 0xFC ) {
   1.361 +      incr = 6;
   1.362 +    } else {
   1.363 +      nss_SetError(NSS_ERROR_INVALID_STRING);
   1.364 +      goto loser;
   1.365 +    }
   1.366 +
   1.367 +    l += incr;
   1.368 +
   1.369 +#ifdef PEDANTIC
   1.370 +    if( l < incr ) {
   1.371 +      /* Wrapped-- too big */
   1.372 +      nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
   1.373 +      goto loser;
   1.374 +    }
   1.375 +
   1.376 +    {
   1.377 +      PRUint8 *d;
   1.378 +      for( d = &c[1]; d < &c[incr]; d++ ) {
   1.379 +        if( (*d & 0xC0) != 0xF0 ) {
   1.380 +          nss_SetError(NSS_ERROR_INVALID_STRING);
   1.381 +          goto loser;
   1.382 +        }
   1.383 +      }
   1.384 +    }
   1.385 +#endif /* PEDANTIC */
   1.386 +
   1.387 +    c += incr;
   1.388 +  }
   1.389 +
   1.390 +  if( (PRStatus *)NULL != statusOpt ) {
   1.391 +    *statusOpt = PR_SUCCESS;
   1.392 +  }
   1.393 +
   1.394 +  return l;
   1.395 +
   1.396 + loser:
   1.397 +  if( (PRStatus *)NULL != statusOpt ) {
   1.398 +    *statusOpt = PR_FAILURE;
   1.399 +  }
   1.400 +
   1.401 +  return 0;
   1.402 +}
   1.403 +
   1.404 +
   1.405 +/*
   1.406 + * nssUTF8_Create
   1.407 + *
   1.408 + * This routine creates a UTF8 string from a string in some other
   1.409 + * format.  Some types of string may include embedded null characters,
   1.410 + * so for them the length parameter must be used.  For string types
   1.411 + * that are null-terminated, the length parameter is optional; if it
   1.412 + * is zero, it will be ignored.  If the optional arena argument is
   1.413 + * non-null, the memory used for the new string will be obtained from
   1.414 + * that arena, otherwise it will be obtained from the heap.  This
   1.415 + * routine may return NULL upon error, in which case it will have
   1.416 + * placed an error on the error stack.
   1.417 + *
   1.418 + * The error may be one of the following:
   1.419 + *  NSS_ERROR_INVALID_POINTER
   1.420 + *  NSS_ERROR_NO_MEMORY
   1.421 + *  NSS_ERROR_UNSUPPORTED_TYPE
   1.422 + *
   1.423 + * Return value:
   1.424 + *  NULL upon error
   1.425 + *  A non-null pointer to a new UTF8 string otherwise
   1.426 + */
   1.427 +
   1.428 +extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */
   1.429 +
   1.430 +NSS_IMPLEMENT NSSUTF8 *
   1.431 +nssUTF8_Create
   1.432 +(
   1.433 +  NSSArena *arenaOpt,
   1.434 +  nssStringType type,
   1.435 +  const void *inputString,
   1.436 +  PRUint32 size /* in bytes, not characters */
   1.437 +)
   1.438 +{
   1.439 +  NSSUTF8 *rv = NULL;
   1.440 +
   1.441 +#ifdef NSSDEBUG
   1.442 +  if( (NSSArena *)NULL != arenaOpt ) {
   1.443 +    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
   1.444 +      return (NSSUTF8 *)NULL;
   1.445 +    }
   1.446 +  }
   1.447 +
   1.448 +  if( (const void *)NULL == inputString ) {
   1.449 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.450 +    return (NSSUTF8 *)NULL;
   1.451 +  }
   1.452 +#endif /* NSSDEBUG */
   1.453 +
   1.454 +  switch( type ) {
   1.455 +  case nssStringType_DirectoryString:
   1.456 +    /* This is a composite type requiring BER */
   1.457 +    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
   1.458 +    break;
   1.459 +  case nssStringType_TeletexString:
   1.460 +    /*
   1.461 +     * draft-ietf-pkix-ipki-part1-11 says in part:
   1.462 +     *
   1.463 +     * In addition, many legacy implementations support names encoded 
   1.464 +     * in the ISO 8859-1 character set (Latin1String) but tag them as 
   1.465 +     * TeletexString.  The Latin1String includes characters used in 
   1.466 +     * Western European countries which are not part of the 
   1.467 +     * TeletexString charcter set.  Implementations that process 
   1.468 +     * TeletexString SHOULD be prepared to handle the entire ISO 
   1.469 +     * 8859-1 character set.[ISO 8859-1].
   1.470 +     */
   1.471 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.472 +    break;
   1.473 +  case nssStringType_PrintableString:
   1.474 +    /*
   1.475 +     * PrintableString consists of A-Za-z0-9 ,()+,-./:=?
   1.476 +     * This is a subset of ASCII, which is a subset of UTF8.
   1.477 +     * So we can just duplicate the string over.
   1.478 +     */
   1.479 +
   1.480 +    if( 0 == size ) {
   1.481 +      rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
   1.482 +    } else {
   1.483 +      rv = nss_ZAlloc(arenaOpt, size+1);
   1.484 +      if( (NSSUTF8 *)NULL == rv ) {
   1.485 +        return (NSSUTF8 *)NULL;
   1.486 +      }
   1.487 +
   1.488 +      (void)nsslibc_memcpy(rv, inputString, size);
   1.489 +    }
   1.490 +
   1.491 +    break;
   1.492 +  case nssStringType_UniversalString:
   1.493 +    /* 4-byte unicode */
   1.494 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.495 +    break;
   1.496 +  case nssStringType_BMPString:
   1.497 +    /* Base Multilingual Plane of Unicode */
   1.498 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.499 +    break;
   1.500 +  case nssStringType_UTF8String:
   1.501 +    if( 0 == size ) {
   1.502 +      rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt);
   1.503 +    } else {
   1.504 +      rv = nss_ZAlloc(arenaOpt, size+1);
   1.505 +      if( (NSSUTF8 *)NULL == rv ) {
   1.506 +        return (NSSUTF8 *)NULL;
   1.507 +      }
   1.508 +
   1.509 +      (void)nsslibc_memcpy(rv, inputString, size);
   1.510 +    }
   1.511 +
   1.512 +    break;
   1.513 +  case nssStringType_PHGString:
   1.514 +    /* 
   1.515 +     * PHGString is an IA5String (with case-insensitive comparisons).
   1.516 +     * IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has
   1.517 +     * currency symbol.
   1.518 +     */
   1.519 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.520 +    break;
   1.521 +  case nssStringType_GeneralString:
   1.522 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.523 +    break;
   1.524 +  default:
   1.525 +    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
   1.526 +    break;
   1.527 +  }
   1.528 +
   1.529 +  return rv;
   1.530 +}
   1.531 +
   1.532 +NSS_IMPLEMENT NSSItem *
   1.533 +nssUTF8_GetEncoding
   1.534 +(
   1.535 +  NSSArena *arenaOpt,
   1.536 +  NSSItem *rvOpt,
   1.537 +  nssStringType type,
   1.538 +  NSSUTF8 *string
   1.539 +)
   1.540 +{
   1.541 +  NSSItem *rv = (NSSItem *)NULL;
   1.542 +  PRStatus status = PR_SUCCESS;
   1.543 +
   1.544 +#ifdef NSSDEBUG
   1.545 +  if( (NSSArena *)NULL != arenaOpt ) {
   1.546 +    if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
   1.547 +      return (NSSItem *)NULL;
   1.548 +    }
   1.549 +  }
   1.550 +
   1.551 +  if( (NSSUTF8 *)NULL == string ) {
   1.552 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.553 +    return (NSSItem *)NULL;
   1.554 +  }
   1.555 +#endif /* NSSDEBUG */
   1.556 +
   1.557 +  switch( type ) {
   1.558 +  case nssStringType_DirectoryString:
   1.559 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.560 +    break;
   1.561 +  case nssStringType_TeletexString:
   1.562 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.563 +    break;
   1.564 +  case nssStringType_PrintableString:
   1.565 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.566 +    break;
   1.567 +  case nssStringType_UniversalString:
   1.568 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.569 +    break;
   1.570 +  case nssStringType_BMPString:
   1.571 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.572 +    break;
   1.573 +  case nssStringType_UTF8String:
   1.574 +    {
   1.575 +      NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt);
   1.576 +      if( (NSSUTF8 *)NULL == dup ) {
   1.577 +        return (NSSItem *)NULL;
   1.578 +      }
   1.579 +
   1.580 +      if( (NSSItem *)NULL == rvOpt ) {
   1.581 +        rv = nss_ZNEW(arenaOpt, NSSItem);
   1.582 +        if( (NSSItem *)NULL == rv ) {
   1.583 +          (void)nss_ZFreeIf(dup);
   1.584 +          return (NSSItem *)NULL;
   1.585 +        }
   1.586 +      } else {
   1.587 +        rv = rvOpt;
   1.588 +      }
   1.589 +
   1.590 +      rv->data = dup;
   1.591 +      dup = (NSSUTF8 *)NULL;
   1.592 +      rv->size = nssUTF8_Size(rv->data, &status);
   1.593 +      if( (0 == rv->size) && (PR_SUCCESS != status) ) {
   1.594 +        if( (NSSItem *)NULL == rvOpt ) {
   1.595 +          (void)nss_ZFreeIf(rv);
   1.596 +        }
   1.597 +        return (NSSItem *)NULL;
   1.598 +      }
   1.599 +    }
   1.600 +    break;
   1.601 +  case nssStringType_PHGString:
   1.602 +    nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */
   1.603 +    break;
   1.604 +  default:
   1.605 +    nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE);
   1.606 +    break;
   1.607 +  }
   1.608 +
   1.609 +  return rv;
   1.610 +}
   1.611 +
   1.612 +/*
   1.613 + * nssUTF8_CopyIntoFixedBuffer
   1.614 + *
   1.615 + * This will copy a UTF8 string into a fixed-length buffer, making 
   1.616 + * sure that the all characters are valid.  Any remaining space will
   1.617 + * be padded with the specified ASCII character, typically either 
   1.618 + * null or space.
   1.619 + *
   1.620 + * Blah, blah, blah.
   1.621 + */
   1.622 +
   1.623 +NSS_IMPLEMENT PRStatus
   1.624 +nssUTF8_CopyIntoFixedBuffer
   1.625 +(
   1.626 +  NSSUTF8 *string,
   1.627 +  char *buffer,
   1.628 +  PRUint32 bufferSize,
   1.629 +  char pad
   1.630 +)
   1.631 +{
   1.632 +  PRUint32 stringSize = 0;
   1.633 +
   1.634 +#ifdef NSSDEBUG
   1.635 +  if( (char *)NULL == buffer ) {
   1.636 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.637 +    return PR_FALSE;
   1.638 +  }
   1.639 +
   1.640 +  if( 0 == bufferSize ) {
   1.641 +    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
   1.642 +    return PR_FALSE;
   1.643 +  }
   1.644 +
   1.645 +  if( (pad & 0x80) != 0x00 ) {
   1.646 +    nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
   1.647 +    return PR_FALSE;
   1.648 +  }
   1.649 +#endif /* NSSDEBUG */
   1.650 +
   1.651 +  if( (NSSUTF8 *)NULL == string ) {
   1.652 +    string = (NSSUTF8 *) "";
   1.653 +  }
   1.654 +
   1.655 +  stringSize = nssUTF8_Size(string, (PRStatus *)NULL);
   1.656 +  stringSize--; /* don't count the trailing null */
   1.657 +  if( stringSize > bufferSize ) {
   1.658 +    PRUint32 bs = bufferSize;
   1.659 +    (void)nsslibc_memcpy(buffer, string, bufferSize);
   1.660 +    
   1.661 +    if( (            ((buffer[ bs-1 ] & 0x80) == 0x00)) ||
   1.662 +        ((bs > 1) && ((buffer[ bs-2 ] & 0xE0) == 0xC0)) ||
   1.663 +        ((bs > 2) && ((buffer[ bs-3 ] & 0xF0) == 0xE0)) ||
   1.664 +        ((bs > 3) && ((buffer[ bs-4 ] & 0xF8) == 0xF0)) ||
   1.665 +        ((bs > 4) && ((buffer[ bs-5 ] & 0xFC) == 0xF8)) ||
   1.666 +        ((bs > 5) && ((buffer[ bs-6 ] & 0xFE) == 0xFC)) ) {
   1.667 +      /* It fit exactly */
   1.668 +      return PR_SUCCESS;
   1.669 +    }
   1.670 +
   1.671 +    /* Too long.  We have to trim the last character */
   1.672 +    for( /*bs*/; bs != 0; bs-- ) {
   1.673 +      if( (buffer[bs-1] & 0xC0) != 0x80 ) {
   1.674 +        buffer[bs-1] = pad;
   1.675 +        break;
   1.676 +      } else {
   1.677 +        buffer[bs-1] = pad;
   1.678 +      }
   1.679 +    }      
   1.680 +  } else {
   1.681 +    (void)nsslibc_memset(buffer, pad, bufferSize);
   1.682 +    (void)nsslibc_memcpy(buffer, string, stringSize);
   1.683 +  }
   1.684 +
   1.685 +  return PR_SUCCESS;
   1.686 +}
   1.687 +
   1.688 +/*
   1.689 + * nssUTF8_Equal
   1.690 + *
   1.691 + */
   1.692 +
   1.693 +NSS_IMPLEMENT PRBool
   1.694 +nssUTF8_Equal
   1.695 +(
   1.696 +  const NSSUTF8 *a,
   1.697 +  const NSSUTF8 *b,
   1.698 +  PRStatus *statusOpt
   1.699 +)
   1.700 +{
   1.701 +  PRUint32 la, lb;
   1.702 +
   1.703 +#ifdef NSSDEBUG
   1.704 +  if( ((const NSSUTF8 *)NULL == a) ||
   1.705 +      ((const NSSUTF8 *)NULL == b) ) {
   1.706 +    nss_SetError(NSS_ERROR_INVALID_POINTER);
   1.707 +    if( (PRStatus *)NULL != statusOpt ) {
   1.708 +      *statusOpt = PR_FAILURE;
   1.709 +    }
   1.710 +    return PR_FALSE;
   1.711 +  }
   1.712 +#endif /* NSSDEBUG */
   1.713 +
   1.714 +  la = nssUTF8_Size(a, statusOpt);
   1.715 +  if( 0 == la ) {
   1.716 +    return PR_FALSE;
   1.717 +  }
   1.718 +
   1.719 +  lb = nssUTF8_Size(b, statusOpt);
   1.720 +  if( 0 == lb ) {
   1.721 +    return PR_FALSE;
   1.722 +  }
   1.723 +
   1.724 +  if( la != lb ) {
   1.725 +    return PR_FALSE;
   1.726 +  }
   1.727 +
   1.728 +  return nsslibc_memequal(a, b, la, statusOpt);
   1.729 +}

mercurial