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 *
pkix_pl_String_Comparator(PKIX_PL_String * firstString,PKIX_PL_String * secondString,PKIX_Int32 * pResult,void * plContext)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 *
pkix_pl_String_Destroy(PKIX_PL_Object * object,void * plContext)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 *
pkix_pl_String_ToString(PKIX_PL_Object * object,PKIX_PL_String ** pString,void * plContext)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 *
pkix_pl_String_Equals(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Boolean * pResult,void * plContext)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 *
pkix_pl_String_Hashcode(PKIX_PL_Object * object,PKIX_UInt32 * pHashcode,void * plContext)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 *
pkix_pl_String_RegisterSelf(void * plContext)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 *
PKIX_PL_String_Create(PKIX_UInt32 fmtIndicator,const void * stringRep,PKIX_UInt32 stringLen,PKIX_PL_String ** pString,void * plContext)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 *
PKIX_PL_Sprintf(PKIX_PL_String ** pOut,void * plContext,const PKIX_PL_String * fmt,...)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 *
PKIX_PL_GetString(PKIX_UInt32 stringID,char * defaultString,PKIX_PL_String ** pString,void * plContext)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 *
PKIX_PL_String_GetEncoded(PKIX_PL_String * string,PKIX_UInt32 fmtIndicator,void ** pStringRep,PKIX_UInt32 * pLength,void * plContext)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 }
629