nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / lib / libpkix / pkix_pl_nss / system / pkix_pl_string.c
blob0c129d9d7e4b727dfe7082f11d92c48d74178ee1
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the PKIX-C library.
16 * The Initial Developer of the Original Code is
17 * Sun Microsystems, Inc.
18 * Portions created by the Initial Developer are
19 * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
21 * Contributor(s):
22 * Sun Microsystems, Inc.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 * pkix_pl_string.c
40 * String Object Functions
44 #include "pkix_pl_string.h"
46 /* --Private-String-Functions------------------------------------- */
49 * FUNCTION: pkix_pl_String_Comparator
50 * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
52 * NOTE:
53 * This function is a utility function called by pkix_pl_String_Equals().
54 * It is not officially registered as a comparator.
56 static PKIX_Error *
57 pkix_pl_String_Comparator(
58 PKIX_PL_String *firstString,
59 PKIX_PL_String *secondString,
60 PKIX_Int32 *pResult,
61 void *plContext)
63 PKIX_UInt32 i;
64 PKIX_Int32 result;
65 unsigned char *p1 = NULL;
66 unsigned char *p2 = NULL;
68 PKIX_ENTER(STRING, "pkix_pl_String_Comparator");
69 PKIX_NULLCHECK_THREE(firstString, secondString, pResult);
71 result = 0;
73 p1 = (unsigned char*) firstString->utf16String;
74 p2 = (unsigned char*) secondString->utf16String;
76 /* Compare characters until you find a difference */
77 for (i = 0; ((i < firstString->utf16Length) &&
78 (i < secondString->utf16Length) &&
79 result == 0); i++, p1++, p2++) {
80 if (*p1 < *p2){
81 result = -1;
82 } else if (*p1 > *p2){
83 result = 1;
87 /* If two arrays are identical so far, the longer one is greater */
88 if (result == 0) {
89 if (firstString->utf16Length < secondString->utf16Length) {
90 result = -1;
91 } else if (firstString->utf16Length >
92 secondString->utf16Length) {
93 result = 1;
97 *pResult = result;
99 PKIX_RETURN(STRING);
103 * FUNCTION: pkix_pl_String_Destroy
104 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
106 static PKIX_Error *
107 pkix_pl_String_Destroy(
108 PKIX_PL_Object *object,
109 void *plContext)
111 PKIX_PL_String *string = NULL;
113 PKIX_ENTER(STRING, "pkix_pl_String_Destroy");
114 PKIX_NULLCHECK_ONE(object);
116 PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
117 PKIX_ARGUMENTNOTSTRING);
119 string = (PKIX_PL_String*)object;
121 /* XXX For debugging Destroy EscASCII String */
122 if (string->escAsciiString != NULL) {
123 PKIX_FREE(string->escAsciiString);
124 string->escAsciiString = NULL;
125 string->escAsciiLength = 0;
128 /* Destroy UTF16 String */
129 if (string->utf16String != NULL) {
130 PKIX_FREE(string->utf16String);
131 string->utf16String = NULL;
132 string->utf16Length = 0;
135 cleanup:
137 PKIX_RETURN(STRING);
141 * FUNCTION: pkix_pl_String_ToString
142 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
144 static PKIX_Error *
145 pkix_pl_String_ToString(
146 PKIX_PL_Object *object,
147 PKIX_PL_String **pString,
148 void *plContext)
150 PKIX_PL_String *string = NULL;
151 char *ascii = NULL;
152 PKIX_UInt32 length;
154 PKIX_ENTER(STRING, "pkix_pl_String_ToString");
155 PKIX_NULLCHECK_TWO(object, pString);
157 PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
158 PKIX_ARGUMENTNOTSTRING);
160 string = (PKIX_PL_String*)object;
162 PKIX_CHECK(PKIX_PL_String_GetEncoded
163 (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext),
164 PKIX_STRINGGETENCODEDFAILED);
166 PKIX_CHECK(PKIX_PL_String_Create
167 (PKIX_ESCASCII, ascii, 0, pString, plContext),
168 PKIX_STRINGCREATEFAILED);
170 goto cleanup;
172 cleanup:
174 PKIX_FREE(ascii);
176 PKIX_RETURN(STRING);
180 * FUNCTION: pkix_pl_String_Equals
181 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
183 static PKIX_Error *
184 pkix_pl_String_Equals(
185 PKIX_PL_Object *firstObject,
186 PKIX_PL_Object *secondObject,
187 PKIX_Boolean *pResult,
188 void *plContext)
190 PKIX_UInt32 secondType;
191 PKIX_Int32 cmpResult = 0;
193 PKIX_ENTER(STRING, "pkix_pl_String_Equals");
194 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
196 /* Sanity check: Test that "firstObject" is a Strings */
197 PKIX_CHECK(pkix_CheckType(firstObject, PKIX_STRING_TYPE, plContext),
198 PKIX_FIRSTOBJECTNOTSTRING);
200 /* "SecondObject" doesn't have to be a string */
201 PKIX_CHECK(PKIX_PL_Object_GetType
202 (secondObject, &secondType, plContext),
203 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
205 /* If types differ, then we will return false */
206 *pResult = PKIX_FALSE;
208 if (secondType != PKIX_STRING_TYPE) goto cleanup;
210 /* It's safe to cast here */
211 PKIX_CHECK(pkix_pl_String_Comparator
212 ((PKIX_PL_String*)firstObject,
213 (PKIX_PL_String*)secondObject,
214 &cmpResult,
215 plContext),
216 PKIX_STRINGCOMPARATORFAILED);
218 /* Strings are equal iff Comparator Result is 0 */
219 *pResult = (cmpResult == 0);
221 cleanup:
223 PKIX_RETURN(STRING);
227 * FUNCTION: pkix_pl_String_Hashcode
228 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
230 static PKIX_Error *
231 pkix_pl_String_Hashcode(
232 PKIX_PL_Object *object,
233 PKIX_UInt32 *pHashcode,
234 void *plContext)
236 PKIX_PL_String *string = NULL;
238 PKIX_ENTER(STRING, "pkix_pl_String_Hashcode");
239 PKIX_NULLCHECK_TWO(object, pHashcode);
241 PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
242 PKIX_OBJECTNOTSTRING);
244 string = (PKIX_PL_String*)object;
246 PKIX_CHECK(pkix_hash
247 ((const unsigned char *)string->utf16String,
248 string->utf16Length,
249 pHashcode,
250 plContext),
251 PKIX_HASHFAILED);
253 cleanup:
255 PKIX_RETURN(STRING);
259 * FUNCTION: pkix_pl_String_RegisterSelf
260 * DESCRIPTION:
261 * Registers PKIX_STRING_TYPE and its related functions with systemClasses[]
262 * THREAD SAFETY:
263 * Not Thread Safe - for performance and complexity reasons
265 * Since this function is only called by PKIX_PL_Initialize, which should
266 * only be called once, it is acceptable that this function is not
267 * thread-safe.
269 PKIX_Error *
270 pkix_pl_String_RegisterSelf(
271 void *plContext)
273 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
274 pkix_ClassTable_Entry entry;
276 PKIX_ENTER(STRING, "pkix_pl_String_RegisterSelf");
278 entry.description = "String";
279 entry.objCounter = 0;
280 entry.typeObjectSize = sizeof(PKIX_PL_String);
281 entry.destructor = pkix_pl_String_Destroy;
282 entry.equalsFunction = pkix_pl_String_Equals;
283 entry.hashcodeFunction = pkix_pl_String_Hashcode;
284 entry.toStringFunction = pkix_pl_String_ToString;
285 entry.comparator = NULL;
286 entry.duplicateFunction = pkix_duplicateImmutable;
288 systemClasses[PKIX_STRING_TYPE] = entry;
290 PKIX_RETURN(STRING);
294 /* --Public-String-Functions----------------------------------------- */
297 * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h)
299 PKIX_Error *
300 PKIX_PL_String_Create(
301 PKIX_UInt32 fmtIndicator,
302 const void *stringRep,
303 PKIX_UInt32 stringLen,
304 PKIX_PL_String **pString,
305 void *plContext)
307 PKIX_PL_String *string = NULL;
308 unsigned char *utf16Char = NULL;
309 PKIX_UInt32 i;
311 PKIX_ENTER(STRING, "PKIX_PL_String_Create");
312 PKIX_NULLCHECK_TWO(pString, stringRep);
314 PKIX_CHECK(PKIX_PL_Object_Alloc
315 (PKIX_STRING_TYPE,
316 sizeof (PKIX_PL_String),
317 (PKIX_PL_Object **)&string,
318 plContext),
319 PKIX_COULDNOTALLOCATENEWSTRINGOBJECT);
321 string->utf16String = NULL;
322 string->utf16Length = 0;
324 /* XXX For Debugging */
325 string->escAsciiString = NULL;
326 string->escAsciiLength = 0;
328 switch (fmtIndicator) {
329 case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG:
330 PKIX_STRING_DEBUG("\tCalling PL_strlen).\n");
331 string->escAsciiLength = PL_strlen(stringRep);
333 /* XXX Cache for Debugging */
334 PKIX_CHECK(PKIX_PL_Malloc
335 ((string->escAsciiLength)+1,
336 (void **)&string->escAsciiString,
337 plContext),
338 PKIX_MALLOCFAILED);
340 (void) PORT_Memcpy
341 (string->escAsciiString,
342 (void *)((char *)stringRep),
343 (string->escAsciiLength)+1);
345 /* Convert the EscASCII string to UTF16 */
346 PKIX_CHECK(pkix_EscASCII_to_UTF16
347 (string->escAsciiString,
348 string->escAsciiLength,
349 (fmtIndicator == PKIX_ESCASCII_DEBUG),
350 &string->utf16String,
351 &string->utf16Length,
352 plContext),
353 PKIX_ESCASCIITOUTF16FAILED);
354 break;
355 case PKIX_UTF8:
356 /* Convert the UTF8 string to UTF16 */
357 PKIX_CHECK(pkix_UTF8_to_UTF16
358 (stringRep,
359 stringLen,
360 &string->utf16String,
361 &string->utf16Length,
362 plContext),
363 PKIX_UTF8TOUTF16FAILED);
364 break;
365 case PKIX_UTF16:
366 /* UTF16 Strings must be even in length */
367 if (stringLen%2 == 1) {
368 PKIX_DECREF(string);
369 PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR);
372 utf16Char = (unsigned char *)stringRep;
374 /* Make sure this is a valid UTF-16 String */
375 for (i = 0; \
376 (i < stringLen) && (pkixErrorResult == NULL); \
377 i += 2) {
378 /* Check that surrogate pairs are valid */
379 if ((utf16Char[i] >= 0xD8)&&
380 (utf16Char[i] <= 0xDB)) {
381 if ((i+2) >= stringLen) {
382 PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR);
383 /* Second pair should be DC00-DFFF */
384 } else if (!((utf16Char[i+2] >= 0xDC)&&
385 (utf16Char[i+2] <= 0xDF))) {
386 PKIX_ERROR(PKIX_UTF16LOWZONEERROR);
387 } else {
388 /* Surrogate quartet is valid. */
389 i += 2;
394 /* Create UTF16 String */
395 string->utf16Length = stringLen;
397 /* Alloc space for string */
398 PKIX_CHECK(PKIX_PL_Malloc
399 (stringLen, &string->utf16String, plContext),
400 PKIX_MALLOCFAILED);
402 PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
403 (void) PORT_Memcpy
404 (string->utf16String, stringRep, stringLen);
405 break;
407 default:
408 PKIX_ERROR(PKIX_UNKNOWNFORMAT);
411 *pString = string;
413 cleanup:
415 if (PKIX_ERROR_RECEIVED){
416 PKIX_DECREF(string);
419 PKIX_RETURN(STRING);
423 * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h)
425 PKIX_Error *
426 PKIX_PL_Sprintf(
427 PKIX_PL_String **pOut,
428 void *plContext,
429 const PKIX_PL_String *fmt,
430 ...)
432 PKIX_PL_String *tempString = NULL;
433 PKIX_UInt32 tempUInt = 0;
434 void *pArg = NULL;
435 char *asciiText = NULL;
436 char *asciiFormat = NULL;
437 char *convertedAsciiFormat = NULL;
438 char *convertedAsciiFormatBase = NULL;
439 va_list args;
440 PKIX_UInt32 length, i, j, dummyLen;
442 PKIX_ENTER(STRING, "PKIX_PL_Sprintf");
443 PKIX_NULLCHECK_TWO(pOut, fmt);
445 PKIX_CHECK(PKIX_PL_String_GetEncoded
446 ((PKIX_PL_String *)fmt,
447 PKIX_ESCASCII,
448 (void **)&asciiFormat,
449 &length,
450 plContext),
451 PKIX_STRINGGETENCODEDFAILED);
453 PKIX_STRING_DEBUG("\tCalling PR_Malloc).\n");
454 convertedAsciiFormat = PR_Malloc(length + 1);
455 if (convertedAsciiFormat == NULL)
456 PKIX_ERROR_ALLOC_ERROR();
458 convertedAsciiFormatBase = convertedAsciiFormat;
460 PKIX_STRING_DEBUG("\tCalling va_start).\n");
461 va_start(args, fmt);
463 i = 0;
464 j = 0;
465 while (i < length) {
466 if ((asciiFormat[i] == '%')&&((i+1) < length)) {
467 switch (asciiFormat[i+1]) {
468 case 's':
469 convertedAsciiFormat[j++] = asciiFormat[i++];
470 convertedAsciiFormat[j++] = asciiFormat[i++];
471 convertedAsciiFormat[j] = '\0';
473 tempString = va_arg(args, PKIX_PL_String *);
474 if (tempString != NULL) {
475 PKIX_CHECK(PKIX_PL_String_GetEncoded
476 ((PKIX_PL_String*)
477 tempString,
478 PKIX_ESCASCII,
479 &pArg,
480 &dummyLen,
481 plContext),
482 PKIX_STRINGGETENCODEDFAILED);
483 } else {
484 /* there may be a NULL in var_args */
485 pArg = NULL;
487 if (asciiText != NULL) {
488 asciiText = PR_sprintf_append(asciiText,
489 (const char *)convertedAsciiFormat,
490 pArg);
491 } else {
492 asciiText = PR_smprintf
493 ((const char *)convertedAsciiFormat,
494 pArg);
496 if (pArg != NULL) {
497 PKIX_PL_Free(pArg, plContext);
498 pArg = NULL;
500 convertedAsciiFormat += j;
501 j = 0;
502 break;
503 case 'd':
504 case 'i':
505 case 'o':
506 case 'u':
507 case 'x':
508 case 'X':
509 convertedAsciiFormat[j++] = asciiFormat[i++];
510 convertedAsciiFormat[j++] = asciiFormat[i++];
511 convertedAsciiFormat[j] = '\0';
513 tempUInt = va_arg(args, PKIX_UInt32);
514 if (asciiText != NULL) {
515 asciiText = PR_sprintf_append(asciiText,
516 (const char *)convertedAsciiFormat,
517 tempUInt);
518 } else {
519 asciiText = PR_smprintf
520 ((const char *)convertedAsciiFormat,
521 tempUInt);
523 convertedAsciiFormat += j;
524 j = 0;
525 break;
526 default:
527 convertedAsciiFormat[j++] = asciiFormat[i++];
528 convertedAsciiFormat[j++] = asciiFormat[i++];
529 break;
531 } else {
532 convertedAsciiFormat[j++] = asciiFormat[i++];
536 /* for constant string value at end of fmt */
537 if (j > 0) {
538 convertedAsciiFormat[j] = '\0';
539 if (asciiText != NULL) {
540 asciiText = PR_sprintf_append(asciiText,
541 (const char *)convertedAsciiFormat);
542 } else {
543 asciiText = PR_smprintf((const char *)convertedAsciiFormat);
547 va_end(args);
549 /* Copy temporary char * into a string object */
550 PKIX_CHECK(PKIX_PL_String_Create
551 (PKIX_ESCASCII, (void *)asciiText, 0, pOut, plContext),
552 PKIX_STRINGCREATEFAILED);
554 cleanup:
556 PKIX_FREE(asciiFormat);
558 if (convertedAsciiFormatBase){
559 PR_Free(convertedAsciiFormatBase);
562 if (asciiText){
563 PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n");
564 PR_smprintf_free(asciiText);
567 PKIX_RETURN(STRING);
571 * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h)
573 PKIX_Error *
574 PKIX_PL_GetString(
575 /* ARGSUSED */ PKIX_UInt32 stringID,
576 char *defaultString,
577 PKIX_PL_String **pString,
578 void *plContext)
580 PKIX_ENTER(STRING, "PKIX_PL_GetString");
581 PKIX_NULLCHECK_TWO(pString, defaultString);
583 /* XXX Optimization - use stringID for caching */
584 PKIX_CHECK(PKIX_PL_String_Create
585 (PKIX_ESCASCII, defaultString, 0, pString, plContext),
586 PKIX_STRINGCREATEFAILED);
588 cleanup:
590 PKIX_RETURN(STRING);
594 * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h)
596 PKIX_Error *
597 PKIX_PL_String_GetEncoded(
598 PKIX_PL_String *string,
599 PKIX_UInt32 fmtIndicator,
600 void **pStringRep,
601 PKIX_UInt32 *pLength,
602 void *plContext)
604 PKIX_ENTER(STRING, "PKIX_PL_String_GetEncoded");
605 PKIX_NULLCHECK_THREE(string, pStringRep, pLength);
607 switch (fmtIndicator) {
608 case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG:
609 PKIX_CHECK(pkix_UTF16_to_EscASCII
610 (string->utf16String,
611 string->utf16Length,
612 (fmtIndicator == PKIX_ESCASCII_DEBUG),
613 (char **)pStringRep,
614 pLength,
615 plContext),
616 PKIX_UTF16TOESCASCIIFAILED);
617 break;
618 case PKIX_UTF8:
619 PKIX_CHECK(pkix_UTF16_to_UTF8
620 (string->utf16String,
621 string->utf16Length,
622 PKIX_FALSE,
623 pStringRep,
624 pLength,
625 plContext),
626 PKIX_UTF16TOUTF8FAILED);
627 break;
628 case PKIX_UTF8_NULL_TERM:
629 PKIX_CHECK(pkix_UTF16_to_UTF8
630 (string->utf16String,
631 string->utf16Length,
632 PKIX_TRUE,
633 pStringRep,
634 pLength,
635 plContext),
636 PKIX_UTF16TOUTF8FAILED);
637 break;
638 case PKIX_UTF16:
639 *pLength = string->utf16Length;
641 PKIX_CHECK(PKIX_PL_Malloc(*pLength, pStringRep, plContext),
642 PKIX_MALLOCFAILED);
644 PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
645 (void) PORT_Memcpy(*pStringRep, string->utf16String, *pLength);
646 break;
647 default:
648 PKIX_ERROR(PKIX_UNKNOWNFORMAT);
651 cleanup:
653 PKIX_RETURN(STRING);