| OLD | NEW |
| (Empty) |
| 1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 4 | |
| 5 #ifdef DEBUG | |
| 6 static const char CVS_ID[] = "@(#) $RCSfile: utf8.c,v $ $Revision: 1.8 $ $Date:
2012/04/25 14:49:26 $"; | |
| 7 #endif /* DEBUG */ | |
| 8 | |
| 9 /* | |
| 10 * utf8.c | |
| 11 * | |
| 12 * This file contains some additional utility routines required for | |
| 13 * handling UTF8 strings. | |
| 14 */ | |
| 15 | |
| 16 #ifndef BASE_H | |
| 17 #include "base.h" | |
| 18 #endif /* BASE_H */ | |
| 19 | |
| 20 #include "plstr.h" | |
| 21 | |
| 22 /* | |
| 23 * NOTES: | |
| 24 * | |
| 25 * There's an "is hex string" function in pki1/atav.c. If we need | |
| 26 * it in more places, pull that one out. | |
| 27 */ | |
| 28 | |
| 29 /* | |
| 30 * nssUTF8_CaseIgnoreMatch | |
| 31 * | |
| 32 * Returns true if the two UTF8-encoded strings pointed to by the | |
| 33 * two specified NSSUTF8 pointers differ only in typcase. | |
| 34 * | |
| 35 * The error may be one of the following values: | |
| 36 * NSS_ERROR_INVALID_POINTER | |
| 37 * | |
| 38 * Return value: | |
| 39 * PR_TRUE if the strings match, ignoring case | |
| 40 * PR_FALSE if they don't | |
| 41 * PR_FALSE upon error | |
| 42 */ | |
| 43 | |
| 44 NSS_IMPLEMENT PRBool | |
| 45 nssUTF8_CaseIgnoreMatch | |
| 46 ( | |
| 47 const NSSUTF8 *a, | |
| 48 const NSSUTF8 *b, | |
| 49 PRStatus *statusOpt | |
| 50 ) | |
| 51 { | |
| 52 #ifdef NSSDEBUG | |
| 53 if( ((const NSSUTF8 *)NULL == a) || | |
| 54 ((const NSSUTF8 *)NULL == b) ) { | |
| 55 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 56 if( (PRStatus *)NULL != statusOpt ) { | |
| 57 *statusOpt = PR_FAILURE; | |
| 58 } | |
| 59 return PR_FALSE; | |
| 60 } | |
| 61 #endif /* NSSDEBUG */ | |
| 62 | |
| 63 if( (PRStatus *)NULL != statusOpt ) { | |
| 64 *statusOpt = PR_SUCCESS; | |
| 65 } | |
| 66 | |
| 67 /* | |
| 68 * XXX fgmr | |
| 69 * | |
| 70 * This is, like, so wrong! | |
| 71 */ | |
| 72 if( 0 == PL_strcasecmp((const char *)a, (const char *)b) ) { | |
| 73 return PR_TRUE; | |
| 74 } else { | |
| 75 return PR_FALSE; | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 /* | |
| 80 * nssUTF8_PrintableMatch | |
| 81 * | |
| 82 * Returns true if the two Printable strings pointed to by the | |
| 83 * two specified NSSUTF8 pointers match when compared with the | |
| 84 * rules for Printable String (leading and trailing spaces are | |
| 85 * disregarded, extents of whitespace match irregardless of length, | |
| 86 * and case is not significant), then PR_TRUE will be returned. | |
| 87 * Otherwise, PR_FALSE will be returned. Upon failure, PR_FALSE | |
| 88 * will be returned. If the optional statusOpt argument is not | |
| 89 * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that | |
| 90 * location. | |
| 91 * | |
| 92 * The error may be one of the following values: | |
| 93 * NSS_ERROR_INVALID_POINTER | |
| 94 * | |
| 95 * Return value: | |
| 96 * PR_TRUE if the strings match, ignoring case | |
| 97 * PR_FALSE if they don't | |
| 98 * PR_FALSE upon error | |
| 99 */ | |
| 100 | |
| 101 NSS_IMPLEMENT PRBool | |
| 102 nssUTF8_PrintableMatch | |
| 103 ( | |
| 104 const NSSUTF8 *a, | |
| 105 const NSSUTF8 *b, | |
| 106 PRStatus *statusOpt | |
| 107 ) | |
| 108 { | |
| 109 PRUint8 *c; | |
| 110 PRUint8 *d; | |
| 111 | |
| 112 #ifdef NSSDEBUG | |
| 113 if( ((const NSSUTF8 *)NULL == a) || | |
| 114 ((const NSSUTF8 *)NULL == b) ) { | |
| 115 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 116 if( (PRStatus *)NULL != statusOpt ) { | |
| 117 *statusOpt = PR_FAILURE; | |
| 118 } | |
| 119 return PR_FALSE; | |
| 120 } | |
| 121 #endif /* NSSDEBUG */ | |
| 122 | |
| 123 if( (PRStatus *)NULL != statusOpt ) { | |
| 124 *statusOpt = PR_SUCCESS; | |
| 125 } | |
| 126 | |
| 127 c = (PRUint8 *)a; | |
| 128 d = (PRUint8 *)b; | |
| 129 | |
| 130 while( ' ' == *c ) { | |
| 131 c++; | |
| 132 } | |
| 133 | |
| 134 while( ' ' == *d ) { | |
| 135 d++; | |
| 136 } | |
| 137 | |
| 138 while( ('\0' != *c) && ('\0' != *d) ) { | |
| 139 PRUint8 e, f; | |
| 140 | |
| 141 e = *c; | |
| 142 f = *d; | |
| 143 | |
| 144 if( ('a' <= e) && (e <= 'z') ) { | |
| 145 e -= ('a' - 'A'); | |
| 146 } | |
| 147 | |
| 148 if( ('a' <= f) && (f <= 'z') ) { | |
| 149 f -= ('a' - 'A'); | |
| 150 } | |
| 151 | |
| 152 if( e != f ) { | |
| 153 return PR_FALSE; | |
| 154 } | |
| 155 | |
| 156 c++; | |
| 157 d++; | |
| 158 | |
| 159 if( ' ' == *c ) { | |
| 160 while( ' ' == *c ) { | |
| 161 c++; | |
| 162 } | |
| 163 c--; | |
| 164 } | |
| 165 | |
| 166 if( ' ' == *d ) { | |
| 167 while( ' ' == *d ) { | |
| 168 d++; | |
| 169 } | |
| 170 d--; | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 while( ' ' == *c ) { | |
| 175 c++; | |
| 176 } | |
| 177 | |
| 178 while( ' ' == *d ) { | |
| 179 d++; | |
| 180 } | |
| 181 | |
| 182 if( *c == *d ) { | |
| 183 /* And both '\0', btw */ | |
| 184 return PR_TRUE; | |
| 185 } else { | |
| 186 return PR_FALSE; | |
| 187 } | |
| 188 } | |
| 189 | |
| 190 /* | |
| 191 * nssUTF8_Duplicate | |
| 192 * | |
| 193 * This routine duplicates the UTF8-encoded string pointed to by the | |
| 194 * specified NSSUTF8 pointer. If the optional arenaOpt argument is | |
| 195 * not null, the memory required will be obtained from that arena; | |
| 196 * otherwise, the memory required will be obtained from the heap. | |
| 197 * A pointer to the new string will be returned. In case of error, | |
| 198 * an error will be placed on the error stack and NULL will be | |
| 199 * returned. | |
| 200 * | |
| 201 * The error may be one of the following values: | |
| 202 * NSS_ERROR_INVALID_POINTER | |
| 203 * NSS_ERROR_INVALID_ARENA | |
| 204 * NSS_ERROR_NO_MEMORY | |
| 205 */ | |
| 206 | |
| 207 NSS_IMPLEMENT NSSUTF8 * | |
| 208 nssUTF8_Duplicate | |
| 209 ( | |
| 210 const NSSUTF8 *s, | |
| 211 NSSArena *arenaOpt | |
| 212 ) | |
| 213 { | |
| 214 NSSUTF8 *rv; | |
| 215 PRUint32 len; | |
| 216 | |
| 217 #ifdef NSSDEBUG | |
| 218 if( (const NSSUTF8 *)NULL == s ) { | |
| 219 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 220 return (NSSUTF8 *)NULL; | |
| 221 } | |
| 222 | |
| 223 if( (NSSArena *)NULL != arenaOpt ) { | |
| 224 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { | |
| 225 return (NSSUTF8 *)NULL; | |
| 226 } | |
| 227 } | |
| 228 #endif /* NSSDEBUG */ | |
| 229 | |
| 230 len = PL_strlen((const char *)s); | |
| 231 #ifdef PEDANTIC | |
| 232 if( '\0' != ((const char *)s)[ len ] ) { | |
| 233 /* must have wrapped, e.g., too big for PRUint32 */ | |
| 234 nss_SetError(NSS_ERROR_NO_MEMORY); | |
| 235 return (NSSUTF8 *)NULL; | |
| 236 } | |
| 237 #endif /* PEDANTIC */ | |
| 238 len++; /* zero termination */ | |
| 239 | |
| 240 rv = nss_ZAlloc(arenaOpt, len); | |
| 241 if( (void *)NULL == rv ) { | |
| 242 return (NSSUTF8 *)NULL; | |
| 243 } | |
| 244 | |
| 245 (void)nsslibc_memcpy(rv, s, len); | |
| 246 return rv; | |
| 247 } | |
| 248 | |
| 249 /* | |
| 250 * nssUTF8_Size | |
| 251 * | |
| 252 * This routine returns the length in bytes (including the terminating | |
| 253 * null) of the UTF8-encoded string pointed to by the specified | |
| 254 * NSSUTF8 pointer. Zero is returned on error. | |
| 255 * | |
| 256 * The error may be one of the following values: | |
| 257 * NSS_ERROR_INVALID_POINTER | |
| 258 * NSS_ERROR_VALUE_TOO_LARGE | |
| 259 * | |
| 260 * Return value: | |
| 261 * 0 on error | |
| 262 * nonzero length of the string. | |
| 263 */ | |
| 264 | |
| 265 NSS_IMPLEMENT PRUint32 | |
| 266 nssUTF8_Size | |
| 267 ( | |
| 268 const NSSUTF8 *s, | |
| 269 PRStatus *statusOpt | |
| 270 ) | |
| 271 { | |
| 272 PRUint32 sv; | |
| 273 | |
| 274 #ifdef NSSDEBUG | |
| 275 if( (const NSSUTF8 *)NULL == s ) { | |
| 276 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 277 if( (PRStatus *)NULL != statusOpt ) { | |
| 278 *statusOpt = PR_FAILURE; | |
| 279 } | |
| 280 return 0; | |
| 281 } | |
| 282 #endif /* NSSDEBUG */ | |
| 283 | |
| 284 sv = PL_strlen((const char *)s) + 1; | |
| 285 #ifdef PEDANTIC | |
| 286 if( '\0' != ((const char *)s)[ sv-1 ] ) { | |
| 287 /* wrapped */ | |
| 288 nss_SetError(NSS_ERROR_VALUE_TOO_LARGE); | |
| 289 if( (PRStatus *)NULL != statusOpt ) { | |
| 290 *statusOpt = PR_FAILURE; | |
| 291 } | |
| 292 return 0; | |
| 293 } | |
| 294 #endif /* PEDANTIC */ | |
| 295 | |
| 296 if( (PRStatus *)NULL != statusOpt ) { | |
| 297 *statusOpt = PR_SUCCESS; | |
| 298 } | |
| 299 | |
| 300 return sv; | |
| 301 } | |
| 302 | |
| 303 /* | |
| 304 * nssUTF8_Length | |
| 305 * | |
| 306 * This routine returns the length in characters (not including the | |
| 307 * terminating null) of the UTF8-encoded string pointed to by the | |
| 308 * specified NSSUTF8 pointer. | |
| 309 * | |
| 310 * The error may be one of the following values: | |
| 311 * NSS_ERROR_INVALID_POINTER | |
| 312 * NSS_ERROR_VALUE_TOO_LARGE | |
| 313 * NSS_ERROR_INVALID_STRING | |
| 314 * | |
| 315 * Return value: | |
| 316 * length of the string (which may be zero) | |
| 317 * 0 on error | |
| 318 */ | |
| 319 | |
| 320 NSS_IMPLEMENT PRUint32 | |
| 321 nssUTF8_Length | |
| 322 ( | |
| 323 const NSSUTF8 *s, | |
| 324 PRStatus *statusOpt | |
| 325 ) | |
| 326 { | |
| 327 PRUint32 l = 0; | |
| 328 const PRUint8 *c = (const PRUint8 *)s; | |
| 329 | |
| 330 #ifdef NSSDEBUG | |
| 331 if( (const NSSUTF8 *)NULL == s ) { | |
| 332 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 333 goto loser; | |
| 334 } | |
| 335 #endif /* NSSDEBUG */ | |
| 336 | |
| 337 /* | |
| 338 * From RFC 2044: | |
| 339 * | |
| 340 * UCS-4 range (hex.) UTF-8 octet sequence (binary) | |
| 341 * 0000 0000-0000 007F 0xxxxxxx | |
| 342 * 0000 0080-0000 07FF 110xxxxx 10xxxxxx | |
| 343 * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx | |
| 344 * 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | |
| 345 * 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx | |
| 346 * 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx | |
| 347 */ | |
| 348 | |
| 349 while( 0 != *c ) { | |
| 350 PRUint32 incr; | |
| 351 if( (*c & 0x80) == 0 ) { | |
| 352 incr = 1; | |
| 353 } else if( (*c & 0xE0) == 0xC0 ) { | |
| 354 incr = 2; | |
| 355 } else if( (*c & 0xF0) == 0xE0 ) { | |
| 356 incr = 3; | |
| 357 } else if( (*c & 0xF8) == 0xF0 ) { | |
| 358 incr = 4; | |
| 359 } else if( (*c & 0xFC) == 0xF8 ) { | |
| 360 incr = 5; | |
| 361 } else if( (*c & 0xFE) == 0xFC ) { | |
| 362 incr = 6; | |
| 363 } else { | |
| 364 nss_SetError(NSS_ERROR_INVALID_STRING); | |
| 365 goto loser; | |
| 366 } | |
| 367 | |
| 368 l += incr; | |
| 369 | |
| 370 #ifdef PEDANTIC | |
| 371 if( l < incr ) { | |
| 372 /* Wrapped-- too big */ | |
| 373 nss_SetError(NSS_ERROR_VALUE_TOO_LARGE); | |
| 374 goto loser; | |
| 375 } | |
| 376 | |
| 377 { | |
| 378 PRUint8 *d; | |
| 379 for( d = &c[1]; d < &c[incr]; d++ ) { | |
| 380 if( (*d & 0xC0) != 0xF0 ) { | |
| 381 nss_SetError(NSS_ERROR_INVALID_STRING); | |
| 382 goto loser; | |
| 383 } | |
| 384 } | |
| 385 } | |
| 386 #endif /* PEDANTIC */ | |
| 387 | |
| 388 c += incr; | |
| 389 } | |
| 390 | |
| 391 if( (PRStatus *)NULL != statusOpt ) { | |
| 392 *statusOpt = PR_SUCCESS; | |
| 393 } | |
| 394 | |
| 395 return l; | |
| 396 | |
| 397 loser: | |
| 398 if( (PRStatus *)NULL != statusOpt ) { | |
| 399 *statusOpt = PR_FAILURE; | |
| 400 } | |
| 401 | |
| 402 return 0; | |
| 403 } | |
| 404 | |
| 405 | |
| 406 /* | |
| 407 * nssUTF8_Create | |
| 408 * | |
| 409 * This routine creates a UTF8 string from a string in some other | |
| 410 * format. Some types of string may include embedded null characters, | |
| 411 * so for them the length parameter must be used. For string types | |
| 412 * that are null-terminated, the length parameter is optional; if it | |
| 413 * is zero, it will be ignored. If the optional arena argument is | |
| 414 * non-null, the memory used for the new string will be obtained from | |
| 415 * that arena, otherwise it will be obtained from the heap. This | |
| 416 * routine may return NULL upon error, in which case it will have | |
| 417 * placed an error on the error stack. | |
| 418 * | |
| 419 * The error may be one of the following: | |
| 420 * NSS_ERROR_INVALID_POINTER | |
| 421 * NSS_ERROR_NO_MEMORY | |
| 422 * NSS_ERROR_UNSUPPORTED_TYPE | |
| 423 * | |
| 424 * Return value: | |
| 425 * NULL upon error | |
| 426 * A non-null pointer to a new UTF8 string otherwise | |
| 427 */ | |
| 428 | |
| 429 extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */ | |
| 430 | |
| 431 NSS_IMPLEMENT NSSUTF8 * | |
| 432 nssUTF8_Create | |
| 433 ( | |
| 434 NSSArena *arenaOpt, | |
| 435 nssStringType type, | |
| 436 const void *inputString, | |
| 437 PRUint32 size /* in bytes, not characters */ | |
| 438 ) | |
| 439 { | |
| 440 NSSUTF8 *rv = NULL; | |
| 441 | |
| 442 #ifdef NSSDEBUG | |
| 443 if( (NSSArena *)NULL != arenaOpt ) { | |
| 444 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { | |
| 445 return (NSSUTF8 *)NULL; | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 if( (const void *)NULL == inputString ) { | |
| 450 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 451 return (NSSUTF8 *)NULL; | |
| 452 } | |
| 453 #endif /* NSSDEBUG */ | |
| 454 | |
| 455 switch( type ) { | |
| 456 case nssStringType_DirectoryString: | |
| 457 /* This is a composite type requiring BER */ | |
| 458 nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE); | |
| 459 break; | |
| 460 case nssStringType_TeletexString: | |
| 461 /* | |
| 462 * draft-ietf-pkix-ipki-part1-11 says in part: | |
| 463 * | |
| 464 * In addition, many legacy implementations support names encoded | |
| 465 * in the ISO 8859-1 character set (Latin1String) but tag them as | |
| 466 * TeletexString. The Latin1String includes characters used in | |
| 467 * Western European countries which are not part of the | |
| 468 * TeletexString charcter set. Implementations that process | |
| 469 * TeletexString SHOULD be prepared to handle the entire ISO | |
| 470 * 8859-1 character set.[ISO 8859-1]. | |
| 471 */ | |
| 472 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 473 break; | |
| 474 case nssStringType_PrintableString: | |
| 475 /* | |
| 476 * PrintableString consists of A-Za-z0-9 ,()+,-./:=? | |
| 477 * This is a subset of ASCII, which is a subset of UTF8. | |
| 478 * So we can just duplicate the string over. | |
| 479 */ | |
| 480 | |
| 481 if( 0 == size ) { | |
| 482 rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt); | |
| 483 } else { | |
| 484 rv = nss_ZAlloc(arenaOpt, size+1); | |
| 485 if( (NSSUTF8 *)NULL == rv ) { | |
| 486 return (NSSUTF8 *)NULL; | |
| 487 } | |
| 488 | |
| 489 (void)nsslibc_memcpy(rv, inputString, size); | |
| 490 } | |
| 491 | |
| 492 break; | |
| 493 case nssStringType_UniversalString: | |
| 494 /* 4-byte unicode */ | |
| 495 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 496 break; | |
| 497 case nssStringType_BMPString: | |
| 498 /* Base Multilingual Plane of Unicode */ | |
| 499 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 500 break; | |
| 501 case nssStringType_UTF8String: | |
| 502 if( 0 == size ) { | |
| 503 rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt); | |
| 504 } else { | |
| 505 rv = nss_ZAlloc(arenaOpt, size+1); | |
| 506 if( (NSSUTF8 *)NULL == rv ) { | |
| 507 return (NSSUTF8 *)NULL; | |
| 508 } | |
| 509 | |
| 510 (void)nsslibc_memcpy(rv, inputString, size); | |
| 511 } | |
| 512 | |
| 513 break; | |
| 514 case nssStringType_PHGString: | |
| 515 /* | |
| 516 * PHGString is an IA5String (with case-insensitive comparisons). | |
| 517 * IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has | |
| 518 * currency symbol. | |
| 519 */ | |
| 520 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 521 break; | |
| 522 case nssStringType_GeneralString: | |
| 523 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 524 break; | |
| 525 default: | |
| 526 nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE); | |
| 527 break; | |
| 528 } | |
| 529 | |
| 530 return rv; | |
| 531 } | |
| 532 | |
| 533 NSS_IMPLEMENT NSSItem * | |
| 534 nssUTF8_GetEncoding | |
| 535 ( | |
| 536 NSSArena *arenaOpt, | |
| 537 NSSItem *rvOpt, | |
| 538 nssStringType type, | |
| 539 NSSUTF8 *string | |
| 540 ) | |
| 541 { | |
| 542 NSSItem *rv = (NSSItem *)NULL; | |
| 543 PRStatus status = PR_SUCCESS; | |
| 544 | |
| 545 #ifdef NSSDEBUG | |
| 546 if( (NSSArena *)NULL != arenaOpt ) { | |
| 547 if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { | |
| 548 return (NSSItem *)NULL; | |
| 549 } | |
| 550 } | |
| 551 | |
| 552 if( (NSSUTF8 *)NULL == string ) { | |
| 553 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 554 return (NSSItem *)NULL; | |
| 555 } | |
| 556 #endif /* NSSDEBUG */ | |
| 557 | |
| 558 switch( type ) { | |
| 559 case nssStringType_DirectoryString: | |
| 560 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 561 break; | |
| 562 case nssStringType_TeletexString: | |
| 563 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 564 break; | |
| 565 case nssStringType_PrintableString: | |
| 566 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 567 break; | |
| 568 case nssStringType_UniversalString: | |
| 569 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 570 break; | |
| 571 case nssStringType_BMPString: | |
| 572 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 573 break; | |
| 574 case nssStringType_UTF8String: | |
| 575 { | |
| 576 NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt); | |
| 577 if( (NSSUTF8 *)NULL == dup ) { | |
| 578 return (NSSItem *)NULL; | |
| 579 } | |
| 580 | |
| 581 if( (NSSItem *)NULL == rvOpt ) { | |
| 582 rv = nss_ZNEW(arenaOpt, NSSItem); | |
| 583 if( (NSSItem *)NULL == rv ) { | |
| 584 (void)nss_ZFreeIf(dup); | |
| 585 return (NSSItem *)NULL; | |
| 586 } | |
| 587 } else { | |
| 588 rv = rvOpt; | |
| 589 } | |
| 590 | |
| 591 rv->data = dup; | |
| 592 dup = (NSSUTF8 *)NULL; | |
| 593 rv->size = nssUTF8_Size(rv->data, &status); | |
| 594 if( (0 == rv->size) && (PR_SUCCESS != status) ) { | |
| 595 if( (NSSItem *)NULL == rvOpt ) { | |
| 596 (void)nss_ZFreeIf(rv); | |
| 597 } | |
| 598 return (NSSItem *)NULL; | |
| 599 } | |
| 600 } | |
| 601 break; | |
| 602 case nssStringType_PHGString: | |
| 603 nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ | |
| 604 break; | |
| 605 default: | |
| 606 nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE); | |
| 607 break; | |
| 608 } | |
| 609 | |
| 610 return rv; | |
| 611 } | |
| 612 | |
| 613 /* | |
| 614 * nssUTF8_CopyIntoFixedBuffer | |
| 615 * | |
| 616 * This will copy a UTF8 string into a fixed-length buffer, making | |
| 617 * sure that the all characters are valid. Any remaining space will | |
| 618 * be padded with the specified ASCII character, typically either | |
| 619 * null or space. | |
| 620 * | |
| 621 * Blah, blah, blah. | |
| 622 */ | |
| 623 | |
| 624 NSS_IMPLEMENT PRStatus | |
| 625 nssUTF8_CopyIntoFixedBuffer | |
| 626 ( | |
| 627 NSSUTF8 *string, | |
| 628 char *buffer, | |
| 629 PRUint32 bufferSize, | |
| 630 char pad | |
| 631 ) | |
| 632 { | |
| 633 PRUint32 stringSize = 0; | |
| 634 | |
| 635 #ifdef NSSDEBUG | |
| 636 if( (char *)NULL == buffer ) { | |
| 637 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 638 return PR_FALSE; | |
| 639 } | |
| 640 | |
| 641 if( 0 == bufferSize ) { | |
| 642 nss_SetError(NSS_ERROR_INVALID_ARGUMENT); | |
| 643 return PR_FALSE; | |
| 644 } | |
| 645 | |
| 646 if( (pad & 0x80) != 0x00 ) { | |
| 647 nss_SetError(NSS_ERROR_INVALID_ARGUMENT); | |
| 648 return PR_FALSE; | |
| 649 } | |
| 650 #endif /* NSSDEBUG */ | |
| 651 | |
| 652 if( (NSSUTF8 *)NULL == string ) { | |
| 653 string = (NSSUTF8 *) ""; | |
| 654 } | |
| 655 | |
| 656 stringSize = nssUTF8_Size(string, (PRStatus *)NULL); | |
| 657 stringSize--; /* don't count the trailing null */ | |
| 658 if( stringSize > bufferSize ) { | |
| 659 PRUint32 bs = bufferSize; | |
| 660 (void)nsslibc_memcpy(buffer, string, bufferSize); | |
| 661 | |
| 662 if( ( ((buffer[ bs-1 ] & 0x80) == 0x00)) || | |
| 663 ((bs > 1) && ((buffer[ bs-2 ] & 0xE0) == 0xC0)) || | |
| 664 ((bs > 2) && ((buffer[ bs-3 ] & 0xF0) == 0xE0)) || | |
| 665 ((bs > 3) && ((buffer[ bs-4 ] & 0xF8) == 0xF0)) || | |
| 666 ((bs > 4) && ((buffer[ bs-5 ] & 0xFC) == 0xF8)) || | |
| 667 ((bs > 5) && ((buffer[ bs-6 ] & 0xFE) == 0xFC)) ) { | |
| 668 /* It fit exactly */ | |
| 669 return PR_SUCCESS; | |
| 670 } | |
| 671 | |
| 672 /* Too long. We have to trim the last character */ | |
| 673 for( /*bs*/; bs != 0; bs-- ) { | |
| 674 if( (buffer[bs-1] & 0xC0) != 0x80 ) { | |
| 675 buffer[bs-1] = pad; | |
| 676 break; | |
| 677 } else { | |
| 678 buffer[bs-1] = pad; | |
| 679 } | |
| 680 } | |
| 681 } else { | |
| 682 (void)nsslibc_memset(buffer, pad, bufferSize); | |
| 683 (void)nsslibc_memcpy(buffer, string, stringSize); | |
| 684 } | |
| 685 | |
| 686 return PR_SUCCESS; | |
| 687 } | |
| 688 | |
| 689 /* | |
| 690 * nssUTF8_Equal | |
| 691 * | |
| 692 */ | |
| 693 | |
| 694 NSS_IMPLEMENT PRBool | |
| 695 nssUTF8_Equal | |
| 696 ( | |
| 697 const NSSUTF8 *a, | |
| 698 const NSSUTF8 *b, | |
| 699 PRStatus *statusOpt | |
| 700 ) | |
| 701 { | |
| 702 PRUint32 la, lb; | |
| 703 | |
| 704 #ifdef NSSDEBUG | |
| 705 if( ((const NSSUTF8 *)NULL == a) || | |
| 706 ((const NSSUTF8 *)NULL == b) ) { | |
| 707 nss_SetError(NSS_ERROR_INVALID_POINTER); | |
| 708 if( (PRStatus *)NULL != statusOpt ) { | |
| 709 *statusOpt = PR_FAILURE; | |
| 710 } | |
| 711 return PR_FALSE; | |
| 712 } | |
| 713 #endif /* NSSDEBUG */ | |
| 714 | |
| 715 la = nssUTF8_Size(a, statusOpt); | |
| 716 if( 0 == la ) { | |
| 717 return PR_FALSE; | |
| 718 } | |
| 719 | |
| 720 lb = nssUTF8_Size(b, statusOpt); | |
| 721 if( 0 == lb ) { | |
| 722 return PR_FALSE; | |
| 723 } | |
| 724 | |
| 725 if( la != lb ) { | |
| 726 return PR_FALSE; | |
| 727 } | |
| 728 | |
| 729 return nsslibc_memequal(a, b, la, statusOpt); | |
| 730 } | |
| OLD | NEW |