tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }