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 +}