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