Source code

Revision control

Copy as Markdown

Other Tools

/* 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);
}