andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * pkix_pl_string.c andre@0: * andre@0: * String Object Functions andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_pl_string.h" andre@0: andre@0: /* --Private-String-Functions------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_String_Comparator andre@0: * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) andre@0: * andre@0: * NOTE: andre@0: * This function is a utility function called by pkix_pl_String_Equals(). andre@0: * It is not officially registered as a comparator. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_String_Comparator( andre@0: PKIX_PL_String *firstString, andre@0: PKIX_PL_String *secondString, andre@0: PKIX_Int32 *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 i; andre@0: PKIX_Int32 result; andre@0: unsigned char *p1 = NULL; andre@0: unsigned char *p2 = NULL; andre@0: andre@0: PKIX_ENTER(STRING, "pkix_pl_String_Comparator"); andre@0: PKIX_NULLCHECK_THREE(firstString, secondString, pResult); andre@0: andre@0: result = 0; andre@0: andre@0: p1 = (unsigned char*) firstString->utf16String; andre@0: p2 = (unsigned char*) secondString->utf16String; andre@0: andre@0: /* Compare characters until you find a difference */ andre@0: for (i = 0; ((i < firstString->utf16Length) && andre@0: (i < secondString->utf16Length) && andre@0: result == 0); i++, p1++, p2++) { andre@0: if (*p1 < *p2){ andre@0: result = -1; andre@0: } else if (*p1 > *p2){ andre@0: result = 1; andre@0: } andre@0: } andre@0: andre@0: /* If two arrays are identical so far, the longer one is greater */ andre@0: if (result == 0) { andre@0: if (firstString->utf16Length < secondString->utf16Length) { andre@0: result = -1; andre@0: } else if (firstString->utf16Length > andre@0: secondString->utf16Length) { andre@0: result = 1; andre@0: } andre@0: } andre@0: andre@0: *pResult = result; andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_String_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_String_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *string = NULL; andre@0: andre@0: PKIX_ENTER(STRING, "pkix_pl_String_Destroy"); andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), andre@0: PKIX_ARGUMENTNOTSTRING); andre@0: andre@0: string = (PKIX_PL_String*)object; andre@0: andre@0: /* XXX For debugging Destroy EscASCII String */ andre@0: if (string->escAsciiString != NULL) { andre@0: PKIX_FREE(string->escAsciiString); andre@0: string->escAsciiString = NULL; andre@0: string->escAsciiLength = 0; andre@0: } andre@0: andre@0: /* Destroy UTF16 String */ andre@0: if (string->utf16String != NULL) { andre@0: PKIX_FREE(string->utf16String); andre@0: string->utf16String = NULL; andre@0: string->utf16Length = 0; andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_String_ToString andre@0: * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_String_ToString( andre@0: PKIX_PL_Object *object, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *string = NULL; andre@0: char *ascii = NULL; andre@0: PKIX_UInt32 length; andre@0: andre@0: PKIX_ENTER(STRING, "pkix_pl_String_ToString"); andre@0: PKIX_NULLCHECK_TWO(object, pString); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), andre@0: PKIX_ARGUMENTNOTSTRING); andre@0: andre@0: string = (PKIX_PL_String*)object; andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_GetEncoded andre@0: (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext), andre@0: PKIX_STRINGGETENCODEDFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, ascii, 0, pString, plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: goto cleanup; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_FREE(ascii); andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_String_Equals andre@0: * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_String_Equals( andre@0: PKIX_PL_Object *firstObject, andre@0: PKIX_PL_Object *secondObject, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 secondType; andre@0: PKIX_Int32 cmpResult = 0; andre@0: andre@0: PKIX_ENTER(STRING, "pkix_pl_String_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); andre@0: andre@0: /* Sanity check: Test that "firstObject" is a Strings */ andre@0: PKIX_CHECK(pkix_CheckType(firstObject, PKIX_STRING_TYPE, plContext), andre@0: PKIX_FIRSTOBJECTNOTSTRING); andre@0: andre@0: /* "SecondObject" doesn't have to be a string */ andre@0: PKIX_CHECK(PKIX_PL_Object_GetType andre@0: (secondObject, &secondType, plContext), andre@0: PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); andre@0: andre@0: /* If types differ, then we will return false */ andre@0: *pResult = PKIX_FALSE; andre@0: andre@0: if (secondType != PKIX_STRING_TYPE) goto cleanup; andre@0: andre@0: /* It's safe to cast here */ andre@0: PKIX_CHECK(pkix_pl_String_Comparator andre@0: ((PKIX_PL_String*)firstObject, andre@0: (PKIX_PL_String*)secondObject, andre@0: &cmpResult, andre@0: plContext), andre@0: PKIX_STRINGCOMPARATORFAILED); andre@0: andre@0: /* Strings are equal iff Comparator Result is 0 */ andre@0: *pResult = (cmpResult == 0); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_String_Hashcode andre@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_String_Hashcode( andre@0: PKIX_PL_Object *object, andre@0: PKIX_UInt32 *pHashcode, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *string = NULL; andre@0: andre@0: PKIX_ENTER(STRING, "pkix_pl_String_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(object, pHashcode); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext), andre@0: PKIX_OBJECTNOTSTRING); andre@0: andre@0: string = (PKIX_PL_String*)object; andre@0: andre@0: PKIX_CHECK(pkix_hash andre@0: ((const unsigned char *)string->utf16String, andre@0: string->utf16Length, andre@0: pHashcode, andre@0: plContext), andre@0: PKIX_HASHFAILED); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_String_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_STRING_TYPE and its related functions with systemClasses[] andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, which should andre@0: * only be called once, it is acceptable that this function is not andre@0: * thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_String_RegisterSelf( andre@0: void *plContext) andre@0: { andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry entry; andre@0: andre@0: PKIX_ENTER(STRING, "pkix_pl_String_RegisterSelf"); andre@0: andre@0: entry.description = "String"; andre@0: entry.objCounter = 0; andre@0: entry.typeObjectSize = sizeof(PKIX_PL_String); andre@0: entry.destructor = pkix_pl_String_Destroy; andre@0: entry.equalsFunction = pkix_pl_String_Equals; andre@0: entry.hashcodeFunction = pkix_pl_String_Hashcode; andre@0: entry.toStringFunction = pkix_pl_String_ToString; andre@0: entry.comparator = NULL; andre@0: entry.duplicateFunction = pkix_duplicateImmutable; andre@0: andre@0: systemClasses[PKIX_STRING_TYPE] = entry; andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: andre@0: /* --Public-String-Functions----------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_String_Create( andre@0: PKIX_UInt32 fmtIndicator, andre@0: const void *stringRep, andre@0: PKIX_UInt32 stringLen, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *string = NULL; andre@0: unsigned char *utf16Char = NULL; andre@0: PKIX_UInt32 i; andre@0: andre@0: PKIX_ENTER(STRING, "PKIX_PL_String_Create"); andre@0: PKIX_NULLCHECK_TWO(pString, stringRep); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_STRING_TYPE, andre@0: sizeof (PKIX_PL_String), andre@0: (PKIX_PL_Object **)&string, andre@0: plContext), andre@0: PKIX_COULDNOTALLOCATENEWSTRINGOBJECT); andre@0: andre@0: string->utf16String = NULL; andre@0: string->utf16Length = 0; andre@0: andre@0: /* XXX For Debugging */ andre@0: string->escAsciiString = NULL; andre@0: string->escAsciiLength = 0; andre@0: andre@0: switch (fmtIndicator) { andre@0: case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG: andre@0: PKIX_STRING_DEBUG("\tCalling PL_strlen).\n"); andre@0: string->escAsciiLength = PL_strlen(stringRep); andre@0: andre@0: /* XXX Cache for Debugging */ andre@0: PKIX_CHECK(PKIX_PL_Malloc andre@0: ((string->escAsciiLength)+1, andre@0: (void **)&string->escAsciiString, andre@0: plContext), andre@0: PKIX_MALLOCFAILED); andre@0: andre@0: (void) PORT_Memcpy andre@0: (string->escAsciiString, andre@0: (void *)((char *)stringRep), andre@0: (string->escAsciiLength)+1); andre@0: andre@0: /* Convert the EscASCII string to UTF16 */ andre@0: PKIX_CHECK(pkix_EscASCII_to_UTF16 andre@0: (string->escAsciiString, andre@0: string->escAsciiLength, andre@0: (fmtIndicator == PKIX_ESCASCII_DEBUG), andre@0: &string->utf16String, andre@0: &string->utf16Length, andre@0: plContext), andre@0: PKIX_ESCASCIITOUTF16FAILED); andre@0: break; andre@0: case PKIX_UTF8: andre@0: /* Convert the UTF8 string to UTF16 */ andre@0: PKIX_CHECK(pkix_UTF8_to_UTF16 andre@0: (stringRep, andre@0: stringLen, andre@0: &string->utf16String, andre@0: &string->utf16Length, andre@0: plContext), andre@0: PKIX_UTF8TOUTF16FAILED); andre@0: break; andre@0: case PKIX_UTF16: andre@0: /* UTF16 Strings must be even in length */ andre@0: if (stringLen%2 == 1) { andre@0: PKIX_DECREF(string); andre@0: PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR); andre@0: } andre@0: andre@0: utf16Char = (unsigned char *)stringRep; andre@0: andre@0: /* Make sure this is a valid UTF-16 String */ andre@0: for (i = 0; \ andre@0: (i < stringLen) && (pkixErrorResult == NULL); \ andre@0: i += 2) { andre@0: /* Check that surrogate pairs are valid */ andre@0: if ((utf16Char[i] >= 0xD8)&& andre@0: (utf16Char[i] <= 0xDB)) { andre@0: if ((i+2) >= stringLen) { andre@0: PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR); andre@0: /* Second pair should be DC00-DFFF */ andre@0: } else if (!((utf16Char[i+2] >= 0xDC)&& andre@0: (utf16Char[i+2] <= 0xDF))) { andre@0: PKIX_ERROR(PKIX_UTF16LOWZONEERROR); andre@0: } else { andre@0: /* Surrogate quartet is valid. */ andre@0: i += 2; andre@0: } andre@0: } andre@0: } andre@0: andre@0: /* Create UTF16 String */ andre@0: string->utf16Length = stringLen; andre@0: andre@0: /* Alloc space for string */ andre@0: PKIX_CHECK(PKIX_PL_Malloc andre@0: (stringLen, &string->utf16String, plContext), andre@0: PKIX_MALLOCFAILED); andre@0: andre@0: PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n"); andre@0: (void) PORT_Memcpy andre@0: (string->utf16String, stringRep, stringLen); andre@0: break; andre@0: andre@0: default: andre@0: PKIX_ERROR(PKIX_UNKNOWNFORMAT); andre@0: } andre@0: andre@0: *pString = string; andre@0: andre@0: cleanup: andre@0: andre@0: if (PKIX_ERROR_RECEIVED){ andre@0: PKIX_DECREF(string); andre@0: } andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_Sprintf( andre@0: PKIX_PL_String **pOut, andre@0: void *plContext, andre@0: const PKIX_PL_String *fmt, andre@0: ...) andre@0: { andre@0: PKIX_PL_String *tempString = NULL; andre@0: PKIX_UInt32 tempUInt = 0; andre@0: void *pArg = NULL; andre@0: char *asciiText = NULL; andre@0: char *asciiFormat = NULL; andre@0: char *convertedAsciiFormat = NULL; andre@0: char *convertedAsciiFormatBase = NULL; andre@0: va_list args; andre@0: PKIX_UInt32 length, i, j, dummyLen; andre@0: andre@0: PKIX_ENTER(STRING, "PKIX_PL_Sprintf"); andre@0: PKIX_NULLCHECK_TWO(pOut, fmt); andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_GetEncoded andre@0: ((PKIX_PL_String *)fmt, andre@0: PKIX_ESCASCII, andre@0: (void **)&asciiFormat, andre@0: &length, andre@0: plContext), andre@0: PKIX_STRINGGETENCODEDFAILED); andre@0: andre@0: PKIX_STRING_DEBUG("\tCalling PR_Malloc).\n"); andre@0: convertedAsciiFormat = PR_Malloc(length + 1); andre@0: if (convertedAsciiFormat == NULL) andre@0: PKIX_ERROR_ALLOC_ERROR(); andre@0: andre@0: convertedAsciiFormatBase = convertedAsciiFormat; andre@0: andre@0: PKIX_STRING_DEBUG("\tCalling va_start).\n"); andre@0: va_start(args, fmt); andre@0: andre@0: i = 0; andre@0: j = 0; andre@0: while (i < length) { andre@0: if ((asciiFormat[i] == '%')&&((i+1) < length)) { andre@0: switch (asciiFormat[i+1]) { andre@0: case 's': andre@0: convertedAsciiFormat[j++] = asciiFormat[i++]; andre@0: convertedAsciiFormat[j++] = asciiFormat[i++]; andre@0: convertedAsciiFormat[j] = '\0'; andre@0: andre@0: tempString = va_arg(args, PKIX_PL_String *); andre@0: if (tempString != NULL) { andre@0: PKIX_CHECK(PKIX_PL_String_GetEncoded andre@0: ((PKIX_PL_String*) andre@0: tempString, andre@0: PKIX_ESCASCII, andre@0: &pArg, andre@0: &dummyLen, andre@0: plContext), andre@0: PKIX_STRINGGETENCODEDFAILED); andre@0: } else { andre@0: /* there may be a NULL in var_args */ andre@0: pArg = NULL; andre@0: } andre@0: if (asciiText != NULL) { andre@0: asciiText = PR_sprintf_append(asciiText, andre@0: (const char *)convertedAsciiFormat, andre@0: pArg); andre@0: } else { andre@0: asciiText = PR_smprintf andre@0: ((const char *)convertedAsciiFormat, andre@0: pArg); andre@0: } andre@0: if (pArg != NULL) { andre@0: PKIX_PL_Free(pArg, plContext); andre@0: pArg = NULL; andre@0: } andre@0: convertedAsciiFormat += j; andre@0: j = 0; andre@0: break; andre@0: case 'd': andre@0: case 'i': andre@0: case 'o': andre@0: case 'u': andre@0: case 'x': andre@0: case 'X': andre@0: convertedAsciiFormat[j++] = asciiFormat[i++]; andre@0: convertedAsciiFormat[j++] = asciiFormat[i++]; andre@0: convertedAsciiFormat[j] = '\0'; andre@0: andre@0: tempUInt = va_arg(args, PKIX_UInt32); andre@0: if (asciiText != NULL) { andre@0: asciiText = PR_sprintf_append(asciiText, andre@0: (const char *)convertedAsciiFormat, andre@0: tempUInt); andre@0: } else { andre@0: asciiText = PR_smprintf andre@0: ((const char *)convertedAsciiFormat, andre@0: tempUInt); andre@0: } andre@0: convertedAsciiFormat += j; andre@0: j = 0; andre@0: break; andre@0: default: andre@0: convertedAsciiFormat[j++] = asciiFormat[i++]; andre@0: convertedAsciiFormat[j++] = asciiFormat[i++]; andre@0: break; andre@0: } andre@0: } else { andre@0: convertedAsciiFormat[j++] = asciiFormat[i++]; andre@0: } andre@0: } andre@0: andre@0: /* for constant string value at end of fmt */ andre@0: if (j > 0) { andre@0: convertedAsciiFormat[j] = '\0'; andre@0: if (asciiText != NULL) { andre@0: asciiText = PR_sprintf_append(asciiText, andre@0: (const char *)convertedAsciiFormat); andre@0: } else { andre@0: asciiText = PR_smprintf((const char *)convertedAsciiFormat); andre@0: } andre@0: } andre@0: andre@0: va_end(args); andre@0: andre@0: /* Copy temporary char * into a string object */ andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, (void *)asciiText, 0, pOut, plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_FREE(asciiFormat); andre@0: andre@0: if (convertedAsciiFormatBase){ andre@0: PR_Free(convertedAsciiFormatBase); andre@0: } andre@0: andre@0: if (asciiText){ andre@0: PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n"); andre@0: PR_smprintf_free(asciiText); andre@0: } andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_GetString( andre@0: /* ARGSUSED */ PKIX_UInt32 stringID, andre@0: char *defaultString, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(STRING, "PKIX_PL_GetString"); andre@0: PKIX_NULLCHECK_TWO(pString, defaultString); andre@0: andre@0: /* XXX Optimization - use stringID for caching */ andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, defaultString, 0, pString, plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(STRING); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_String_GetEncoded( andre@0: PKIX_PL_String *string, andre@0: PKIX_UInt32 fmtIndicator, andre@0: void **pStringRep, andre@0: PKIX_UInt32 *pLength, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(STRING, "PKIX_PL_String_GetEncoded"); andre@0: PKIX_NULLCHECK_THREE(string, pStringRep, pLength); andre@0: andre@0: switch (fmtIndicator) { andre@0: case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG: andre@0: PKIX_CHECK(pkix_UTF16_to_EscASCII andre@0: (string->utf16String, andre@0: string->utf16Length, andre@0: (fmtIndicator == PKIX_ESCASCII_DEBUG), andre@0: (char **)pStringRep, andre@0: pLength, andre@0: plContext), andre@0: PKIX_UTF16TOESCASCIIFAILED); andre@0: break; andre@0: case PKIX_UTF8: andre@0: PKIX_CHECK(pkix_UTF16_to_UTF8 andre@0: (string->utf16String, andre@0: string->utf16Length, andre@0: PKIX_FALSE, andre@0: pStringRep, andre@0: pLength, andre@0: plContext), andre@0: PKIX_UTF16TOUTF8FAILED); andre@0: break; andre@0: case PKIX_UTF8_NULL_TERM: andre@0: PKIX_CHECK(pkix_UTF16_to_UTF8 andre@0: (string->utf16String, andre@0: string->utf16Length, andre@0: PKIX_TRUE, andre@0: pStringRep, andre@0: pLength, andre@0: plContext), andre@0: PKIX_UTF16TOUTF8FAILED); andre@0: break; andre@0: case PKIX_UTF16: andre@0: *pLength = string->utf16Length; andre@0: andre@0: PKIX_CHECK(PKIX_PL_Malloc(*pLength, pStringRep, plContext), andre@0: PKIX_MALLOCFAILED); andre@0: andre@0: PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n"); andre@0: (void) PORT_Memcpy(*pStringRep, string->utf16String, *pLength); andre@0: break; andre@0: default: andre@0: PKIX_ERROR(PKIX_UNKNOWNFORMAT); andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(STRING); andre@0: }