Mercurial > trustbridge > nss-cmake-static
diff nss/lib/libpkix/pkix/util/pkix_list.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nss/lib/libpkix/pkix/util/pkix_list.c Mon Jul 28 10:47:06 2014 +0200 @@ -0,0 +1,1701 @@ +/* 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_list.c + * + * List Object Functions + * + */ + +#include "pkix_list.h" + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_List_Create_Internal + * DESCRIPTION: + * + * Creates a new List, using the Boolean value of "isHeader" to determine + * whether the new List should be a header, and stores it at "pList". The + * List is initially empty and holds no items. To initially add items to + * the List, use PKIX_List_AppendItem. + * + * PARAMETERS: + * "isHeader" + * Boolean value indicating whether new List should be a header. + * "pList" + * Address where object pointer 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 Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_List_Create_Internal( + PKIX_Boolean isHeader, + PKIX_List **pList, + void *plContext) +{ + PKIX_List *list = NULL; + + PKIX_ENTER(LIST, "pkix_List_Create_Internal"); + PKIX_NULLCHECK_ONE(pList); + + PKIX_CHECK(PKIX_PL_Object_Alloc + (PKIX_LIST_TYPE, + ((PKIX_UInt32)(sizeof (PKIX_List))), + (PKIX_PL_Object **)&list, plContext), + PKIX_ERRORCREATINGLISTITEM); + + list->item = NULL; + list->next = NULL; + list->immutable = PKIX_FALSE; + list->length = 0; + list->isHeader = isHeader; + + *pList = list; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_Destroy + * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_List_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_List *list = NULL; + PKIX_List *nextItem = NULL; + + PKIX_ENTER(LIST, "pkix_List_Destroy"); + PKIX_NULLCHECK_ONE(object); + + /* Check that this object is a list */ + PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext), + PKIX_OBJECTNOTLIST); + + list = (PKIX_List *)object; + + /* We have a valid list. DecRef its item and recurse on next */ + PKIX_DECREF(list->item); + while ((nextItem = list->next) != NULL) { + list->next = nextItem->next; + nextItem->next = NULL; + PKIX_DECREF(nextItem); + } + list->immutable = PKIX_FALSE; + list->length = 0; + list->isHeader = PKIX_FALSE; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_ToString_Helper + * DESCRIPTION: + * + * Helper function that creates a string representation of the List pointed + * to by "list" and stores its address in the object pointed to by "pString". + * + * PARAMETERS + * "list" + * Address of List whose string representation is desired. + * Must be non-NULL. + * "pString" + * Address of object pointer's destination. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a List Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_List_ToString_Helper( + PKIX_List *list, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *itemString = NULL; + PKIX_PL_String *nextString = NULL; + PKIX_PL_String *format = NULL; + PKIX_Boolean empty; + + PKIX_ENTER(LIST, "pkix_List_ToString_Helper"); + PKIX_NULLCHECK_TWO(list, pString); + + /* special case when list is the header */ + if (list->isHeader){ + + PKIX_CHECK(PKIX_List_IsEmpty(list, &empty, plContext), + PKIX_LISTISEMPTYFAILED); + + if (empty){ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + "EMPTY", + 0, + &itemString, + plContext), + PKIX_ERRORCREATINGITEMSTRING); + (*pString) = itemString; + PKIX_DEBUG_EXIT(LIST); + return (NULL); + } else { + PKIX_CHECK(pkix_List_ToString_Helper + (list->next, &itemString, plContext), + PKIX_LISTTOSTRINGHELPERFAILED); + } + + /* Create a string object from the format */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "%s", 0, &format, plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (pString, plContext, format, itemString), + PKIX_SPRINTFFAILED); + } else { + /* Get a string for this list's item */ + if (list->item == NULL) { + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + "(null)", + 0, + &itemString, + plContext), + PKIX_STRINGCREATEFAILED); + } else { + PKIX_CHECK(PKIX_PL_Object_ToString + ((PKIX_PL_Object*)list->item, + &itemString, + plContext), + PKIX_OBJECTTOSTRINGFAILED); + } + if (list->next == NULL) { + /* Just return the itemstring */ + (*pString) = itemString; + PKIX_DEBUG_EXIT(LIST); + return (NULL); + } + + /* Recursive call to get string for this list's next pointer */ + PKIX_CHECK(pkix_List_ToString_Helper + (list->next, &nextString, plContext), + PKIX_LISTTOSTRINGHELPERFAILED); + + /* Create a string object from the format */ + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + "%s, %s", + 0, + &format, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (pString, + plContext, + format, + itemString, + nextString), + PKIX_SPRINTFFAILED); + } + +cleanup: + + PKIX_DECREF(itemString); + PKIX_DECREF(nextString); + PKIX_DECREF(format); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_ToString + * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_List_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_List *list = NULL; + PKIX_PL_String *listString = NULL; + PKIX_PL_String *format = NULL; + + PKIX_ENTER(LIST, "pkix_List_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext), + PKIX_OBJECTNOTLIST); + + list = (PKIX_List *)object; + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + PKIX_CHECK(pkix_List_ToString_Helper(list, &listString, plContext), + PKIX_LISTTOSTRINGHELPERFAILED); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, "(%s)", 0, &format, plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf(pString, plContext, format, listString), + PKIX_SPRINTFFAILED); + +cleanup: + + PKIX_DECREF(listString); + PKIX_DECREF(format); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_Equals + * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_List_Equals( + PKIX_PL_Object *first, + PKIX_PL_Object *second, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_UInt32 secondType; + PKIX_Boolean cmpResult; + PKIX_List *firstList = NULL; + PKIX_List *secondList = NULL; + PKIX_UInt32 firstLength = 0; + PKIX_UInt32 secondLength = 0; + PKIX_PL_Object *firstItem = NULL; + PKIX_PL_Object *secondItem = NULL; + PKIX_UInt32 i = 0; + + PKIX_ENTER(LIST, "pkix_List_Equals"); + PKIX_NULLCHECK_THREE(first, second, pResult); + + /* test that first is a List */ + PKIX_CHECK(pkix_CheckType(first, PKIX_LIST_TYPE, plContext), + PKIX_FIRSTOBJECTNOTLIST); + + /* + * Since we know first is a List, if both references are + * identical, they must be equal + */ + if (first == second){ + *pResult = PKIX_TRUE; + goto cleanup; + } + + /* + * If second isn't a List, we don't throw an error. + * We simply return a Boolean result of FALSE + */ + *pResult = PKIX_FALSE; + PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), + PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); + if (secondType != PKIX_LIST_TYPE) goto cleanup; + + firstList = (PKIX_List *)first; + secondList = (PKIX_List *)second; + + if ((!firstList->isHeader) && (!secondList->isHeader)){ + PKIX_ERROR(PKIX_INPUTLISTSMUSTBELISTHEADERS); + } + + firstLength = firstList->length; + secondLength = secondList->length; + + cmpResult = PKIX_FALSE; + if (firstLength == secondLength){ + for (i = 0, cmpResult = PKIX_TRUE; + ((i < firstLength) && cmpResult); + i++){ + PKIX_CHECK(PKIX_List_GetItem + (firstList, i, &firstItem, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_List_GetItem + (secondList, i, &secondItem, plContext), + PKIX_LISTGETITEMFAILED); + + if ((!firstItem && secondItem) || + (firstItem && !secondItem)){ + cmpResult = PKIX_FALSE; + } else if (!firstItem && !secondItem){ + continue; + } else { + PKIX_CHECK(PKIX_PL_Object_Equals + (firstItem, + secondItem, + &cmpResult, + plContext), + PKIX_OBJECTEQUALSFAILED); + + PKIX_DECREF(firstItem); + PKIX_DECREF(secondItem); + } + } + } + + *pResult = cmpResult; + +cleanup: + + PKIX_DECREF(firstItem); + PKIX_DECREF(secondItem); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_Hashcode + * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_List_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pHashcode, + void *plContext) +{ + PKIX_List *list = NULL; + PKIX_PL_Object *element = NULL; + PKIX_UInt32 hash = 0; + PKIX_UInt32 tempHash = 0; + PKIX_UInt32 length, i; + + PKIX_ENTER(LIST, "pkix_List_Hashcode"); + PKIX_NULLCHECK_TWO(object, pHashcode); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext), + PKIX_OBJECTNOTLIST); + + list = (PKIX_List *)object; + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + length = list->length; + + for (i = 0; i < length; i++){ + PKIX_CHECK(PKIX_List_GetItem(list, i, &element, plContext), + PKIX_LISTGETITEMFAILED); + + if (!element){ + tempHash = 100; + } else { + PKIX_CHECK(PKIX_PL_Object_Hashcode + (element, &tempHash, plContext), + PKIX_LISTHASHCODEFAILED); + } + + hash = 31 * hash + tempHash; + + PKIX_DECREF(element); + } + + *pHashcode = hash; + +cleanup: + + PKIX_DECREF(element); + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_Duplicate + * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) + */ +static PKIX_Error * +pkix_List_Duplicate( + PKIX_PL_Object *object, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_List *list = NULL; + PKIX_List *listDuplicate = NULL; + + PKIX_ENTER(LIST, "pkix_List_Duplicate"); + PKIX_NULLCHECK_TWO(object, pNewObject); + + PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext), + PKIX_OBJECTNOTLIST); + + list = (PKIX_List *)object; + + if (list->immutable){ + PKIX_CHECK(pkix_duplicateImmutable + (object, pNewObject, plContext), + PKIX_DUPLICATEIMMUTABLEFAILED); + } else { + + PKIX_CHECK(pkix_List_Create_Internal + (list->isHeader, &listDuplicate, plContext), + PKIX_LISTCREATEINTERNALFAILED); + + listDuplicate->length = list->length; + + PKIX_INCREF(list->item); + listDuplicate->item = list->item; + + if (list->next == NULL){ + listDuplicate->next = NULL; + } else { + /* Recursively Duplicate list */ + PKIX_CHECK(pkix_List_Duplicate + ((PKIX_PL_Object *)list->next, + (PKIX_PL_Object **)&listDuplicate->next, + plContext), + PKIX_LISTDUPLICATEFAILED); + } + + *pNewObject = (PKIX_PL_Object *)listDuplicate; + } + +cleanup: + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(listDuplicate); + } + + PKIX_RETURN(LIST); +} + + +/* + * FUNCTION: pkix_List_GetElement + * DESCRIPTION: + * + * Copies the "list"'s element at "index" into "element". The input List must + * be the header of the List (as opposed to being an element of the List). The + * index counts from zero and must be less than the List's length. This + * function does NOT increment the reference count of the List element since + * the returned element's reference will not be stored by the calling + * function. + * + * PARAMETERS: + * "list" + * Address of List (must be header) to get element from. Must be non-NULL. + * "index" + * Index of list to get element from. Must be less than List's length. + * "pElement" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Conditionally Thread Safe + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_List_GetElement( + PKIX_List *list, + PKIX_UInt32 index, + PKIX_List **pElement, + void *plContext) +{ + PKIX_List *iterator = NULL; + PKIX_UInt32 length; + PKIX_UInt32 position = 0; + + PKIX_ENTER(LIST, "pkix_List_GetElement"); + PKIX_NULLCHECK_TWO(list, pElement); + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + length = list->length; + + if (index >= length) { + PKIX_ERROR(PKIX_INDEXOUTOFBOUNDS); + } + + for (iterator = list; position++ <= index; iterator = iterator->next) + ; + + (*pElement) = iterator; + +cleanup: + + PKIX_RETURN(LIST); +} + + +/* + * FUNCTION: pkix_List_RegisterSelf + * DESCRIPTION: + * Registers PKIX_LIST_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_List_RegisterSelf(void *plContext) +{ + extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; + pkix_ClassTable_Entry entry; + + PKIX_ENTER(LIST, "pkix_List_RegisterSelf"); + + entry.description = "List"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_List); + entry.destructor = pkix_List_Destroy; + entry.equalsFunction = pkix_List_Equals; + entry.hashcodeFunction = pkix_List_Hashcode; + entry.toStringFunction = pkix_List_ToString; + entry.comparator = NULL; + entry.duplicateFunction = pkix_List_Duplicate; + + systemClasses[PKIX_LIST_TYPE] = entry; + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_Contains + * DESCRIPTION: + * + * Checks a List pointed to by "list", to determine whether it includes + * an entry that is equal to the Object pointed to by "object", and stores + * the result in "pFound". + * + * PARAMETERS: + * "list" + * List to be searched; may be empty; must be non-NULL + * "object" + * Object to be checked for; must be non-NULL + * "pFound" + * Address where the result of the search 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 Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_Contains( + PKIX_List *list, + PKIX_PL_Object *object, + PKIX_Boolean *pFound, + void *plContext) +{ + PKIX_PL_Object *current = NULL; + PKIX_UInt32 numEntries = 0; + PKIX_UInt32 index = 0; + PKIX_Boolean match = PKIX_FALSE; + + PKIX_ENTER(LIST, "pkix_List_Contains"); + PKIX_NULLCHECK_THREE(list, object, pFound); + + PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (index = 0; index < numEntries; index++) { + PKIX_CHECK(PKIX_List_GetItem + (list, index, ¤t, plContext), + PKIX_LISTGETITEMFAILED); + + if (current) { + PKIX_CHECK(PKIX_PL_Object_Equals + (object, current, &match, plContext), + PKIX_OBJECTEQUALSFAILED); + + PKIX_DECREF(current); + } + + if (match) { + break; + } + } + + *pFound = match; + +cleanup: + + PKIX_DECREF(current); + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_Remove + * DESCRIPTION: + * + * Traverses the List pointed to by "list", to find and delete an entry + * that is equal to the Object pointed to by "object". If no such entry + * is found the function does not return an error. + * + * PARAMETERS: + * "list" + * List to be searched; may be empty; must be non-NULL + * "object" + * Object to be checked for and deleted, if found; 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 Validate Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_Remove( + PKIX_List *list, + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *current = NULL; + PKIX_UInt32 numEntries = 0; + PKIX_UInt32 index = 0; + PKIX_Boolean match = PKIX_FALSE; + + PKIX_ENTER(LIST, "pkix_List_Remove"); + PKIX_NULLCHECK_TWO(list, object); + + PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (index = 0; index < numEntries; index++) { + PKIX_CHECK(PKIX_List_GetItem + (list, index, ¤t, plContext), + PKIX_LISTGETITEMFAILED); + + if (current) { + PKIX_CHECK(PKIX_PL_Object_Equals + (object, current, &match, plContext), + PKIX_OBJECTEQUALSFAILED); + + PKIX_DECREF(current); + } + + if (match) { + PKIX_CHECK(PKIX_List_DeleteItem + (list, index, plContext), + PKIX_LISTDELETEITEMFAILED); + break; + } + } + +cleanup: + + PKIX_DECREF(current); + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_RemoveItems + * DESCRIPTION: + * + * Traverses the List pointed to by "list", to find and delete an entry + * that is equal to the Object in the "deleteList". If no such entry + * is found the function does not return an error. + * + * PARAMETERS: + * "list" + * Object in "list" is checked for object in "deleteList" and deleted if + * found; may be empty; must be non-NULL + * "deleteList" + * List of objects to be searched ; may be empty; 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 Validate Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_RemoveItems( + PKIX_List *list, + PKIX_List *deleteList, + void *plContext) +{ + PKIX_PL_Object *current = NULL; + PKIX_UInt32 numEntries = 0; + PKIX_UInt32 index = 0; + + PKIX_ENTER(LIST, "pkix_List_RemoveItems"); + PKIX_NULLCHECK_TWO(list, deleteList); + + PKIX_CHECK(PKIX_List_GetLength(deleteList, &numEntries, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (index = 0; index < numEntries; index++) { + PKIX_CHECK(PKIX_List_GetItem + (deleteList, index, ¤t, plContext), + PKIX_LISTGETITEMFAILED); + + if (current) { + PKIX_CHECK(pkix_List_Remove + (list, current, plContext), + PKIX_OBJECTEQUALSFAILED); + + PKIX_DECREF(current); + } + } + +cleanup: + + PKIX_DECREF(current); + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_MergeLists + * DESCRIPTION: + * + * Creates a new list consisting of the items from "firstList", followed by + * the items on "secondList", returns the new list at "pMergedList". If + * both input lists are NULL or empty, the result is an empty list. If an error + * occurs, the result is NULL. + * + * PARAMETERS: + * "firstList" + * Address of list to be merged from. May be NULL or empty. + * "secondList" + * Address of list to be merged from. May be NULL or empty. + * "pMergedList" + * Address where returned object is stored. + * "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 List Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_MergeLists( + PKIX_List *firstList, + PKIX_List *secondList, + PKIX_List **pMergedList, + void *plContext) +{ + PKIX_List *list = NULL; + PKIX_PL_Object *item = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(LIST, "pkix_List_MergeLists"); + PKIX_NULLCHECK_ONE(pMergedList); + + *pMergedList = NULL; + + PKIX_CHECK(PKIX_List_Create(&list, plContext), + PKIX_LISTCREATEFAILED); + + if (firstList != NULL) { + + PKIX_CHECK(PKIX_List_GetLength(firstList, &numItems, plContext), + PKIX_LISTGETLENGTHFAILED); + } + + for (i = 0; i < numItems; i++) { + + PKIX_CHECK(PKIX_List_GetItem(firstList, i, &item, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_List_AppendItem(list, item, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(item); + } + + numItems = 0; + if (secondList != NULL) { + + PKIX_CHECK(PKIX_List_GetLength + (secondList, + &numItems, + plContext), + PKIX_LISTGETLENGTHFAILED); + + } + + for (i = 0; i < numItems; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (secondList, i, &item, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (list, item, plContext), PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(item); + } + + *pMergedList = list; + list = NULL; + +cleanup: + PKIX_DECREF(list); + PKIX_DECREF(item); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_AppendList + * DESCRIPTION: + * + * Append items on "fromList" to the "toList". Item reference count on + * "toList" is not incremented, but items appended from "fromList" are + * incremented. + * + * PARAMETERS: + * "toList" + * Address of list to be appended to. Must be non-NULL. + * "fromList" + * Address of list to be appended from. May be NULL or empty. + * "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 List Error if the functions fails in a non-fatal way + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_AppendList( + PKIX_List *toList, + PKIX_List *fromList, + void *plContext) +{ + PKIX_PL_Object *item = NULL; + PKIX_UInt32 numItems = 0; + PKIX_UInt32 i; + + PKIX_ENTER(LIST, "pkix_List_AppendList"); + PKIX_NULLCHECK_ONE(toList); + + /* if fromList is NULL or is an empty list, no action */ + + if (fromList == NULL) { + goto cleanup; + } + + PKIX_CHECK(PKIX_List_GetLength(fromList, &numItems, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (numItems == 0) { + goto cleanup; + } + + for (i = 0; i < numItems; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (fromList, i, &item, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_List_AppendItem(toList, item, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(item); + } + +cleanup: + + PKIX_DECREF(item); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_AppendUnique + * DESCRIPTION: + * + * Adds each Object in the List pointed to by "fromList" to the List pointed + * to by "toList", if it is not already a member of that List. In other words, + * "toList" becomes the union of the two sets. + * + * PARAMETERS: + * "toList" + * Address of a List of Objects to be augmented by "fromList". Must be + * non-NULL, but may be empty. + * "fromList" + * Address of a List of Objects to be added, if not already present, to + * "toList". Must be non-NULL, but may be empty. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "toList" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_AppendUnique( + PKIX_List *toList, + PKIX_List *fromList, + void *plContext) +{ + PKIX_Boolean isContained = PKIX_FALSE; + PKIX_UInt32 listLen = 0; + PKIX_UInt32 listIx = 0; + PKIX_PL_Object *object = NULL; + + PKIX_ENTER(BUILD, "pkix_List_AppendUnique"); + PKIX_NULLCHECK_TWO(fromList, toList); + + PKIX_CHECK(PKIX_List_GetLength(fromList, &listLen, plContext), + PKIX_LISTGETLENGTHFAILED); + + for (listIx = 0; listIx < listLen; listIx++) { + + PKIX_CHECK(PKIX_List_GetItem + (fromList, listIx, &object, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(pkix_List_Contains + (toList, object, &isContained, plContext), + PKIX_LISTCONTAINSFAILED); + + if (isContained == PKIX_FALSE) { + PKIX_CHECK(PKIX_List_AppendItem + (toList, object, plContext), + PKIX_LISTAPPENDITEMFAILED); + } + + PKIX_DECREF(object); + } + +cleanup: + + PKIX_DECREF(object); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_QuickSort + * DESCRIPTION: + * + * Sorts List of Objects "fromList" using "comparatorCallback"'s result as + * comasrison key and returns the sorted List at "pSortedList". The sorting + * algorithm used is quick sort (n*logn). + * + * PARAMETERS: + * "fromList" + * Address of a List of Objects to be sorted. Must be non-NULL, but may be + * empty. + * "comparatorCallback" + * Address of callback function that will compare two Objects on the List. + * It should return -1 for less, 0 for equal and 1 for greater. The + * callback implementation chooses what in Objects to be compared. Must be + * non-NULL. + * "pSortedList" + * Address of a List of Objects that shall be sorted and returned. Must be + * non-NULL, but may be empty. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "toList" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_QuickSort( + PKIX_List *fromList, + PKIX_List_SortComparatorCallback comparator, + PKIX_List **pSortedList, + void *plContext) +{ + PKIX_List *sortedList = NULL; + PKIX_List *lessList = NULL; + PKIX_List *greaterList = NULL; + PKIX_List *sortedLessList = NULL; + PKIX_List *sortedGreaterList = NULL; + PKIX_PL_Object *object = NULL; + PKIX_PL_Object *cmpObj = NULL; + PKIX_Int32 cmpResult = 0; + PKIX_UInt32 size = 0; + PKIX_UInt32 i; + + PKIX_ENTER(BUILD, "pkix_List_QuickSort"); + PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList); + + PKIX_CHECK(PKIX_List_GetLength(fromList, &size, plContext), + PKIX_LISTGETLENGTHFAILED); + + PKIX_CHECK(PKIX_List_Create(&lessList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_Create(&greaterList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_GetItem + (fromList, 0, &object, plContext), + PKIX_LISTGETITEMFAILED); + + /* + * Pick the first item on the list as the one to be compared. + * Separate rest of the itmes into two lists: less-than or greater- + * than lists. Sort those two lists recursively. Insert sorted + * less-than list before the picked item and append the greater- + * than list after the picked item. + */ + for (i = 1; i < size; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (fromList, i, &cmpObj, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(comparator(object, cmpObj, &cmpResult, plContext), + PKIX_COMPARATORCALLBACKFAILED); + + if (cmpResult >= 0) { + PKIX_CHECK(PKIX_List_AppendItem + (lessList, cmpObj, plContext), + PKIX_LISTAPPENDITEMFAILED); + } else { + PKIX_CHECK(PKIX_List_AppendItem + (greaterList, cmpObj, plContext), + PKIX_LISTAPPENDITEMFAILED); + } + PKIX_DECREF(cmpObj); + } + + PKIX_CHECK(PKIX_List_Create(&sortedList, plContext), + PKIX_LISTCREATEFAILED); + + PKIX_CHECK(PKIX_List_GetLength(lessList, &size, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (size > 1) { + + PKIX_CHECK(pkix_List_QuickSort + (lessList, comparator, &sortedLessList, plContext), + PKIX_LISTQUICKSORTFAILED); + + PKIX_CHECK(pkix_List_AppendList + (sortedList, sortedLessList, plContext), + PKIX_LISTAPPENDLISTFAILED); + } else { + PKIX_CHECK(pkix_List_AppendList + (sortedList, lessList, plContext), + PKIX_LISTAPPENDLISTFAILED); + } + + PKIX_CHECK(PKIX_List_AppendItem(sortedList, object, plContext), + PKIX_LISTAPPENDFAILED); + + PKIX_CHECK(PKIX_List_GetLength(greaterList, &size, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (size > 1) { + + PKIX_CHECK(pkix_List_QuickSort + (greaterList, comparator, &sortedGreaterList, plContext), + PKIX_LISTQUICKSORTFAILED); + + PKIX_CHECK(pkix_List_AppendList + (sortedList, sortedGreaterList, plContext), + PKIX_LISTAPPENDLISTFAILED); + } else { + PKIX_CHECK(pkix_List_AppendList + (sortedList, greaterList, plContext), + PKIX_LISTAPPENDLISTFAILED); + } + + *pSortedList = sortedList; + +cleanup: + + PKIX_DECREF(cmpObj); + PKIX_DECREF(object); + PKIX_DECREF(sortedGreaterList); + PKIX_DECREF(sortedLessList); + PKIX_DECREF(greaterList); + PKIX_DECREF(lessList); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: pkix_List_BubbleSort + * DESCRIPTION: + * + * Sorts List of Objects "fromList" using "comparatorCallback"'s result as + * comasrison key and returns the sorted List at "pSortedList". The sorting + * algorithm used is bubble sort (n*n). + * + * PARAMETERS: + * "fromList" + * Address of a List of Objects to be sorted. Must be non-NULL, but may be + * empty. + * "comparatorCallback" + * Address of callback function that will compare two Objects on the List. + * It should return -1 for less, 0 for equal and 1 for greater. The + * callback implementation chooses what in Objects to be compared. Must be + * non-NULL. + * "pSortedList" + * Address of a List of Objects that shall be sorted and returned. Must be + * non-NULL, but may be empty. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Not Thread Safe - assumes exclusive access to "toList" + * (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds + * Returns a Fatal Error if the function fails in an unrecoverable way + */ +PKIX_Error * +pkix_List_BubbleSort( + PKIX_List *fromList, + PKIX_List_SortComparatorCallback comparator, + PKIX_List **pSortedList, + void *plContext) +{ + PKIX_List *sortedList = NULL; + PKIX_PL_Object *cmpObj = NULL; + PKIX_PL_Object *leastObj = NULL; + PKIX_Int32 cmpResult = 0; + PKIX_UInt32 size = 0; + PKIX_UInt32 i, j; + + PKIX_ENTER(BUILD, "pkix_List_BubbleSort"); + PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList); + + if (fromList->immutable) { + PKIX_ERROR(PKIX_CANNOTSORTIMMUTABLELIST); + } + PKIX_CHECK(pkix_List_Duplicate + ((PKIX_PL_Object *) fromList, + (PKIX_PL_Object **) &sortedList, + plContext), + PKIX_LISTDUPLICATEFAILED); + + PKIX_CHECK(PKIX_List_GetLength(sortedList, &size, plContext), + PKIX_LISTGETLENGTHFAILED); + + if (size > 1) { + + /* + * Move from the first of the item on the list, For each iteration, + * compare and swap the least value to the head of the comparisoning + * sub-list. + */ + for (i = 0; i < size - 1; i++) { + + PKIX_CHECK(PKIX_List_GetItem + (sortedList, i, &leastObj, plContext), + PKIX_LISTGETITEMFAILED); + + for (j = i + 1; j < size; j++) { + PKIX_CHECK(PKIX_List_GetItem + (sortedList, j, &cmpObj, plContext), + PKIX_LISTGETITEMFAILED); + PKIX_CHECK(comparator + (leastObj, cmpObj, &cmpResult, plContext), + PKIX_COMPARATORCALLBACKFAILED); + if (cmpResult > 0) { + PKIX_CHECK(PKIX_List_SetItem + (sortedList, j, leastObj, plContext), + PKIX_LISTSETITEMFAILED); + + PKIX_DECREF(leastObj); + leastObj = cmpObj; + cmpObj = NULL; + } else { + PKIX_DECREF(cmpObj); + } + } + PKIX_CHECK(PKIX_List_SetItem + (sortedList, i, leastObj, plContext), + PKIX_LISTSETITEMFAILED); + + PKIX_DECREF(leastObj); + } + + } + + *pSortedList = sortedList; + sortedList = NULL; +cleanup: + + PKIX_DECREF(sortedList); + PKIX_DECREF(leastObj); + PKIX_DECREF(cmpObj); + + PKIX_RETURN(LIST); +} + +/* --Public-List-Functions--------------------------------------------- */ + +/* + * FUNCTION: PKIX_List_Create (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_Create( + PKIX_List **pList, + void *plContext) +{ + PKIX_List *list = NULL; + + PKIX_ENTER(LIST, "PKIX_List_Create"); + PKIX_NULLCHECK_ONE(pList); + + PKIX_CHECK(pkix_List_Create_Internal(PKIX_TRUE, &list, plContext), + PKIX_LISTCREATEINTERNALFAILED); + + *pList = list; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_SetImmutable (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_SetImmutable( + PKIX_List *list, + void *plContext) +{ + PKIX_ENTER(LIST, "PKIX_List_SetImmutable"); + PKIX_NULLCHECK_ONE(list); + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + list->immutable = PKIX_TRUE; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_IsImmutable (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_IsImmutable( + PKIX_List *list, + PKIX_Boolean *pImmutable, + void *plContext) +{ + PKIX_ENTER(LIST, "PKIX_List_IsImmutable"); + PKIX_NULLCHECK_TWO(list, pImmutable); + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + *pImmutable = list->immutable; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_GetLength (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_GetLength( + PKIX_List *list, + PKIX_UInt32 *pLength, + void *plContext) +{ + PKIX_ENTER(LIST, "PKIX_List_GetLength"); + PKIX_NULLCHECK_TWO(list, pLength); + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + *pLength = list->length; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_IsEmpty (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_IsEmpty( + PKIX_List *list, + PKIX_Boolean *pEmpty, + void *plContext) +{ + PKIX_UInt32 length; + + PKIX_ENTER(LIST, "PKIX_List_IsEmpty"); + PKIX_NULLCHECK_TWO(list, pEmpty); + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + length = list->length; + + if (length == 0){ + *pEmpty = PKIX_TRUE; + } else { + *pEmpty = PKIX_FALSE; + } + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_AppendItem (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_AppendItem( + PKIX_List *list, + PKIX_PL_Object *item, + void *plContext) +{ + PKIX_List *lastElement = NULL; + PKIX_List *newElement = NULL; + PKIX_UInt32 length, i; + + PKIX_ENTER(LIST, "PKIX_List_AppendItem"); + PKIX_NULLCHECK_ONE(list); + + if (list->immutable){ + PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST); + } + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + length = list->length; + + /* find last element of list and create new element there */ + + lastElement = list; + for (i = 0; i < length; i++){ + lastElement = lastElement->next; + } + + PKIX_CHECK(pkix_List_Create_Internal + (PKIX_FALSE, &newElement, plContext), + PKIX_LISTCREATEINTERNALFAILED); + + PKIX_INCREF(item); + newElement->item = item; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)list, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + lastElement->next = newElement; + newElement = NULL; + list->length += 1; + +cleanup: + + PKIX_DECREF(newElement); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_InsertItem (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_InsertItem( + PKIX_List *list, + PKIX_UInt32 index, + PKIX_PL_Object *item, + void *plContext) +{ + PKIX_List *element = NULL; + PKIX_List *newElem = NULL; + + PKIX_ENTER(LIST, "PKIX_List_InsertItem"); + PKIX_NULLCHECK_ONE(list); + + + if (list->immutable){ + PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST); + } + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + /* Create a new list object */ + PKIX_CHECK(pkix_List_Create_Internal(PKIX_FALSE, &newElem, plContext), + PKIX_LISTCREATEINTERNALFAILED); + + if (list->length) { + PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext), + PKIX_LISTGETELEMENTFAILED); + /* Copy the old element's contents into the new element */ + newElem->item = element->item; + /* Add new item to the list */ + PKIX_INCREF(item); + element->item = item; + /* Set the new element's next pointer to the old element's next */ + newElem->next = element->next; + /* Set the old element's next pointer to the new element */ + element->next = newElem; + newElem = NULL; + } else { + PKIX_INCREF(item); + newElem->item = item; + newElem->next = NULL; + list->next = newElem; + newElem = NULL; + } + list->length++; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)list, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); +cleanup: + PKIX_DECREF(newElem); + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_GetItem (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_GetItem( + PKIX_List *list, + PKIX_UInt32 index, + PKIX_PL_Object **pItem, + void *plContext) +{ + PKIX_List *element = NULL; + + PKIX_ENTER(LIST, "PKIX_List_GetItem"); + PKIX_NULLCHECK_TWO(list, pItem); + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext), + PKIX_LISTGETELEMENTFAILED); + + PKIX_INCREF(element->item); + *pItem = element->item; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_SetItem (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_SetItem( + PKIX_List *list, + PKIX_UInt32 index, + PKIX_PL_Object *item, + void *plContext) +{ + PKIX_List *element; + + PKIX_ENTER(LIST, "PKIX_List_SetItem"); + PKIX_NULLCHECK_ONE(list); + + if (list->immutable){ + PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST); + } + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext), + PKIX_LISTGETELEMENTFAILED); + + /* DecRef old contents */ + PKIX_DECREF(element->item); + + /* Set New Contents */ + PKIX_INCREF(item); + element->item = item; + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)list, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_DeleteItem (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_DeleteItem( + PKIX_List *list, + PKIX_UInt32 index, + void *plContext) +{ + PKIX_List *element = NULL; + PKIX_List *prevElement = NULL; + PKIX_List *nextElement = NULL; + + PKIX_ENTER(LIST, "PKIX_List_DeleteItem"); + PKIX_NULLCHECK_ONE(list); + + if (list->immutable){ + PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST); + } + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext), + PKIX_LISTGETELEMENTFAILED); + + /* DecRef old contents */ + PKIX_DECREF(element->item); + + nextElement = element->next; + + if (nextElement != NULL) { + /* If the next element exists, splice it out. */ + + /* Don't need to change ref counts for targets of next */ + element->item = nextElement->item; + nextElement->item = NULL; + + /* Don't need to change ref counts for targets of next */ + element->next = nextElement->next; + nextElement->next = NULL; + + PKIX_DECREF(nextElement); + + } else { /* The element is at the tail of the list */ + if (index != 0) { + PKIX_CHECK(pkix_List_GetElement + (list, index-1, &prevElement, plContext), + PKIX_LISTGETELEMENTFAILED); + } else if (index == 0){ /* prevElement must be header */ + prevElement = list; + } + prevElement->next = NULL; + + /* Delete the element */ + PKIX_DECREF(element); + } + + PKIX_CHECK(PKIX_PL_Object_InvalidateCache + ((PKIX_PL_Object *)list, plContext), + PKIX_OBJECTINVALIDATECACHEFAILED); + + list->length = list->length - 1; + +cleanup: + + PKIX_RETURN(LIST); +} + +/* + * FUNCTION: PKIX_List_ReverseList (see comments in pkix_util.h) + */ +PKIX_Error * +PKIX_List_ReverseList( + PKIX_List *list, + PKIX_List **pReversedList, + void *plContext) +{ + PKIX_List *reversedList = NULL; + PKIX_PL_Object *item = NULL; + PKIX_PL_Object *duplicateItem = NULL; + PKIX_UInt32 length, i; + + PKIX_ENTER(LIST, "pkix_List_ReverseList"); + PKIX_NULLCHECK_TWO(list, pReversedList); + + if (!list->isHeader){ + PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER); + } + + length = list->length; + + /* Create a new list object */ + PKIX_CHECK(PKIX_List_Create(&reversedList, plContext), + PKIX_LISTCREATEINTERNALFAILED); + + /* + * Starting with the last item and traversing backwards (from + * the original list), append each item to the reversed list + */ + + for (i = 1; i <= length; i++){ + PKIX_CHECK(PKIX_List_GetItem + (list, (length - i), &item, plContext), + PKIX_LISTGETITEMFAILED); + + PKIX_CHECK(PKIX_PL_Object_Duplicate + (item, &duplicateItem, plContext), + PKIX_LISTDUPLICATEFAILED); + + PKIX_CHECK(PKIX_List_AppendItem + (reversedList, duplicateItem, plContext), + PKIX_LISTAPPENDITEMFAILED); + + PKIX_DECREF(item); + PKIX_DECREF(duplicateItem); + } + + *pReversedList = reversedList; + +cleanup: + + PKIX_DECREF(item); + PKIX_DECREF(duplicateItem); + + if (PKIX_ERROR_RECEIVED){ + PKIX_DECREF(reversedList); + } + + PKIX_RETURN(LIST); +}