pkix_pl_string.c (21265B)
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 * pkix_pl_string.c 6 * 7 * String Object Functions 8 * 9 */ 10 11 #include "pkix_pl_string.h" 12 13 /* --Private-String-Functions------------------------------------- */ 14 15 /* 16 * FUNCTION: pkix_pl_String_Comparator 17 * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) 18 * 19 * NOTE: 20 * This function is a utility function called by pkix_pl_String_Equals(). 21 * It is not officially registered as a comparator. 22 */ 23 static PKIX_Error * 24 pkix_pl_String_Comparator( 25 PKIX_PL_String *firstString, 26 PKIX_PL_String *secondString, 27 PKIX_Int32 *pResult, 28 void *plContext) 29 { 30 PKIX_UInt32 i; 31 PKIX_Int32 result; 32 unsigned char *p1 = NULL; 33 unsigned char *p2 = NULL; 34 35 PKIX_ENTER(STRING, "pkix_pl_String_Comparator"); 36 PKIX_NULLCHECK_THREE(firstString, secondString, pResult); 37 38 result = 0; 39 40 p1 = (unsigned char*) firstString->utf16String; 41 p2 = (unsigned char*) secondString->utf16String; 42 43 /* Compare characters until you find a difference */ 44 for (i = 0; ((i < firstString->utf16Length) && 45 (i < secondString->utf16Length) && 46 result == 0); i++, p1++, p2++) { 47 if (*p1 < *p2){ 48 result = -1; 49 } else if (*p1 > *p2){ 50 result = 1; 51 } 52 } 53 54 /* If two arrays are identical so far, the longer one is greater */ 55 if (result == 0) { 56 if (firstString->utf16Length < secondString->utf16Length) { 57 result = -1; 58 } else if (firstString->utf16Length > 59 secondString->utf16Length) { 60 result = 1; 61 } 62 } 63 64 *pResult = result; 65 66 PKIX_RETURN(STRING); 67 } 68 69 /* 70 * FUNCTION: pkix_pl_String_Destroy 71 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) 72 */ 73 static PKIX_Error * 74 pkix_pl_String_Destroy( 75 PKIX_PL_Object *object, 76 void *plContext) 77 { 78 PKIX_PL_String *string = NULL; 79 80 PKIX_ENTER(STRING, "pkix_pl_String_Destroy"); 81 PKIX_NULLCHECK_ONE(object); 82 83 PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), 84 PKIX_ARGUMENTNOTSTRING); 85 86 string = (PKIX_PL_String*)object; 87 88 /* XXX For debugging Destroy EscASCII String */ 89 if (string->escAsciiString != NULL) { 90 PKIX_FREE(string->escAsciiString); 91 string->escAsciiString = NULL; 92 string->escAsciiLength = 0; 93 } 94 95 /* Destroy UTF16 String */ 96 if (string->utf16String != NULL) { 97 PKIX_FREE(string->utf16String); 98 string->utf16String = NULL; 99 string->utf16Length = 0; 100 } 101 102 cleanup: 103 104 PKIX_RETURN(STRING); 105 } 106 107 /* 108 * FUNCTION: pkix_pl_String_ToString 109 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) 110 */ 111 static PKIX_Error * 112 pkix_pl_String_ToString( 113 PKIX_PL_Object *object, 114 PKIX_PL_String **pString, 115 void *plContext) 116 { 117 PKIX_PL_String *string = NULL; 118 char *ascii = NULL; 119 PKIX_UInt32 length; 120 121 PKIX_ENTER(STRING, "pkix_pl_String_ToString"); 122 PKIX_NULLCHECK_TWO(object, pString); 123 124 PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), 125 PKIX_ARGUMENTNOTSTRING); 126 127 string = (PKIX_PL_String*)object; 128 129 PKIX_CHECK(PKIX_PL_String_GetEncoded 130 (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext), 131 PKIX_STRINGGETENCODEDFAILED); 132 133 PKIX_CHECK(PKIX_PL_String_Create 134 (PKIX_ESCASCII, ascii, 0, pString, plContext), 135 PKIX_STRINGCREATEFAILED); 136 137 goto cleanup; 138 139 cleanup: 140 141 PKIX_FREE(ascii); 142 143 PKIX_RETURN(STRING); 144 } 145 146 /* 147 * FUNCTION: pkix_pl_String_Equals 148 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) 149 */ 150 static PKIX_Error * 151 pkix_pl_String_Equals( 152 PKIX_PL_Object *firstObject, 153 PKIX_PL_Object *secondObject, 154 PKIX_Boolean *pResult, 155 void *plContext) 156 { 157 PKIX_UInt32 secondType; 158 PKIX_Int32 cmpResult = 0; 159 160 PKIX_ENTER(STRING, "pkix_pl_String_Equals"); 161 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); 162 163 /* Sanity check: Test that "firstObject" is a Strings */ 164 PKIX_CHECK(pkix_CheckType(firstObject, PKIX_STRING_TYPE, plContext), 165 PKIX_FIRSTOBJECTNOTSTRING); 166 167 /* "SecondObject" doesn't have to be a string */ 168 PKIX_CHECK(PKIX_PL_Object_GetType 169 (secondObject, &secondType, plContext), 170 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); 171 172 /* If types differ, then we will return false */ 173 *pResult = PKIX_FALSE; 174 175 if (secondType != PKIX_STRING_TYPE) goto cleanup; 176 177 /* It's safe to cast here */ 178 PKIX_CHECK(pkix_pl_String_Comparator 179 ((PKIX_PL_String*)firstObject, 180 (PKIX_PL_String*)secondObject, 181 &cmpResult, 182 plContext), 183 PKIX_STRINGCOMPARATORFAILED); 184 185 /* Strings are equal iff Comparator Result is 0 */ 186 *pResult = (cmpResult == 0); 187 188 cleanup: 189 190 PKIX_RETURN(STRING); 191 } 192 193 /* 194 * FUNCTION: pkix_pl_String_Hashcode 195 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) 196 */ 197 static PKIX_Error * 198 pkix_pl_String_Hashcode( 199 PKIX_PL_Object *object, 200 PKIX_UInt32 *pHashcode, 201 void *plContext) 202 { 203 PKIX_PL_String *string = NULL; 204 205 PKIX_ENTER(STRING, "pkix_pl_String_Hashcode"); 206 PKIX_NULLCHECK_TWO(object, pHashcode); 207 208 PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), 209 PKIX_OBJECTNOTSTRING); 210 211 string = (PKIX_PL_String*)object; 212 213 PKIX_CHECK(pkix_hash 214 ((const unsigned char *)string->utf16String, 215 string->utf16Length, 216 pHashcode, 217 plContext), 218 PKIX_HASHFAILED); 219 220 cleanup: 221 222 PKIX_RETURN(STRING); 223 } 224 225 /* 226 * FUNCTION: pkix_pl_String_RegisterSelf 227 * DESCRIPTION: 228 * Registers PKIX_STRING_TYPE and its related functions with systemClasses[] 229 * THREAD SAFETY: 230 * Not Thread Safe - for performance and complexity reasons 231 * 232 * Since this function is only called by PKIX_PL_Initialize, which should 233 * only be called once, it is acceptable that this function is not 234 * thread-safe. 235 */ 236 PKIX_Error * 237 pkix_pl_String_RegisterSelf( 238 void *plContext) 239 { 240 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; 241 pkix_ClassTable_Entry entry; 242 243 PKIX_ENTER(STRING, "pkix_pl_String_RegisterSelf"); 244 245 entry.description = "String"; 246 entry.objCounter = 0; 247 entry.typeObjectSize = sizeof(PKIX_PL_String); 248 entry.destructor = pkix_pl_String_Destroy; 249 entry.equalsFunction = pkix_pl_String_Equals; 250 entry.hashcodeFunction = pkix_pl_String_Hashcode; 251 entry.toStringFunction = pkix_pl_String_ToString; 252 entry.comparator = NULL; 253 entry.duplicateFunction = pkix_duplicateImmutable; 254 255 systemClasses[PKIX_STRING_TYPE] = entry; 256 257 PKIX_RETURN(STRING); 258 } 259 260 261 /* --Public-String-Functions----------------------------------------- */ 262 263 /* 264 * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h) 265 */ 266 PKIX_Error * 267 PKIX_PL_String_Create( 268 PKIX_UInt32 fmtIndicator, 269 const void *stringRep, 270 PKIX_UInt32 stringLen, 271 PKIX_PL_String **pString, 272 void *plContext) 273 { 274 PKIX_PL_String *string = NULL; 275 unsigned char *utf16Char = NULL; 276 PKIX_UInt32 i; 277 278 PKIX_ENTER(STRING, "PKIX_PL_String_Create"); 279 PKIX_NULLCHECK_TWO(pString, stringRep); 280 281 PKIX_CHECK(PKIX_PL_Object_Alloc 282 (PKIX_STRING_TYPE, 283 sizeof (PKIX_PL_String), 284 (PKIX_PL_Object **)&string, 285 plContext), 286 PKIX_COULDNOTALLOCATENEWSTRINGOBJECT); 287 288 string->utf16String = NULL; 289 string->utf16Length = 0; 290 291 /* XXX For Debugging */ 292 string->escAsciiString = NULL; 293 string->escAsciiLength = 0; 294 295 switch (fmtIndicator) { 296 case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG: 297 PKIX_STRING_DEBUG("\tCalling PL_strlen).\n"); 298 string->escAsciiLength = PL_strlen(stringRep); 299 300 /* XXX Cache for Debugging */ 301 PKIX_CHECK(PKIX_PL_Malloc 302 ((string->escAsciiLength)+1, 303 (void **)&string->escAsciiString, 304 plContext), 305 PKIX_MALLOCFAILED); 306 307 (void) PORT_Memcpy 308 (string->escAsciiString, 309 (void *)((char *)stringRep), 310 (string->escAsciiLength)+1); 311 312 /* Convert the EscASCII string to UTF16 */ 313 PKIX_CHECK(pkix_EscASCII_to_UTF16 314 (string->escAsciiString, 315 string->escAsciiLength, 316 (fmtIndicator == PKIX_ESCASCII_DEBUG), 317 &string->utf16String, 318 &string->utf16Length, 319 plContext), 320 PKIX_ESCASCIITOUTF16FAILED); 321 break; 322 case PKIX_UTF8: 323 /* Convert the UTF8 string to UTF16 */ 324 PKIX_CHECK(pkix_UTF8_to_UTF16 325 (stringRep, 326 stringLen, 327 &string->utf16String, 328 &string->utf16Length, 329 plContext), 330 PKIX_UTF8TOUTF16FAILED); 331 break; 332 case PKIX_UTF16: 333 /* UTF16 Strings must be even in length */ 334 if (stringLen%2 == 1) { 335 PKIX_DECREF(string); 336 PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR); 337 } 338 339 utf16Char = (unsigned char *)stringRep; 340 341 /* Make sure this is a valid UTF-16 String */ 342 for (i = 0; \ 343 (i < stringLen) && (pkixErrorResult == NULL); \ 344 i += 2) { 345 /* Check that surrogate pairs are valid */ 346 if ((utf16Char[i] >= 0xD8)&& 347 (utf16Char[i] <= 0xDB)) { 348 if ((i+2) >= stringLen) { 349 PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR); 350 /* Second pair should be DC00-DFFF */ 351 } else if (!((utf16Char[i+2] >= 0xDC)&& 352 (utf16Char[i+2] <= 0xDF))) { 353 PKIX_ERROR(PKIX_UTF16LOWZONEERROR); 354 } else { 355 /* Surrogate quartet is valid. */ 356 i += 2; 357 } 358 } 359 } 360 361 /* Create UTF16 String */ 362 string->utf16Length = stringLen; 363 364 /* Alloc space for string */ 365 PKIX_CHECK(PKIX_PL_Malloc 366 (stringLen, &string->utf16String, plContext), 367 PKIX_MALLOCFAILED); 368 369 PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n"); 370 (void) PORT_Memcpy 371 (string->utf16String, stringRep, stringLen); 372 break; 373 374 default: 375 PKIX_ERROR(PKIX_UNKNOWNFORMAT); 376 } 377 378 *pString = string; 379 380 cleanup: 381 382 if (PKIX_ERROR_RECEIVED){ 383 PKIX_DECREF(string); 384 } 385 386 PKIX_RETURN(STRING); 387 } 388 389 /* 390 * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h) 391 */ 392 PKIX_Error * 393 PKIX_PL_Sprintf( 394 PKIX_PL_String **pOut, 395 void *plContext, 396 const PKIX_PL_String *fmt, 397 ...) 398 { 399 PKIX_PL_String *tempString = NULL; 400 PKIX_UInt32 tempUInt = 0; 401 void *pArg = NULL; 402 char *asciiText = NULL; 403 char *asciiFormat = NULL; 404 char *convertedAsciiFormat = NULL; 405 char *convertedAsciiFormatBase = NULL; 406 va_list args; 407 PKIX_UInt32 length, i, j, dummyLen; 408 409 PKIX_ENTER(STRING, "PKIX_PL_Sprintf"); 410 PKIX_NULLCHECK_TWO(pOut, fmt); 411 412 PKIX_CHECK(PKIX_PL_String_GetEncoded 413 ((PKIX_PL_String *)fmt, 414 PKIX_ESCASCII, 415 (void **)&asciiFormat, 416 &length, 417 plContext), 418 PKIX_STRINGGETENCODEDFAILED); 419 420 PKIX_STRING_DEBUG("\tCalling PR_Malloc).\n"); 421 convertedAsciiFormat = PR_Malloc(length + 1); 422 if (convertedAsciiFormat == NULL) 423 PKIX_ERROR_ALLOC_ERROR(); 424 425 convertedAsciiFormatBase = convertedAsciiFormat; 426 427 PKIX_STRING_DEBUG("\tCalling va_start).\n"); 428 va_start(args, fmt); 429 430 i = 0; 431 j = 0; 432 while (i < length) { 433 if ((asciiFormat[i] == '%')&&((i+1) < length)) { 434 switch (asciiFormat[i+1]) { 435 case 's': 436 convertedAsciiFormat[j++] = asciiFormat[i++]; 437 convertedAsciiFormat[j++] = asciiFormat[i++]; 438 convertedAsciiFormat[j] = '\0'; 439 440 tempString = va_arg(args, PKIX_PL_String *); 441 if (tempString != NULL) { 442 PKIX_CHECK_NO_GOTO( 443 PKIX_PL_String_GetEncoded 444 ((PKIX_PL_String*) 445 tempString, 446 PKIX_ESCASCII, 447 &pArg, 448 &dummyLen, 449 plContext), 450 PKIX_STRINGGETENCODEDFAILED); 451 /* need to cleanup var args before 452 * we ditch out to cleanup. */ 453 if (pkixErrorResult) { 454 va_end(args); 455 goto cleanup; 456 } 457 } else { 458 /* there may be a NULL in var_args */ 459 pArg = NULL; 460 } 461 if (asciiText != NULL) { 462 asciiText = PR_sprintf_append(asciiText, 463 (const char *)convertedAsciiFormat, 464 pArg); 465 } else { 466 asciiText = PR_smprintf 467 ((const char *)convertedAsciiFormat, 468 pArg); 469 } 470 if (pArg != NULL) { 471 PKIX_PL_Free(pArg, plContext); 472 pArg = NULL; 473 } 474 convertedAsciiFormat += j; 475 j = 0; 476 break; 477 case 'd': 478 case 'i': 479 case 'o': 480 case 'u': 481 case 'x': 482 case 'X': 483 convertedAsciiFormat[j++] = asciiFormat[i++]; 484 convertedAsciiFormat[j++] = asciiFormat[i++]; 485 convertedAsciiFormat[j] = '\0'; 486 487 tempUInt = va_arg(args, PKIX_UInt32); 488 if (asciiText != NULL) { 489 asciiText = PR_sprintf_append(asciiText, 490 (const char *)convertedAsciiFormat, 491 tempUInt); 492 } else { 493 asciiText = PR_smprintf 494 ((const char *)convertedAsciiFormat, 495 tempUInt); 496 } 497 convertedAsciiFormat += j; 498 j = 0; 499 break; 500 default: 501 convertedAsciiFormat[j++] = asciiFormat[i++]; 502 convertedAsciiFormat[j++] = asciiFormat[i++]; 503 break; 504 } 505 } else { 506 convertedAsciiFormat[j++] = asciiFormat[i++]; 507 } 508 } 509 510 /* for constant string value at end of fmt */ 511 if (j > 0) { 512 convertedAsciiFormat[j] = '\0'; 513 if (asciiText != NULL) { 514 asciiText = PR_sprintf_append(asciiText, 515 (const char *)convertedAsciiFormat); 516 } else { 517 asciiText = PR_smprintf((const char *)convertedAsciiFormat); 518 } 519 } 520 521 va_end(args); 522 523 /* Copy temporary char * into a string object */ 524 PKIX_CHECK(PKIX_PL_String_Create 525 (PKIX_ESCASCII, (void *)asciiText, 0, pOut, plContext), 526 PKIX_STRINGCREATEFAILED); 527 528 cleanup: 529 530 PKIX_FREE(asciiFormat); 531 532 if (convertedAsciiFormatBase){ 533 PR_Free(convertedAsciiFormatBase); 534 } 535 536 if (asciiText){ 537 PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n"); 538 PR_smprintf_free(asciiText); 539 } 540 541 PKIX_RETURN(STRING); 542 } 543 544 /* 545 * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h) 546 */ 547 PKIX_Error * 548 PKIX_PL_GetString( 549 /* ARGSUSED */ PKIX_UInt32 stringID, 550 char *defaultString, 551 PKIX_PL_String **pString, 552 void *plContext) 553 { 554 PKIX_ENTER(STRING, "PKIX_PL_GetString"); 555 PKIX_NULLCHECK_TWO(pString, defaultString); 556 557 /* XXX Optimization - use stringID for caching */ 558 PKIX_CHECK(PKIX_PL_String_Create 559 (PKIX_ESCASCII, defaultString, 0, pString, plContext), 560 PKIX_STRINGCREATEFAILED); 561 562 cleanup: 563 564 PKIX_RETURN(STRING); 565 } 566 567 /* 568 * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h) 569 */ 570 PKIX_Error * 571 PKIX_PL_String_GetEncoded( 572 PKIX_PL_String *string, 573 PKIX_UInt32 fmtIndicator, 574 void **pStringRep, 575 PKIX_UInt32 *pLength, 576 void *plContext) 577 { 578 PKIX_ENTER(STRING, "PKIX_PL_String_GetEncoded"); 579 PKIX_NULLCHECK_THREE(string, pStringRep, pLength); 580 581 switch (fmtIndicator) { 582 case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG: 583 PKIX_CHECK(pkix_UTF16_to_EscASCII 584 (string->utf16String, 585 string->utf16Length, 586 (fmtIndicator == PKIX_ESCASCII_DEBUG), 587 (char **)pStringRep, 588 pLength, 589 plContext), 590 PKIX_UTF16TOESCASCIIFAILED); 591 break; 592 case PKIX_UTF8: 593 PKIX_CHECK(pkix_UTF16_to_UTF8 594 (string->utf16String, 595 string->utf16Length, 596 PKIX_FALSE, 597 pStringRep, 598 pLength, 599 plContext), 600 PKIX_UTF16TOUTF8FAILED); 601 break; 602 case PKIX_UTF8_NULL_TERM: 603 PKIX_CHECK(pkix_UTF16_to_UTF8 604 (string->utf16String, 605 string->utf16Length, 606 PKIX_TRUE, 607 pStringRep, 608 pLength, 609 plContext), 610 PKIX_UTF16TOUTF8FAILED); 611 break; 612 case PKIX_UTF16: 613 *pLength = string->utf16Length; 614 615 PKIX_CHECK(PKIX_PL_Malloc(*pLength, pStringRep, plContext), 616 PKIX_MALLOCFAILED); 617 618 PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n"); 619 (void) PORT_Memcpy(*pStringRep, string->utf16String, *pLength); 620 break; 621 default: 622 PKIX_ERROR(PKIX_UNKNOWNFORMAT); 623 } 624 625 cleanup: 626 627 PKIX_RETURN(STRING); 628 }