PageRenderTime 59ms CodeModel.GetById 20ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c

http://github.com/zpao/v8monkey
C | 654 lines | 441 code | 98 blank | 115 comment | 56 complexity | b3f88f0cfafb433516e1ea1ec78d799c MD5 | raw file
  1/* ***** BEGIN LICENSE BLOCK *****
  2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3 *
  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/
  8 *
  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.
 13 *
 14 * The Original Code is the PKIX-C library.
 15 *
 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.
 20 *
 21 * Contributor(s):
 22 *   Sun Microsystems, Inc.
 23 *
 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.
 35 *
 36 * ***** END LICENSE BLOCK ***** */
 37/*
 38 * pkix_pl_string.c
 39 *
 40 * String Object Functions
 41 *
 42 */
 43
 44#include "pkix_pl_string.h"
 45
 46/* --Private-String-Functions------------------------------------- */
 47
 48/*
 49 * FUNCTION: pkix_pl_String_Comparator
 50 * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
 51 *
 52 * NOTE:
 53 *  This function is a utility function called by pkix_pl_String_Equals().
 54 *  It is not officially registered as a comparator.
 55 */
 56static PKIX_Error *
 57pkix_pl_String_Comparator(
 58        PKIX_PL_String *firstString,
 59        PKIX_PL_String *secondString,
 60        PKIX_Int32 *pResult,
 61        void *plContext)
 62{
 63        PKIX_UInt32 i;
 64        PKIX_Int32 result;
 65        unsigned char *p1 = NULL;
 66        unsigned char *p2 = NULL;
 67
 68        PKIX_ENTER(STRING, "pkix_pl_String_Comparator");
 69        PKIX_NULLCHECK_THREE(firstString, secondString, pResult);
 70
 71        result = 0;
 72
 73        p1 = (unsigned char*) firstString->utf16String;
 74        p2 = (unsigned char*) secondString->utf16String;
 75
 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;
 84                }
 85        }
 86
 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;
 94                }
 95        }
 96
 97        *pResult = result;
 98
 99        PKIX_RETURN(STRING);
100}
101
102/*
103 * FUNCTION: pkix_pl_String_Destroy
104 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
105 */
106static PKIX_Error *
107pkix_pl_String_Destroy(
108        PKIX_PL_Object *object,
109        void *plContext)
110{
111        PKIX_PL_String *string = NULL;
112
113        PKIX_ENTER(STRING, "pkix_pl_String_Destroy");
114        PKIX_NULLCHECK_ONE(object);
115
116        PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
117                    PKIX_ARGUMENTNOTSTRING);
118
119        string = (PKIX_PL_String*)object;
120
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;
126        }
127
128        /* Destroy UTF16 String */
129        if (string->utf16String != NULL) {
130                PKIX_FREE(string->utf16String);
131                string->utf16String = NULL;
132                string->utf16Length = 0;
133        }
134
135cleanup:
136
137        PKIX_RETURN(STRING);
138}
139
140/*
141 * FUNCTION: pkix_pl_String_ToString
142 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
143 */
144static PKIX_Error *
145pkix_pl_String_ToString(
146        PKIX_PL_Object *object,
147        PKIX_PL_String **pString,
148        void *plContext)
149{
150        PKIX_PL_String *string = NULL;
151        char *ascii = NULL;
152        PKIX_UInt32 length;
153
154        PKIX_ENTER(STRING, "pkix_pl_String_ToString");
155        PKIX_NULLCHECK_TWO(object, pString);
156
157        PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
158                    PKIX_ARGUMENTNOTSTRING);
159
160        string = (PKIX_PL_String*)object;
161
162        PKIX_CHECK(PKIX_PL_String_GetEncoded
163                (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext),
164                PKIX_STRINGGETENCODEDFAILED);
165
166        PKIX_CHECK(PKIX_PL_String_Create
167                    (PKIX_ESCASCII, ascii, 0, pString, plContext),
168                    PKIX_STRINGCREATEFAILED);
169
170        goto cleanup;
171
172cleanup:
173
174        PKIX_FREE(ascii);
175
176        PKIX_RETURN(STRING);
177}
178
179/*
180 * FUNCTION: pkix_pl_String_Equals
181 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
182 */
183static PKIX_Error *
184pkix_pl_String_Equals(
185        PKIX_PL_Object *firstObject,
186        PKIX_PL_Object *secondObject,
187        PKIX_Boolean *pResult,
188        void *plContext)
189{
190        PKIX_UInt32 secondType;
191        PKIX_Int32 cmpResult = 0;
192
193        PKIX_ENTER(STRING, "pkix_pl_String_Equals");
194        PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
195
196        /* Sanity check: Test that "firstObject" is a Strings */
197        PKIX_CHECK(pkix_CheckType(firstObject, PKIX_STRING_TYPE, plContext),
198                PKIX_FIRSTOBJECTNOTSTRING);
199
200        /* "SecondObject" doesn't have to be a string */
201        PKIX_CHECK(PKIX_PL_Object_GetType
202                (secondObject, &secondType, plContext),
203                PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
204
205        /* If types differ, then we will return false */
206        *pResult = PKIX_FALSE;
207
208        if (secondType != PKIX_STRING_TYPE) goto cleanup;
209
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);
217
218        /* Strings are equal iff Comparator Result is 0 */
219        *pResult = (cmpResult == 0);
220
221cleanup:
222
223        PKIX_RETURN(STRING);
224}
225
226/*
227 * FUNCTION: pkix_pl_String_Hashcode
228 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
229 */
230static PKIX_Error *
231pkix_pl_String_Hashcode(
232        PKIX_PL_Object *object,
233        PKIX_UInt32 *pHashcode,
234        void *plContext)
235{
236        PKIX_PL_String *string = NULL;
237
238        PKIX_ENTER(STRING, "pkix_pl_String_Hashcode");
239        PKIX_NULLCHECK_TWO(object, pHashcode);
240
241        PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
242                PKIX_OBJECTNOTSTRING);
243
244        string = (PKIX_PL_String*)object;
245
246        PKIX_CHECK(pkix_hash
247                ((const unsigned char *)string->utf16String,
248                string->utf16Length,
249                pHashcode,
250                plContext),
251                PKIX_HASHFAILED);
252
253cleanup:
254
255        PKIX_RETURN(STRING);
256}
257
258/*
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
264 *
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.
268 */
269PKIX_Error *
270pkix_pl_String_RegisterSelf(
271        void *plContext)
272{
273        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
274        pkix_ClassTable_Entry entry;
275
276        PKIX_ENTER(STRING, "pkix_pl_String_RegisterSelf");
277
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;
287
288        systemClasses[PKIX_STRING_TYPE] = entry;
289
290        PKIX_RETURN(STRING);
291}
292
293
294/* --Public-String-Functions----------------------------------------- */
295
296/*
297 * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h)
298 */
299PKIX_Error *
300PKIX_PL_String_Create(
301        PKIX_UInt32 fmtIndicator,
302        const void *stringRep,
303        PKIX_UInt32 stringLen,
304        PKIX_PL_String **pString,
305        void *plContext)
306{
307        PKIX_PL_String *string = NULL;
308        unsigned char *utf16Char = NULL;
309        PKIX_UInt32 i;
310
311        PKIX_ENTER(STRING, "PKIX_PL_String_Create");
312        PKIX_NULLCHECK_TWO(pString, stringRep);
313
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);
320
321        string->utf16String = NULL;
322        string->utf16Length = 0;
323
324        /* XXX For Debugging */
325        string->escAsciiString = NULL;
326        string->escAsciiLength = 0;
327
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);
332
333                /* XXX Cache for Debugging */
334                PKIX_CHECK(PKIX_PL_Malloc
335                            ((string->escAsciiLength)+1,
336                            (void **)&string->escAsciiString,
337                            plContext),
338                            PKIX_MALLOCFAILED);
339
340                (void) PORT_Memcpy
341                        (string->escAsciiString,
342                        (void *)((char *)stringRep),
343                        (string->escAsciiLength)+1);
344
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);
370                }
371
372                utf16Char = (unsigned char *)stringRep;
373
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;
390                                }
391                        }
392                }
393
394                /* Create UTF16 String */
395                string->utf16Length = stringLen;
396
397                /* Alloc space for string */
398                PKIX_CHECK(PKIX_PL_Malloc
399                            (stringLen, &string->utf16String, plContext),
400                            PKIX_MALLOCFAILED);
401
402                PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
403                (void) PORT_Memcpy
404                        (string->utf16String, stringRep, stringLen);
405                break;
406
407        default:
408                PKIX_ERROR(PKIX_UNKNOWNFORMAT);
409        }
410
411        *pString = string;
412
413cleanup:
414
415        if (PKIX_ERROR_RECEIVED){
416                PKIX_DECREF(string);
417        }
418
419        PKIX_RETURN(STRING);
420}
421
422/*
423 * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h)
424 */
425PKIX_Error *
426PKIX_PL_Sprintf(
427        PKIX_PL_String **pOut,
428        void *plContext,
429        const PKIX_PL_String *fmt,
430        ...)
431{
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;
441
442        PKIX_ENTER(STRING, "PKIX_PL_Sprintf");
443        PKIX_NULLCHECK_TWO(pOut, fmt);
444
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);
452
453        PKIX_STRING_DEBUG("\tCalling PR_Malloc).\n");
454        convertedAsciiFormat = PR_Malloc(length + 1);
455        if (convertedAsciiFormat == NULL)
456                PKIX_ERROR_ALLOC_ERROR();
457
458        convertedAsciiFormatBase = convertedAsciiFormat;
459
460        PKIX_STRING_DEBUG("\tCalling va_start).\n");
461        va_start(args, fmt);
462
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';
472
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;
486                                }
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);
495                                }
496                                if (pArg != NULL) {
497                                        PKIX_PL_Free(pArg, plContext);
498                                        pArg = NULL;
499                                }
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';
512
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);
522                                }     
523                                convertedAsciiFormat += j;
524                                j = 0;
525                                break;
526                        default:
527                                convertedAsciiFormat[j++] = asciiFormat[i++];
528                                convertedAsciiFormat[j++] = asciiFormat[i++];
529                                break;
530                        }
531                } else {
532                        convertedAsciiFormat[j++] = asciiFormat[i++];
533                }
534        }
535
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);
544                }
545        }
546
547        va_end(args);
548
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);
553
554cleanup:
555
556        PKIX_FREE(asciiFormat);
557
558        if (convertedAsciiFormatBase){
559                PR_Free(convertedAsciiFormatBase);
560        }
561
562        if (asciiText){
563                PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n");
564                PR_smprintf_free(asciiText);
565        }
566
567        PKIX_RETURN(STRING);
568}
569
570/*
571 * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h)
572 */
573PKIX_Error *
574PKIX_PL_GetString(
575        /* ARGSUSED */ PKIX_UInt32 stringID,
576        char *defaultString,
577        PKIX_PL_String **pString,
578        void *plContext)
579{
580        PKIX_ENTER(STRING, "PKIX_PL_GetString");
581        PKIX_NULLCHECK_TWO(pString, defaultString);
582
583        /* XXX Optimization - use stringID for caching */
584        PKIX_CHECK(PKIX_PL_String_Create
585                    (PKIX_ESCASCII, defaultString, 0, pString, plContext),
586                    PKIX_STRINGCREATEFAILED);
587
588cleanup:
589
590        PKIX_RETURN(STRING);
591}
592
593/*
594 * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h)
595 */
596PKIX_Error *
597PKIX_PL_String_GetEncoded(
598        PKIX_PL_String *string,
599        PKIX_UInt32 fmtIndicator,
600        void **pStringRep,
601        PKIX_UInt32 *pLength,
602        void *plContext)
603{
604        PKIX_ENTER(STRING, "PKIX_PL_String_GetEncoded");
605        PKIX_NULLCHECK_THREE(string, pStringRep, pLength);
606
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;
640
641                PKIX_CHECK(PKIX_PL_Malloc(*pLength, pStringRep, plContext),
642                            PKIX_MALLOCFAILED);
643
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);
649        }
650
651cleanup:
652
653        PKIX_RETURN(STRING);
654}