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
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.
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 ***** */
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)
53 * This function is a utility function called by pkix_pl_String_Equals().
54 * It is not officially registered as a comparator.
57 pkix_pl_String_Comparator(
58 PKIX_PL_String
*firstString
,
59 PKIX_PL_String
*secondString
,
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
);
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
++) {
82 } else if (*p1
> *p2
){
87 /* If two arrays are identical so far, the longer one is greater */
89 if (firstString
->utf16Length
< secondString
->utf16Length
) {
91 } else if (firstString
->utf16Length
>
92 secondString
->utf16Length
) {
103 * FUNCTION: pkix_pl_String_Destroy
104 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
107 pkix_pl_String_Destroy(
108 PKIX_PL_Object
*object
,
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;
141 * FUNCTION: pkix_pl_String_ToString
142 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
145 pkix_pl_String_ToString(
146 PKIX_PL_Object
*object
,
147 PKIX_PL_String
**pString
,
150 PKIX_PL_String
*string
= NULL
;
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
);
180 * FUNCTION: pkix_pl_String_Equals
181 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
184 pkix_pl_String_Equals(
185 PKIX_PL_Object
*firstObject
,
186 PKIX_PL_Object
*secondObject
,
187 PKIX_Boolean
*pResult
,
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
,
216 PKIX_STRINGCOMPARATORFAILED
);
218 /* Strings are equal iff Comparator Result is 0 */
219 *pResult
= (cmpResult
== 0);
227 * FUNCTION: pkix_pl_String_Hashcode
228 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
231 pkix_pl_String_Hashcode(
232 PKIX_PL_Object
*object
,
233 PKIX_UInt32
*pHashcode
,
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
;
247 ((const unsigned char *)string
->utf16String
,
259 * FUNCTION: pkix_pl_String_RegisterSelf
261 * Registers PKIX_STRING_TYPE and its related functions with systemClasses[]
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
270 pkix_pl_String_RegisterSelf(
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
;
294 /* --Public-String-Functions----------------------------------------- */
297 * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h)
300 PKIX_PL_String_Create(
301 PKIX_UInt32 fmtIndicator
,
302 const void *stringRep
,
303 PKIX_UInt32 stringLen
,
304 PKIX_PL_String
**pString
,
307 PKIX_PL_String
*string
= NULL
;
308 unsigned char *utf16Char
= NULL
;
311 PKIX_ENTER(STRING
, "PKIX_PL_String_Create");
312 PKIX_NULLCHECK_TWO(pString
, stringRep
);
314 PKIX_CHECK(PKIX_PL_Object_Alloc
316 sizeof (PKIX_PL_String
),
317 (PKIX_PL_Object
**)&string
,
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
,
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
,
353 PKIX_ESCASCIITOUTF16FAILED
);
356 /* Convert the UTF8 string to UTF16 */
357 PKIX_CHECK(pkix_UTF8_to_UTF16
360 &string
->utf16String
,
361 &string
->utf16Length
,
363 PKIX_UTF8TOUTF16FAILED
);
366 /* UTF16 Strings must be even in length */
367 if (stringLen
%2 == 1) {
369 PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR
);
372 utf16Char
= (unsigned char *)stringRep
;
374 /* Make sure this is a valid UTF-16 String */
376 (i
< stringLen
) && (pkixErrorResult
== NULL
); \
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
);
388 /* Surrogate quartet is valid. */
394 /* Create UTF16 String */
395 string
->utf16Length
= stringLen
;
397 /* Alloc space for string */
398 PKIX_CHECK(PKIX_PL_Malloc
399 (stringLen
, &string
->utf16String
, plContext
),
402 PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
404 (string
->utf16String
, stringRep
, stringLen
);
408 PKIX_ERROR(PKIX_UNKNOWNFORMAT
);
415 if (PKIX_ERROR_RECEIVED
){
423 * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h)
427 PKIX_PL_String
**pOut
,
429 const PKIX_PL_String
*fmt
,
432 PKIX_PL_String
*tempString
= NULL
;
433 PKIX_UInt32 tempUInt
= 0;
435 char *asciiText
= NULL
;
436 char *asciiFormat
= NULL
;
437 char *convertedAsciiFormat
= NULL
;
438 char *convertedAsciiFormatBase
= NULL
;
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
,
448 (void **)&asciiFormat
,
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");
466 if ((asciiFormat
[i
] == '%')&&((i
+1) < length
)) {
467 switch (asciiFormat
[i
+1]) {
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
482 PKIX_STRINGGETENCODEDFAILED
);
484 /* there may be a NULL in var_args */
487 if (asciiText
!= NULL
) {
488 asciiText
= PR_sprintf_append(asciiText
,
489 (const char *)convertedAsciiFormat
,
492 asciiText
= PR_smprintf
493 ((const char *)convertedAsciiFormat
,
497 PKIX_PL_Free(pArg
, plContext
);
500 convertedAsciiFormat
+= j
;
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
,
519 asciiText
= PR_smprintf
520 ((const char *)convertedAsciiFormat
,
523 convertedAsciiFormat
+= j
;
527 convertedAsciiFormat
[j
++] = asciiFormat
[i
++];
528 convertedAsciiFormat
[j
++] = asciiFormat
[i
++];
532 convertedAsciiFormat
[j
++] = asciiFormat
[i
++];
536 /* for constant string value at end of fmt */
538 convertedAsciiFormat
[j
] = '\0';
539 if (asciiText
!= NULL
) {
540 asciiText
= PR_sprintf_append(asciiText
,
541 (const char *)convertedAsciiFormat
);
543 asciiText
= PR_smprintf((const char *)convertedAsciiFormat
);
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
);
556 PKIX_FREE(asciiFormat
);
558 if (convertedAsciiFormatBase
){
559 PR_Free(convertedAsciiFormatBase
);
563 PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n");
564 PR_smprintf_free(asciiText
);
571 * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h)
575 /* ARGSUSED */ PKIX_UInt32 stringID
,
577 PKIX_PL_String
**pString
,
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
);
594 * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h)
597 PKIX_PL_String_GetEncoded(
598 PKIX_PL_String
*string
,
599 PKIX_UInt32 fmtIndicator
,
601 PKIX_UInt32
*pLength
,
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
,
612 (fmtIndicator
== PKIX_ESCASCII_DEBUG
),
616 PKIX_UTF16TOESCASCIIFAILED
);
619 PKIX_CHECK(pkix_UTF16_to_UTF8
620 (string
->utf16String
,
626 PKIX_UTF16TOUTF8FAILED
);
628 case PKIX_UTF8_NULL_TERM
:
629 PKIX_CHECK(pkix_UTF16_to_UTF8
630 (string
->utf16String
,
636 PKIX_UTF16TOUTF8FAILED
);
639 *pLength
= string
->utf16Length
;
641 PKIX_CHECK(PKIX_PL_Malloc(*pLength
, pStringRep
, plContext
),
644 PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
645 (void) PORT_Memcpy(*pStringRep
, string
->utf16String
, *pLength
);
648 PKIX_ERROR(PKIX_UNKNOWNFORMAT
);