summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/libpkix/pkix/util/pkix_list.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/libpkix/pkix/util/pkix_list.c')
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/util/pkix_list.c1701
1 files changed, 1701 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix/util/pkix_list.c b/security/nss/lib/libpkix/pkix/util/pkix_list.c
new file mode 100755
index 000000000..d02b66e6d
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/util/pkix_list.c
@@ -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, &current, 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, &current, 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, &current, 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);
+}