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