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