/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * pkix_pl_bytearray.c * * ByteArray Object Functions * */ #include "pkix_pl_bytearray.h" /* --Private-ByteArray-Functions------------------------------------- */ /* * FUNCTION: pkix_pl_ByteArray_ToHexString * DESCRIPTION: * * Creates a hex-String representation of the ByteArray pointed to by "array" * and stores the result at "pString". The hex-String consists of hex-digit * pairs separated by spaces, and the entire string enclosed within square * brackets, e.g. [43 61 6E 20 79 6F 75 20 72 65 61 64 20 74 68 69 73 3F]. * A zero-length ByteArray is represented as []. * PARAMETERS * "array" * ByteArray to be represented by the hex-String; must be non-NULL * "pString" * Address where String will be stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a Cert Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_pl_ByteArray_ToHexString( PKIX_PL_ByteArray *array, PKIX_PL_String **pString, void *plContext) { char *tempText = NULL; char *stringText = NULL; /* "[XX XX XX ...]" */ PKIX_UInt32 i, outputLen, bufferSize; PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToHexString"); PKIX_NULLCHECK_TWO(array, pString); if ((array->length) == 0) { PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "[]", 0, pString, plContext), PKIX_COULDNOTCREATESTRING); } else { /* * Allocate space for format string * '[' + "XX" + (n-1)*" XX" + ']' + '\0' */ bufferSize = 2 + (3*(array->length)); PKIX_CHECK(PKIX_PL_Malloc (bufferSize, (void **)&stringText, plContext), PKIX_COULDNOTALLOCATEMEMORY); stringText[0] = 0; outputLen = 0; PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); tempText = PR_smprintf ("[%02X", (0x0FF&((char *)(array->array))[0])); PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); outputLen += PL_strlen(tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); stringText = PL_strcat(stringText, tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); PR_smprintf_free(tempText); for (i = 1; i < array->length; i++) { PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); tempText = PR_smprintf (" %02X", (0x0FF&((char *)(array->array))[i])); if (tempText == NULL){ PKIX_ERROR(PKIX_PRSMPRINTFFAILED); } PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); outputLen += PL_strlen(tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); stringText = PL_strcat(stringText, tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); PR_smprintf_free(tempText); tempText = NULL; } stringText[outputLen++] = ']'; stringText[outputLen] = 0; PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, stringText, 0, pString, plContext), PKIX_COULDNOTCREATESTRING); } cleanup: PKIX_FREE(stringText); PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: pkix_pl_ByteArray_Comparator * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h) * * NOTE: * It is not clear that this definition of comparing byte arrays makes * sense. It does allow you to tell whether two blocks of memory are * identical, so we only use it for the Equals function (i.e. we don't * register it as a Compare function for ByteArray). */ static PKIX_Error * pkix_pl_ByteArray_Comparator( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Int32 *pResult, void *plContext) { PKIX_PL_ByteArray *firstByteArray = NULL; PKIX_PL_ByteArray *secondByteArray = NULL; unsigned char *firstData = NULL; unsigned char *secondData = NULL; PKIX_UInt32 i; PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Comparator"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); PKIX_CHECK(pkix_CheckTypes (firstObject, secondObject, PKIX_BYTEARRAY_TYPE, plContext), PKIX_ARGUMENTSNOTBYTEARRAYS); /* It's safe to cast */ firstByteArray = (PKIX_PL_ByteArray *)firstObject; secondByteArray = (PKIX_PL_ByteArray *)secondObject; *pResult = 0; firstData = (unsigned char *)firstByteArray->array; secondData = (unsigned char *)secondByteArray->array; if (firstByteArray->length < secondByteArray->length) { *pResult = -1; } else if (firstByteArray->length > secondByteArray->length) { *pResult = 1; } else if (firstByteArray->length == secondByteArray->length) { /* Check if both array contents are identical */ for (i = 0; (i < firstByteArray->length) && (*pResult == 0); i++) { if (firstData[i] < secondData[i]) { *pResult = -1; } else if (firstData[i] > secondData[i]) { *pResult = 1; } } } cleanup: PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: pkix_pl_ByteArray_ToString * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_ByteArray_ToString( PKIX_PL_Object *object, PKIX_PL_String **pString, void *plContext) { PKIX_PL_ByteArray *array = NULL; char *tempText = NULL; char *stringText = NULL; /* "[OOO, OOO, ... OOO]" */ PKIX_UInt32 i, outputLen, bufferSize; PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToString"); PKIX_NULLCHECK_TWO(object, pString); PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext), PKIX_OBJECTNOTBYTEARRAY); array = (PKIX_PL_ByteArray *)object; if ((array->length) == 0) { PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "[]", 0, pString, plContext), PKIX_COULDNOTCREATESTRING); } else { /* Allocate space for "XXX, ". */ bufferSize = 2+5*array->length; /* Allocate space for format string */ PKIX_CHECK(PKIX_PL_Malloc (bufferSize, (void **)&stringText, plContext), PKIX_MALLOCFAILED); stringText[0] = 0; outputLen = 0; PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); tempText = PR_smprintf ("[%03u", (0x0FF&((char *)(array->array))[0])); PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); outputLen += PL_strlen(tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); stringText = PL_strcat(stringText, tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); PR_smprintf_free(tempText); for (i = 1; i < array->length; i++) { PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n"); tempText = PR_smprintf (", %03u", (0x0FF&((char *)(array->array))[i])); if (tempText == NULL){ PKIX_ERROR(PKIX_PRSMPRINTFFAILED); } PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n"); outputLen += PL_strlen(tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n"); stringText = PL_strcat(stringText, tempText); PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n"); PR_smprintf_free(tempText); tempText = NULL; } stringText[outputLen++] = ']'; stringText[outputLen] = 0; PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, stringText, 0, pString, plContext), PKIX_STRINGCREATEFAILED); } cleanup: PKIX_FREE(stringText); PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: pkix_pl_ByteArray_Equals * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_ByteArray_Equals( PKIX_PL_Object *first, PKIX_PL_Object *second, PKIX_Boolean *pResult, void *plContext) { PKIX_UInt32 secondType; PKIX_Int32 cmpResult = 0; PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Equals"); PKIX_NULLCHECK_THREE(first, second, pResult); /* Sanity check: Test that "first" is a ByteArray */ PKIX_CHECK(pkix_CheckType(first, PKIX_BYTEARRAY_TYPE, plContext), PKIX_FIRSTARGUMENTNOTBYTEARRAY); PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); /* If types differ, then we will return false */ *pResult = PKIX_FALSE; /* Second type may not be a BA */ if (secondType != PKIX_BYTEARRAY_TYPE) goto cleanup; /* It's safe to cast here */ PKIX_CHECK(pkix_pl_ByteArray_Comparator (first, second, &cmpResult, plContext), PKIX_BYTEARRAYCOMPARATORFAILED); /* ByteArrays are equal iff Comparator Result is 0 */ *pResult = (cmpResult == 0); cleanup: PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: pkix_pl_ByteArray_Destroy * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_ByteArray_Destroy( PKIX_PL_Object *object, void *plContext) { PKIX_PL_ByteArray *array = NULL; PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Destroy"); PKIX_NULLCHECK_ONE(object); PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext), PKIX_OBJECTNOTBYTEARRAY); array = (PKIX_PL_ByteArray*)object; PKIX_FREE(array->array); array->array = NULL; array->length = 0; cleanup: PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: pkix_pl_ByteArray_Hashcode * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_pl_ByteArray_Hashcode( PKIX_PL_Object *object, PKIX_UInt32 *pHashcode, void *plContext) { PKIX_PL_ByteArray *array = NULL; PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Hashcode"); PKIX_NULLCHECK_TWO(object, pHashcode); PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext), PKIX_OBJECTNOTBYTEARRAY); array = (PKIX_PL_ByteArray*)object; PKIX_CHECK(pkix_hash ((const unsigned char *)array->array, array->length, pHashcode, plContext), PKIX_HASHFAILED); cleanup: PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: pkix_pl_ByteArray_RegisterSelf * DESCRIPTION: * Registers PKIX_BYTEARRAY_TYPE and its related functions with systemClasses[] * THREAD SAFETY: * Not Thread Safe - for performance and complexity reasons * * Since this function is only called by PKIX_PL_Initialize, which should * only be called once, it is acceptable that this function is not * thread-safe. */ PKIX_Error * pkix_pl_ByteArray_RegisterSelf(void *plContext) { extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; pkix_ClassTable_Entry entry; PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_RegisterSelf"); entry.description = "ByteArray"; entry.objCounter = 0; entry.typeObjectSize = sizeof(PKIX_PL_ByteArray); entry.destructor = pkix_pl_ByteArray_Destroy; entry.equalsFunction = pkix_pl_ByteArray_Equals; entry.hashcodeFunction = pkix_pl_ByteArray_Hashcode; entry.toStringFunction = pkix_pl_ByteArray_ToString; entry.comparator = NULL; entry.duplicateFunction = pkix_duplicateImmutable; systemClasses[PKIX_BYTEARRAY_TYPE] = entry; PKIX_RETURN(BYTEARRAY); } /* --Public-Functions------------------------------------------------------- */ /* * FUNCTION: PKIX_PL_ByteArray_Create (see comments in pkix_pl_system.h) */ PKIX_Error * PKIX_PL_ByteArray_Create( void *array, PKIX_UInt32 length, PKIX_PL_ByteArray **pByteArray, void *plContext) { PKIX_PL_ByteArray *byteArray = NULL; PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_Create"); PKIX_NULLCHECK_ONE(pByteArray); PKIX_CHECK(PKIX_PL_Object_Alloc (PKIX_BYTEARRAY_TYPE, sizeof (PKIX_PL_ByteArray), (PKIX_PL_Object **)&byteArray, plContext), PKIX_COULDNOTCREATEOBJECTSTORAGE); byteArray->length = length; byteArray->array = NULL; if (length != 0){ /* Alloc space for array */ PKIX_NULLCHECK_ONE(array); PKIX_CHECK(PKIX_PL_Malloc (length, (void**)&(byteArray->array), plContext), PKIX_MALLOCFAILED); PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n"); (void) PORT_Memcpy(byteArray->array, array, length); } *pByteArray = byteArray; cleanup: if (PKIX_ERROR_RECEIVED){ PKIX_DECREF(byteArray); } PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: PKIX_PL_ByteArray_GetPointer (see comments in pkix_pl_system.h) */ PKIX_Error * PKIX_PL_ByteArray_GetPointer( PKIX_PL_ByteArray *byteArray, void **pArray, void *plContext) { void *bytes = NULL; PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetPointer"); PKIX_NULLCHECK_TWO(byteArray, pArray); if (byteArray->length != 0){ PKIX_CHECK(PKIX_PL_Malloc (byteArray->length, &bytes, plContext), PKIX_MALLOCFAILED); PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n"); (void) PORT_Memcpy (bytes, byteArray->array, byteArray->length); } *pArray = bytes; cleanup: if (PKIX_ERROR_RECEIVED){ PKIX_FREE(bytes); } PKIX_RETURN(BYTEARRAY); } /* * FUNCTION: PKIX_PL_ByteArray_GetLength (see comments in pkix_pl_system.h) */ PKIX_Error * PKIX_PL_ByteArray_GetLength( PKIX_PL_ByteArray *byteArray, PKIX_UInt32 *pLength, void *plContext) { PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetLength"); PKIX_NULLCHECK_TWO(byteArray, pLength); *pLength = byteArray->length; PKIX_RETURN(BYTEARRAY); }