tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkix_list.c (50944B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * pkix_list.c
      6 *
      7 * List Object Functions
      8 *
      9 */
     10 
     11 #include "pkix_list.h"
     12 
     13 /* --Private-Functions-------------------------------------------- */
     14 
     15 /*
     16 * FUNCTION: pkix_List_Create_Internal
     17 * DESCRIPTION:
     18 *
     19 *  Creates a new List, using the Boolean value of "isHeader" to determine
     20 *  whether the new List should be a header, and stores it at "pList". The
     21 *  List is initially empty and holds no items. To initially add items to
     22 *  the List, use PKIX_List_AppendItem.
     23 *
     24 * PARAMETERS:
     25 *  "isHeader"
     26 *      Boolean value indicating whether new List should be a header.
     27 *  "pList"
     28 *      Address where object pointer will be stored. Must be non-NULL.
     29 *  "plContext"
     30 *      Platform-specific context pointer.
     31 * THREAD SAFETY:
     32 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
     33 * RETURNS:
     34 *  Returns NULL if the function succeeds.
     35 *  Returns a Fatal Error if the function fails in an unrecoverable way.
     36 */
     37 static PKIX_Error *
     38 pkix_List_Create_Internal(
     39        PKIX_Boolean isHeader,
     40        PKIX_List **pList,
     41        void *plContext)
     42 {
     43        PKIX_List *list = NULL;
     44 
     45        PKIX_ENTER(LIST, "pkix_List_Create_Internal");
     46        PKIX_NULLCHECK_ONE(pList);
     47 
     48        PKIX_CHECK(PKIX_PL_Object_Alloc
     49                    (PKIX_LIST_TYPE,
     50                    ((PKIX_UInt32)(sizeof (PKIX_List))),
     51                    (PKIX_PL_Object **)&list, plContext),
     52                    PKIX_ERRORCREATINGLISTITEM);
     53 
     54        list->item = NULL;
     55        list->next = NULL;
     56        list->immutable = PKIX_FALSE;
     57        list->length = 0;
     58        list->isHeader = isHeader;
     59 
     60        *pList = list;
     61 
     62 cleanup:
     63 
     64        PKIX_RETURN(LIST);
     65 }
     66 
     67 /*
     68 * FUNCTION: pkix_List_Destroy
     69 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
     70 */
     71 static PKIX_Error *
     72 pkix_List_Destroy(
     73        PKIX_PL_Object *object,
     74        void *plContext)
     75 {
     76        PKIX_List *list = NULL;
     77        PKIX_List *nextItem = NULL;
     78 
     79        PKIX_ENTER(LIST, "pkix_List_Destroy");
     80        PKIX_NULLCHECK_ONE(object);
     81 
     82        /* Check that this object is a list */
     83        PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
     84                    PKIX_OBJECTNOTLIST);
     85 
     86        list = (PKIX_List *)object;
     87 
     88        /* We have a valid list. DecRef its item and recurse on next */
     89        PKIX_DECREF(list->item);
     90        while ((nextItem = list->next) != NULL) {
     91            list->next = nextItem->next;
     92            nextItem->next = NULL;
     93            PKIX_DECREF(nextItem);
     94        }      
     95        list->immutable = PKIX_FALSE;
     96        list->length = 0;
     97        list->isHeader = PKIX_FALSE;
     98 
     99 cleanup:
    100 
    101        PKIX_RETURN(LIST);
    102 }
    103 
    104 /*
    105 * FUNCTION: pkix_List_ToString_Helper
    106 * DESCRIPTION:
    107 *
    108 *  Helper function that creates a string representation of the List pointed
    109 *  to by "list" and stores its address in the object pointed to by "pString".
    110 *
    111 * PARAMETERS
    112 *  "list"
    113 *      Address of List whose string representation is desired.
    114 *      Must be non-NULL.
    115 *  "pString"
    116 *      Address of object pointer's destination. Must be non-NULL.
    117 *  "plContext"
    118 *      Platform-specific context pointer.
    119 * THREAD SAFETY:
    120 *  Conditionally Thread Safe
    121 *      (see Thread Safety Definitions in Programmer's Guide)
    122 * RETURNS:
    123 *  Returns NULL if the function succeeds.
    124 *  Returns a List Error if the function fails in a non-fatal way.
    125 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    126 */
    127 static PKIX_Error *
    128 pkix_List_ToString_Helper(
    129        PKIX_List *list,
    130        PKIX_PL_String **pString,
    131        void *plContext)
    132 {
    133        PKIX_PL_String *itemString = NULL;
    134        PKIX_PL_String *nextString = NULL;
    135        PKIX_PL_String *format = NULL;
    136        PKIX_Boolean empty;
    137 
    138        PKIX_ENTER(LIST, "pkix_List_ToString_Helper");
    139        PKIX_NULLCHECK_TWO(list, pString);
    140 
    141        /* special case when list is the header */
    142        if (list->isHeader){
    143 
    144                PKIX_CHECK(PKIX_List_IsEmpty(list, &empty, plContext),
    145                            PKIX_LISTISEMPTYFAILED);
    146 
    147                if (empty){
    148                        PKIX_CHECK(PKIX_PL_String_Create
    149                                    (PKIX_ESCASCII,
    150                                    "EMPTY",
    151                                    0,
    152                                    &itemString,
    153                                    plContext),
    154                                    PKIX_ERRORCREATINGITEMSTRING);
    155                        (*pString) = itemString;
    156                        PKIX_DEBUG_EXIT(LIST);
    157                        return (NULL);
    158                } else {
    159                        PKIX_CHECK(pkix_List_ToString_Helper
    160                                    (list->next, &itemString, plContext),
    161                                    PKIX_LISTTOSTRINGHELPERFAILED);
    162                }
    163 
    164                /* Create a string object from the format */
    165                PKIX_CHECK(PKIX_PL_String_Create
    166                            (PKIX_ESCASCII, "%s", 0, &format, plContext),
    167                            PKIX_STRINGCREATEFAILED);
    168 
    169                PKIX_CHECK(PKIX_PL_Sprintf
    170                            (pString, plContext, format, itemString),
    171                            PKIX_SPRINTFFAILED);
    172        } else {
    173                /* Get a string for this list's item */
    174                if (list->item == NULL) {
    175                        PKIX_CHECK(PKIX_PL_String_Create
    176                                    (PKIX_ESCASCII,
    177                                    "(null)",
    178                                    0,
    179                                    &itemString,
    180                                    plContext),
    181                                    PKIX_STRINGCREATEFAILED);
    182                } else {
    183                        PKIX_CHECK(PKIX_PL_Object_ToString
    184                                    ((PKIX_PL_Object*)list->item,
    185                                    &itemString,
    186                                    plContext),
    187                                    PKIX_OBJECTTOSTRINGFAILED);
    188                }
    189                if (list->next == NULL) {
    190                        /* Just return the itemstring */
    191                        (*pString) = itemString;
    192                        PKIX_DEBUG_EXIT(LIST);
    193                        return (NULL);
    194                }
    195 
    196                /* Recursive call to get string for this list's next pointer */
    197                PKIX_CHECK(pkix_List_ToString_Helper
    198                            (list->next, &nextString, plContext),
    199                            PKIX_LISTTOSTRINGHELPERFAILED);
    200 
    201                /* Create a string object from the format */
    202                PKIX_CHECK(PKIX_PL_String_Create
    203                            (PKIX_ESCASCII,
    204                            "%s, %s",
    205                            0,
    206                            &format,
    207                            plContext),
    208                            PKIX_STRINGCREATEFAILED);
    209 
    210                PKIX_CHECK(PKIX_PL_Sprintf
    211                            (pString,
    212                            plContext,
    213                            format,
    214                            itemString,
    215                            nextString),
    216                            PKIX_SPRINTFFAILED);
    217        }
    218 
    219 cleanup:
    220 
    221        PKIX_DECREF(itemString);
    222        PKIX_DECREF(nextString);
    223        PKIX_DECREF(format);
    224 
    225        PKIX_RETURN(LIST);
    226 }
    227 
    228 /*
    229 * FUNCTION: pkix_List_ToString
    230 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
    231 */
    232 static PKIX_Error *
    233 pkix_List_ToString(
    234        PKIX_PL_Object *object,
    235        PKIX_PL_String **pString,
    236        void *plContext)
    237 {
    238        PKIX_List *list = NULL;
    239        PKIX_PL_String *listString = NULL;
    240        PKIX_PL_String *format = NULL;
    241 
    242        PKIX_ENTER(LIST, "pkix_List_ToString");
    243        PKIX_NULLCHECK_TWO(object, pString);
    244 
    245        PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
    246                    PKIX_OBJECTNOTLIST);
    247 
    248        list = (PKIX_List *)object;
    249 
    250        if (!list->isHeader){
    251                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
    252        }
    253 
    254        PKIX_CHECK(pkix_List_ToString_Helper(list, &listString, plContext),
    255                    PKIX_LISTTOSTRINGHELPERFAILED);
    256 
    257        PKIX_CHECK(PKIX_PL_String_Create
    258                    (PKIX_ESCASCII, "(%s)", 0, &format, plContext),
    259                    PKIX_STRINGCREATEFAILED);
    260 
    261        PKIX_CHECK(PKIX_PL_Sprintf(pString, plContext, format, listString),
    262                    PKIX_SPRINTFFAILED);
    263 
    264 cleanup:
    265 
    266        PKIX_DECREF(listString);
    267        PKIX_DECREF(format);
    268 
    269        PKIX_RETURN(LIST);
    270 }
    271 
    272 /*
    273 * FUNCTION: pkix_List_Equals
    274 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
    275 */
    276 static PKIX_Error *
    277 pkix_List_Equals(
    278        PKIX_PL_Object *first,
    279        PKIX_PL_Object *second,
    280        PKIX_Boolean *pResult,
    281        void *plContext)
    282 {
    283        PKIX_UInt32 secondType;
    284        PKIX_Boolean cmpResult;
    285        PKIX_List *firstList = NULL;
    286        PKIX_List *secondList = NULL;
    287        PKIX_UInt32 firstLength = 0;
    288        PKIX_UInt32 secondLength = 0;
    289        PKIX_PL_Object *firstItem = NULL;
    290        PKIX_PL_Object *secondItem = NULL;
    291        PKIX_UInt32 i = 0;
    292 
    293        PKIX_ENTER(LIST, "pkix_List_Equals");
    294        PKIX_NULLCHECK_THREE(first, second, pResult);
    295 
    296        /* test that first is a List */
    297        PKIX_CHECK(pkix_CheckType(first, PKIX_LIST_TYPE, plContext),
    298                PKIX_FIRSTOBJECTNOTLIST);
    299 
    300        /*
    301         * Since we know first is a List, if both references are
    302         * identical, they must be equal
    303         */
    304        if (first == second){
    305                *pResult = PKIX_TRUE;
    306                goto cleanup;
    307        }
    308 
    309        /*
    310         * If second isn't a List, we don't throw an error.
    311         * We simply return a Boolean result of FALSE
    312         */
    313        *pResult = PKIX_FALSE;
    314        PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
    315                    PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
    316        if (secondType != PKIX_LIST_TYPE) goto cleanup;
    317 
    318        firstList = (PKIX_List *)first;
    319        secondList = (PKIX_List *)second;
    320 
    321        if ((!firstList->isHeader) && (!secondList->isHeader)){
    322                PKIX_ERROR(PKIX_INPUTLISTSMUSTBELISTHEADERS);
    323        }
    324 
    325        firstLength = firstList->length;
    326        secondLength = secondList->length;
    327 
    328        cmpResult = PKIX_FALSE;
    329        if (firstLength == secondLength){
    330                for (i = 0, cmpResult = PKIX_TRUE;
    331                    ((i < firstLength) && cmpResult);
    332                    i++){
    333                        PKIX_CHECK(PKIX_List_GetItem
    334                                    (firstList, i, &firstItem, plContext),
    335                                    PKIX_LISTGETITEMFAILED);
    336 
    337                        PKIX_CHECK(PKIX_List_GetItem
    338                                    (secondList, i, &secondItem, plContext),
    339                                    PKIX_LISTGETITEMFAILED);
    340 
    341                        if ((!firstItem && secondItem) ||
    342                            (firstItem && !secondItem)){
    343                                        cmpResult = PKIX_FALSE;
    344                        } else if (!firstItem && !secondItem){
    345                                continue;
    346                        } else {
    347                                PKIX_CHECK(PKIX_PL_Object_Equals
    348                                            (firstItem,
    349                                            secondItem,
    350                                            &cmpResult,
    351                                            plContext),
    352                                            PKIX_OBJECTEQUALSFAILED);
    353 
    354                                PKIX_DECREF(firstItem);
    355                                PKIX_DECREF(secondItem);
    356                        }
    357                }
    358        }
    359 
    360        *pResult = cmpResult;
    361 
    362 cleanup:
    363 
    364        PKIX_DECREF(firstItem);
    365        PKIX_DECREF(secondItem);
    366 
    367        PKIX_RETURN(LIST);
    368 }
    369 
    370 /*
    371 * FUNCTION: pkix_List_Hashcode
    372 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
    373 */
    374 static PKIX_Error *
    375 pkix_List_Hashcode(
    376        PKIX_PL_Object *object,
    377        PKIX_UInt32 *pHashcode,
    378        void *plContext)
    379 {
    380        PKIX_List *list = NULL;
    381        PKIX_PL_Object *element = NULL;
    382        PKIX_UInt32 hash = 0;
    383        PKIX_UInt32 tempHash = 0;
    384        PKIX_UInt32 length, i;
    385 
    386        PKIX_ENTER(LIST, "pkix_List_Hashcode");
    387        PKIX_NULLCHECK_TWO(object, pHashcode);
    388 
    389        PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
    390                    PKIX_OBJECTNOTLIST);
    391 
    392        list = (PKIX_List *)object;
    393 
    394        if (!list->isHeader){
    395                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
    396        }
    397 
    398        length = list->length;
    399 
    400        for (i = 0; i < length; i++){
    401                PKIX_CHECK(PKIX_List_GetItem(list, i, &element, plContext),
    402                            PKIX_LISTGETITEMFAILED);
    403 
    404                if (!element){
    405                        tempHash = 100;
    406                } else {
    407                        PKIX_CHECK(PKIX_PL_Object_Hashcode
    408                                    (element, &tempHash, plContext),
    409                                    PKIX_LISTHASHCODEFAILED);
    410                }
    411 
    412                hash = 31 * hash + tempHash;
    413 
    414                PKIX_DECREF(element);
    415        }
    416 
    417        *pHashcode = hash;
    418 
    419 cleanup:
    420 
    421        PKIX_DECREF(element);
    422        PKIX_RETURN(LIST);
    423 }
    424 
    425 /*
    426 * FUNCTION: pkix_List_Duplicate
    427 * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h)
    428 */
    429 static PKIX_Error *
    430 pkix_List_Duplicate(
    431        PKIX_PL_Object *object,
    432        PKIX_PL_Object **pNewObject,
    433        void *plContext)
    434 {
    435        PKIX_List *list = NULL;
    436        PKIX_List *listDuplicate = NULL;
    437 
    438        PKIX_ENTER(LIST, "pkix_List_Duplicate");
    439        PKIX_NULLCHECK_TWO(object, pNewObject);
    440 
    441        PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
    442                    PKIX_OBJECTNOTLIST);
    443 
    444        list = (PKIX_List *)object;
    445 
    446        if (list->immutable){
    447                PKIX_CHECK(pkix_duplicateImmutable
    448                            (object, pNewObject, plContext),
    449                            PKIX_DUPLICATEIMMUTABLEFAILED);
    450        } else {
    451 
    452                PKIX_CHECK(pkix_List_Create_Internal
    453                            (list->isHeader, &listDuplicate, plContext),
    454                            PKIX_LISTCREATEINTERNALFAILED);
    455 
    456                listDuplicate->length = list->length;
    457 
    458                PKIX_INCREF(list->item);
    459                listDuplicate->item = list->item;
    460 
    461                if (list->next == NULL){
    462                        listDuplicate->next = NULL;
    463                } else {
    464                        /* Recursively Duplicate list */
    465                        PKIX_CHECK(pkix_List_Duplicate
    466                                    ((PKIX_PL_Object *)list->next,
    467                                    (PKIX_PL_Object **)&listDuplicate->next,
    468                                    plContext),
    469                                    PKIX_LISTDUPLICATEFAILED);
    470                }
    471 
    472                *pNewObject = (PKIX_PL_Object *)listDuplicate;
    473        }
    474 
    475 cleanup:
    476 
    477        if (PKIX_ERROR_RECEIVED){
    478                PKIX_DECREF(listDuplicate);
    479        }
    480 
    481        PKIX_RETURN(LIST);
    482 }
    483 
    484 
    485 /*
    486 * FUNCTION: pkix_List_GetElement
    487 * DESCRIPTION:
    488 *
    489 *  Copies the "list"'s element at "index" into "element". The input List must
    490 *  be the header of the List (as opposed to being an element of the List). The
    491 *  index counts from zero and must be less than the List's length. This
    492 *  function does NOT increment the reference count of the List element since
    493 *  the returned element's reference will not be stored by the calling
    494 *  function.
    495 *
    496 * PARAMETERS:
    497 *  "list"
    498 *      Address of List (must be header) to get element from. Must be non-NULL.
    499 *  "index"
    500 *      Index of list to get element from. Must be less than List's length.
    501 *  "pElement"
    502 *      Address where object pointer will be stored. Must be non-NULL.
    503 *  "plContext"
    504 *      Platform-specific context pointer.
    505 * THREAD SAFETY:
    506 *  Conditionally Thread Safe
    507 *      (see Thread Safety Definitions in Programmer's Guide)
    508 * RETURNS:
    509 *  Returns NULL if the function succeeds.
    510 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    511 */
    512 static PKIX_Error *
    513 pkix_List_GetElement(
    514        PKIX_List *list,
    515        PKIX_UInt32 index,
    516        PKIX_List **pElement,
    517        void *plContext)
    518 {
    519        PKIX_List *iterator = NULL;
    520        PKIX_UInt32 length;
    521        PKIX_UInt32 position = 0;
    522 
    523        PKIX_ENTER(LIST, "pkix_List_GetElement");
    524        PKIX_NULLCHECK_TWO(list, pElement);
    525 
    526        if (!list->isHeader){
    527                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
    528        }
    529 
    530        length = list->length;
    531 
    532        if (index >= length) {
    533                PKIX_ERROR(PKIX_INDEXOUTOFBOUNDS);
    534        }
    535 
    536        for (iterator = list; position++ <= index; iterator = iterator->next)
    537                ;
    538 
    539        (*pElement) = iterator;
    540 
    541 cleanup:
    542 
    543        PKIX_RETURN(LIST);
    544 }
    545 
    546 
    547 /*
    548 * FUNCTION: pkix_List_RegisterSelf
    549 * DESCRIPTION:
    550 *  Registers PKIX_LIST_TYPE and its related functions with systemClasses[]
    551 * THREAD SAFETY:
    552 *  Not Thread Safe - for performance and complexity reasons
    553 *
    554 *  Since this function is only called by PKIX_PL_Initialize, which should
    555 *  only be called once, it is acceptable that this function is not
    556 *  thread-safe.
    557 */
    558 PKIX_Error *
    559 pkix_List_RegisterSelf(void *plContext)
    560 {
    561        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
    562        pkix_ClassTable_Entry entry;
    563 
    564        PKIX_ENTER(LIST, "pkix_List_RegisterSelf");
    565 
    566        entry.description = "List";
    567        entry.objCounter = 0;
    568        entry.typeObjectSize = sizeof(PKIX_List);
    569        entry.destructor = pkix_List_Destroy;
    570        entry.equalsFunction = pkix_List_Equals;
    571        entry.hashcodeFunction = pkix_List_Hashcode;
    572        entry.toStringFunction = pkix_List_ToString;
    573        entry.comparator = NULL;
    574        entry.duplicateFunction = pkix_List_Duplicate;
    575 
    576        systemClasses[PKIX_LIST_TYPE] = entry;
    577 
    578        PKIX_RETURN(LIST);
    579 }
    580 
    581 /*
    582 * FUNCTION: pkix_List_Contains
    583 * DESCRIPTION:
    584 *
    585 *  Checks a List pointed to by "list", to determine whether it includes
    586 *  an entry that is equal to the Object pointed to by "object", and stores
    587 *  the result in "pFound".
    588 *
    589 * PARAMETERS:
    590 *  "list"
    591 *      List to be searched; may be empty; must be non-NULL
    592 *  "object"
    593 *      Object to be checked for; must be non-NULL
    594 *  "pFound"
    595 *      Address where the result of the search will be stored. Must
    596 *      be non-NULL
    597 *  "plContext"
    598 *      platform-specific context pointer
    599 * THREAD SAFETY:
    600 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    601 * RETURNS:
    602 *  Returns NULL if the function succeeds
    603 *  Returns a Fatal Error if the function fails in an unrecoverable way
    604 */
    605 PKIX_Error *
    606 pkix_List_Contains(
    607        PKIX_List *list,
    608        PKIX_PL_Object *object,
    609        PKIX_Boolean *pFound,
    610        void *plContext)
    611 {
    612        PKIX_PL_Object *current = NULL;
    613        PKIX_UInt32 numEntries = 0;
    614        PKIX_UInt32 index = 0;
    615        PKIX_Boolean match = PKIX_FALSE;
    616 
    617        PKIX_ENTER(LIST, "pkix_List_Contains");
    618        PKIX_NULLCHECK_THREE(list, object, pFound);
    619 
    620        PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext),
    621                PKIX_LISTGETLENGTHFAILED);
    622 
    623        for (index = 0; index < numEntries; index++) {
    624                PKIX_CHECK(PKIX_List_GetItem
    625                        (list, index, &current, plContext),
    626                        PKIX_LISTGETITEMFAILED);
    627 
    628                if (current) {
    629                        PKIX_CHECK(PKIX_PL_Object_Equals
    630                                (object, current, &match, plContext),
    631                                PKIX_OBJECTEQUALSFAILED);
    632 
    633                        PKIX_DECREF(current);
    634                }
    635 
    636                if (match) {
    637                        break;
    638                }
    639        }
    640 
    641        *pFound = match;
    642 
    643 cleanup:
    644 
    645        PKIX_DECREF(current);
    646        PKIX_RETURN(LIST);
    647 }
    648 
    649 /*
    650 * FUNCTION: pkix_List_Remove
    651 * DESCRIPTION:
    652 *
    653 *  Traverses the List pointed to by "list", to find and delete an entry
    654 *  that is equal to the Object pointed to by "object". If no such entry
    655 *  is found the function does not return an error.
    656 *
    657 * PARAMETERS:
    658 *  "list"
    659 *      List to be searched; may be empty; must be non-NULL
    660 *  "object"
    661 *      Object to be checked for and deleted, if found; must be non-NULL
    662 *  "plContext"
    663 *      platform-specific context pointer
    664 * THREAD SAFETY:
    665 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    666 * RETURNS:
    667 *  Returns NULL if the function succeeds
    668 *  Returns a Validate Error if the functions fails in a non-fatal way
    669 *  Returns a Fatal Error if the function fails in an unrecoverable way
    670 */
    671 PKIX_Error *
    672 pkix_List_Remove(
    673        PKIX_List *list,
    674        PKIX_PL_Object *object,
    675        void *plContext)
    676 {
    677        PKIX_PL_Object *current = NULL;
    678        PKIX_UInt32 numEntries = 0;
    679        PKIX_UInt32 index = 0;
    680        PKIX_Boolean match = PKIX_FALSE;
    681 
    682        PKIX_ENTER(LIST, "pkix_List_Remove");
    683        PKIX_NULLCHECK_TWO(list, object);
    684 
    685        PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext),
    686                PKIX_LISTGETLENGTHFAILED);
    687 
    688        for (index = 0; index < numEntries; index++) {
    689                PKIX_CHECK(PKIX_List_GetItem
    690                        (list, index, &current, plContext),
    691                        PKIX_LISTGETITEMFAILED);
    692 
    693                if (current) {
    694                        PKIX_CHECK(PKIX_PL_Object_Equals
    695                                (object, current, &match, plContext),
    696                                PKIX_OBJECTEQUALSFAILED);
    697 
    698                        PKIX_DECREF(current);
    699                }
    700 
    701                if (match) {
    702                        PKIX_CHECK(PKIX_List_DeleteItem
    703                                (list, index, plContext),
    704                                PKIX_LISTDELETEITEMFAILED);
    705                        break;
    706                }
    707        }
    708 
    709 cleanup:
    710 
    711        PKIX_DECREF(current);
    712        PKIX_RETURN(LIST);
    713 }
    714 
    715 /*
    716 * FUNCTION: pkix_List_RemoveItems
    717 * DESCRIPTION:
    718 *
    719 *  Traverses the List pointed to by "list", to find and delete an entry
    720 *  that is equal to the Object in the "deleteList". If no such entry
    721 *  is found the function does not return an error.
    722 *
    723 * PARAMETERS:
    724 *  "list"
    725 *      Object in "list" is checked for object in "deleteList" and deleted if
    726 *      found; may be empty; must be non-NULL
    727 *  "deleteList"
    728 *      List of objects to be searched ; may be empty; must be non-NULL
    729 *  "plContext"
    730 *      platform-specific context pointer
    731 * THREAD SAFETY:
    732 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    733 * RETURNS:
    734 *  Returns NULL if the function succeeds
    735 *  Returns a Validate Error if the functions fails in a non-fatal way
    736 *  Returns a Fatal Error if the function fails in an unrecoverable way
    737 */
    738 PKIX_Error *
    739 pkix_List_RemoveItems(
    740        PKIX_List *list,
    741        PKIX_List *deleteList,
    742        void *plContext)
    743 {
    744        PKIX_PL_Object *current = NULL;
    745        PKIX_UInt32 numEntries = 0;
    746        PKIX_UInt32 index = 0;
    747 
    748        PKIX_ENTER(LIST, "pkix_List_RemoveItems");
    749        PKIX_NULLCHECK_TWO(list, deleteList);
    750 
    751        PKIX_CHECK(PKIX_List_GetLength(deleteList, &numEntries, plContext),
    752                PKIX_LISTGETLENGTHFAILED);
    753 
    754        for (index = 0; index < numEntries; index++) {
    755                PKIX_CHECK(PKIX_List_GetItem
    756                        (deleteList, index, &current, plContext),
    757                        PKIX_LISTGETITEMFAILED);
    758 
    759                if (current) {
    760                        PKIX_CHECK(pkix_List_Remove
    761                                (list, current, plContext),
    762                                PKIX_OBJECTEQUALSFAILED);
    763 
    764                        PKIX_DECREF(current);
    765                }
    766        }
    767 
    768 cleanup:
    769 
    770        PKIX_DECREF(current);
    771        PKIX_RETURN(LIST);
    772 }
    773 
    774 /*
    775 * FUNCTION: pkix_List_MergeLists
    776 * DESCRIPTION:
    777 *
    778 *  Creates a new list consisting of the items from "firstList", followed by
    779 *  the items on "secondList", returns the new list at "pMergedList". If
    780 *  both input lists are NULL or empty, the result is an empty list. If an error
    781 *  occurs, the result is NULL.
    782 *
    783 * PARAMETERS:
    784 *  "firstList"
    785 *      Address of list to be merged from. May be NULL or empty.
    786 *  "secondList"
    787 *      Address of list to be merged from. May be NULL or empty.
    788 *  "pMergedList"
    789 *      Address where returned object is stored.
    790 *  "plContext"
    791 *      platform-specific context pointer * THREAD SAFETY:
    792 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    793 * RETURNS:
    794 *  Returns NULL if the function succeeds
    795 *  Returns a List Error if the functions fails in a non-fatal way
    796 *  Returns a Fatal Error if the function fails in an unrecoverable way
    797 */
    798 PKIX_Error *
    799 pkix_List_MergeLists(
    800        PKIX_List *firstList,
    801        PKIX_List *secondList,
    802        PKIX_List **pMergedList,
    803        void *plContext)
    804 {
    805        PKIX_List *list = NULL;
    806        PKIX_PL_Object *item = NULL;
    807        PKIX_UInt32 numItems = 0;
    808        PKIX_UInt32 i;
    809 
    810        PKIX_ENTER(LIST, "pkix_List_MergeLists");
    811        PKIX_NULLCHECK_ONE(pMergedList);
    812 
    813        *pMergedList = NULL;
    814 
    815        PKIX_CHECK(PKIX_List_Create(&list, plContext),
    816                    PKIX_LISTCREATEFAILED);
    817 
    818        if (firstList != NULL) {
    819 
    820                PKIX_CHECK(PKIX_List_GetLength(firstList, &numItems, plContext),
    821                    PKIX_LISTGETLENGTHFAILED);
    822        }
    823 
    824        for (i = 0; i < numItems; i++) {
    825 
    826                PKIX_CHECK(PKIX_List_GetItem(firstList, i, &item, plContext),
    827                        PKIX_LISTGETITEMFAILED);
    828 
    829                PKIX_CHECK(PKIX_List_AppendItem(list, item, plContext),
    830                        PKIX_LISTAPPENDITEMFAILED);
    831 
    832                PKIX_DECREF(item);
    833        }
    834 
    835        numItems = 0;
    836        if (secondList != NULL) {
    837 
    838                PKIX_CHECK(PKIX_List_GetLength
    839                        (secondList,
    840                        &numItems,
    841                        plContext),
    842                        PKIX_LISTGETLENGTHFAILED);
    843 
    844        }
    845 
    846        for (i = 0; i < numItems; i++) {
    847 
    848                PKIX_CHECK(PKIX_List_GetItem
    849                        (secondList, i, &item, plContext),
    850                        PKIX_LISTGETITEMFAILED);
    851 
    852                PKIX_CHECK(PKIX_List_AppendItem
    853                        (list, item, plContext), PKIX_LISTAPPENDITEMFAILED);
    854 
    855                PKIX_DECREF(item);
    856        }
    857 
    858        *pMergedList = list;
    859        list = NULL;
    860 
    861 cleanup:
    862        PKIX_DECREF(list);
    863        PKIX_DECREF(item);
    864 
    865        PKIX_RETURN(LIST);
    866 }
    867 
    868 /*
    869 * FUNCTION: pkix_List_AppendList
    870 * DESCRIPTION:
    871 *
    872 *  Append items on "fromList" to the "toList". Item reference count on
    873 *  "toList" is not incremented, but items appended from "fromList" are
    874 *  incremented.
    875 *
    876 * PARAMETERS:
    877 *  "toList"
    878 *      Address of list to be appended to. Must be non-NULL.
    879 *  "fromList"
    880 *      Address of list to be appended from. May be NULL or empty.
    881 *  "plContext"
    882 *      platform-specific context pointer
    883 * THREAD SAFETY:
    884 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    885 * RETURNS:
    886 *  Returns NULL if the function succeeds
    887 *  Returns a List Error if the functions fails in a non-fatal way
    888 *  Returns a Fatal Error if the function fails in an unrecoverable way
    889 */
    890 PKIX_Error *
    891 pkix_List_AppendList(
    892        PKIX_List *toList,
    893        PKIX_List *fromList,
    894        void *plContext)
    895 {
    896        PKIX_PL_Object *item = NULL;
    897        PKIX_UInt32 numItems = 0;
    898        PKIX_UInt32 i;
    899 
    900        PKIX_ENTER(LIST, "pkix_List_AppendList");
    901        PKIX_NULLCHECK_ONE(toList);
    902 
    903        /* if fromList is NULL or is an empty list, no action */
    904 
    905        if (fromList == NULL) {
    906                goto cleanup;
    907        }
    908 
    909        PKIX_CHECK(PKIX_List_GetLength(fromList, &numItems, plContext),
    910                    PKIX_LISTGETLENGTHFAILED);
    911 
    912        if (numItems == 0) {
    913                goto cleanup;
    914        }
    915 
    916        for (i = 0; i < numItems; i++) {
    917 
    918                PKIX_CHECK(PKIX_List_GetItem
    919                        (fromList, i, &item, plContext),
    920                        PKIX_LISTGETITEMFAILED);
    921 
    922                PKIX_CHECK(PKIX_List_AppendItem(toList, item, plContext),
    923                            PKIX_LISTAPPENDITEMFAILED);
    924 
    925                PKIX_DECREF(item);
    926        }
    927 
    928 cleanup:
    929 
    930        PKIX_DECREF(item);
    931 
    932        PKIX_RETURN(LIST);
    933 }
    934 
    935 /*
    936 * FUNCTION: pkix_List_AppendUnique
    937 * DESCRIPTION:
    938 *
    939 *  Adds each Object in the List pointed to by "fromList" to the List pointed
    940 *  to by "toList", if it is not already a member of that List. In other words,
    941 *  "toList" becomes the union of the two sets.
    942 *
    943 * PARAMETERS:
    944 *  "toList"
    945 *      Address of a List of Objects to be augmented by "fromList". Must be
    946 *      non-NULL, but may be empty.
    947 *  "fromList"
    948 *      Address of a List of Objects to be added, if not already present, to
    949 *      "toList". Must be non-NULL, but may be empty.
    950 *  "plContext"
    951 *      Platform-specific context pointer.
    952 * THREAD SAFETY:
    953 *  Not Thread Safe - assumes exclusive access to "toList"
    954 *  (see Thread Safety Definitions in Programmer's Guide)
    955 * RETURNS:
    956 *  Returns NULL if the function succeeds
    957 *  Returns a Fatal Error if the function fails in an unrecoverable way
    958 */
    959 PKIX_Error *
    960 pkix_List_AppendUnique(
    961        PKIX_List *toList,
    962        PKIX_List *fromList,
    963        void *plContext)
    964 {
    965        PKIX_Boolean isContained = PKIX_FALSE;
    966        PKIX_UInt32 listLen = 0;
    967        PKIX_UInt32 listIx = 0;
    968        PKIX_PL_Object *object = NULL;
    969 
    970        PKIX_ENTER(BUILD, "pkix_List_AppendUnique");
    971        PKIX_NULLCHECK_TWO(fromList, toList);
    972 
    973        PKIX_CHECK(PKIX_List_GetLength(fromList, &listLen, plContext),
    974                PKIX_LISTGETLENGTHFAILED);
    975 
    976        for (listIx = 0; listIx < listLen; listIx++) {
    977 
    978                PKIX_CHECK(PKIX_List_GetItem
    979                        (fromList, listIx, &object, plContext),
    980                        PKIX_LISTGETITEMFAILED);
    981 
    982                PKIX_CHECK(pkix_List_Contains
    983                        (toList, object, &isContained, plContext),
    984                        PKIX_LISTCONTAINSFAILED);
    985 
    986                if (isContained == PKIX_FALSE) {
    987                        PKIX_CHECK(PKIX_List_AppendItem
    988                                (toList, object, plContext),
    989                                PKIX_LISTAPPENDITEMFAILED);
    990                }
    991 
    992                PKIX_DECREF(object);
    993        }
    994 
    995 cleanup:
    996 
    997        PKIX_DECREF(object);
    998 
    999        PKIX_RETURN(LIST);
   1000 }
   1001 
   1002 /*
   1003 * FUNCTION: pkix_List_QuickSort
   1004 * DESCRIPTION:
   1005 *
   1006 *  Sorts List of Objects "fromList" using "comparatorCallback"'s result as
   1007 *  comasrison key and returns the sorted List at "pSortedList". The sorting
   1008 *  algorithm used is quick sort (n*logn).
   1009 *
   1010 * PARAMETERS:
   1011 *  "fromList"
   1012 *      Address of a List of Objects to be sorted. Must be non-NULL, but may be
   1013 *      empty.
   1014 *  "comparatorCallback"
   1015 *      Address of callback function that will compare two Objects on the List.
   1016 *      It should return -1 for less, 0 for equal and 1 for greater. The
   1017 *      callback implementation chooses what in Objects to be compared. Must be
   1018 *      non-NULL.
   1019 *  "pSortedList"
   1020 *      Address of a List of Objects that shall be sorted and returned. Must be
   1021 *      non-NULL, but may be empty.
   1022 *  "plContext"
   1023 *      Platform-specific context pointer.
   1024 * THREAD SAFETY:
   1025 *  Not Thread Safe - assumes exclusive access to "toList"
   1026 *  (see Thread Safety Definitions in Programmer's Guide)
   1027 * RETURNS:
   1028 *  Returns NULL if the function succeeds
   1029 *  Returns a Fatal Error if the function fails in an unrecoverable way
   1030 */
   1031 PKIX_Error *
   1032 pkix_List_QuickSort(
   1033        PKIX_List *fromList,
   1034        PKIX_List_SortComparatorCallback comparator,
   1035        PKIX_List **pSortedList,
   1036        void *plContext)
   1037 {
   1038        PKIX_List *sortedList = NULL;
   1039        PKIX_List *lessList = NULL;
   1040        PKIX_List *greaterList = NULL;
   1041        PKIX_List *sortedLessList = NULL;
   1042        PKIX_List *sortedGreaterList = NULL;
   1043        PKIX_PL_Object *object = NULL;
   1044        PKIX_PL_Object *cmpObj = NULL;
   1045        PKIX_Int32 cmpResult = 0;
   1046        PKIX_UInt32 size = 0;
   1047        PKIX_UInt32 i;
   1048 
   1049        PKIX_ENTER(BUILD, "pkix_List_QuickSort");
   1050        PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);
   1051 
   1052        PKIX_CHECK(PKIX_List_GetLength(fromList, &size, plContext),
   1053                PKIX_LISTGETLENGTHFAILED);
   1054 
   1055        PKIX_CHECK(PKIX_List_Create(&lessList, plContext),
   1056                    PKIX_LISTCREATEFAILED);
   1057 
   1058        PKIX_CHECK(PKIX_List_Create(&greaterList, plContext),
   1059                    PKIX_LISTCREATEFAILED);
   1060 
   1061        PKIX_CHECK(PKIX_List_GetItem
   1062                (fromList, 0, &object, plContext),
   1063                PKIX_LISTGETITEMFAILED);
   1064 
   1065        /*
   1066         * Pick the first item on the list as the one to be compared.
   1067         * Separate rest of the itmes into two lists: less-than or greater-
   1068         * than lists. Sort those two lists recursively. Insert sorted
   1069         * less-than list before the picked item and append the greater-
   1070         * than list after the picked item.
   1071         */
   1072        for (i = 1; i < size; i++) {
   1073 
   1074                PKIX_CHECK(PKIX_List_GetItem
   1075                        (fromList, i, &cmpObj, plContext),
   1076                        PKIX_LISTGETITEMFAILED);
   1077 
   1078                PKIX_CHECK(comparator(object, cmpObj, &cmpResult, plContext),
   1079                        PKIX_COMPARATORCALLBACKFAILED);
   1080 
   1081                if (cmpResult >= 0) {
   1082                        PKIX_CHECK(PKIX_List_AppendItem
   1083                                (lessList, cmpObj, plContext),
   1084                                PKIX_LISTAPPENDITEMFAILED);
   1085                } else {
   1086                        PKIX_CHECK(PKIX_List_AppendItem
   1087                                (greaterList, cmpObj, plContext),
   1088                                PKIX_LISTAPPENDITEMFAILED);
   1089                }
   1090                PKIX_DECREF(cmpObj);
   1091        }
   1092 
   1093        PKIX_CHECK(PKIX_List_Create(&sortedList, plContext),
   1094                    PKIX_LISTCREATEFAILED);
   1095 
   1096        PKIX_CHECK(PKIX_List_GetLength(lessList, &size, plContext),
   1097                PKIX_LISTGETLENGTHFAILED);
   1098 
   1099        if (size > 1) {
   1100 
   1101                PKIX_CHECK(pkix_List_QuickSort
   1102                        (lessList, comparator, &sortedLessList, plContext),
   1103                        PKIX_LISTQUICKSORTFAILED);
   1104 
   1105                PKIX_CHECK(pkix_List_AppendList
   1106                        (sortedList, sortedLessList, plContext),
   1107                        PKIX_LISTAPPENDLISTFAILED);
   1108        } else {
   1109                PKIX_CHECK(pkix_List_AppendList
   1110                        (sortedList, lessList, plContext),
   1111                        PKIX_LISTAPPENDLISTFAILED);
   1112        }
   1113 
   1114        PKIX_CHECK(PKIX_List_AppendItem(sortedList, object, plContext),
   1115                PKIX_LISTAPPENDFAILED);
   1116 
   1117        PKIX_CHECK(PKIX_List_GetLength(greaterList, &size, plContext),
   1118                PKIX_LISTGETLENGTHFAILED);
   1119 
   1120        if (size > 1) {
   1121 
   1122                PKIX_CHECK(pkix_List_QuickSort
   1123                        (greaterList, comparator, &sortedGreaterList, plContext),
   1124                        PKIX_LISTQUICKSORTFAILED);
   1125 
   1126                PKIX_CHECK(pkix_List_AppendList
   1127                        (sortedList, sortedGreaterList, plContext),
   1128                        PKIX_LISTAPPENDLISTFAILED);
   1129        } else {
   1130                PKIX_CHECK(pkix_List_AppendList
   1131                        (sortedList, greaterList, plContext),
   1132                        PKIX_LISTAPPENDLISTFAILED);
   1133        }
   1134 
   1135        *pSortedList = sortedList;
   1136 
   1137 cleanup:
   1138 
   1139        PKIX_DECREF(cmpObj);
   1140        PKIX_DECREF(object);
   1141        PKIX_DECREF(sortedGreaterList);
   1142        PKIX_DECREF(sortedLessList);
   1143        PKIX_DECREF(greaterList);
   1144        PKIX_DECREF(lessList);
   1145 
   1146        PKIX_RETURN(LIST);
   1147 }
   1148 
   1149 /*
   1150 * FUNCTION: pkix_List_BubbleSort
   1151 * DESCRIPTION:
   1152 *
   1153 *  Sorts List of Objects "fromList" using "comparatorCallback"'s result as
   1154 *  comasrison key and returns the sorted List at "pSortedList". The sorting
   1155 *  algorithm used is bubble sort (n*n).
   1156 *
   1157 * PARAMETERS:
   1158 *  "fromList"
   1159 *      Address of a List of Objects to be sorted. Must be non-NULL, but may be
   1160 *      empty.
   1161 *  "comparatorCallback"
   1162 *      Address of callback function that will compare two Objects on the List.
   1163 *      It should return -1 for less, 0 for equal and 1 for greater. The
   1164 *      callback implementation chooses what in Objects to be compared. Must be
   1165 *      non-NULL.
   1166 *  "pSortedList"
   1167 *      Address of a List of Objects that shall be sorted and returned. Must be
   1168 *      non-NULL, but may be empty.
   1169 *  "plContext"
   1170 *      Platform-specific context pointer.
   1171 * THREAD SAFETY:
   1172 *  Not Thread Safe - assumes exclusive access to "toList"
   1173 *  (see Thread Safety Definitions in Programmer's Guide)
   1174 * RETURNS:
   1175 *  Returns NULL if the function succeeds
   1176 *  Returns a Fatal Error if the function fails in an unrecoverable way
   1177 */
   1178 PKIX_Error *
   1179 pkix_List_BubbleSort(
   1180        PKIX_List *fromList,
   1181        PKIX_List_SortComparatorCallback comparator,
   1182        PKIX_List **pSortedList,
   1183        void *plContext)
   1184 {
   1185        PKIX_List *sortedList = NULL;
   1186        PKIX_PL_Object *cmpObj = NULL;
   1187        PKIX_PL_Object *leastObj = NULL;
   1188        PKIX_Int32 cmpResult = 0;
   1189        PKIX_UInt32 size = 0;
   1190        PKIX_UInt32 i, j;
   1191 
   1192        PKIX_ENTER(BUILD, "pkix_List_BubbleSort");
   1193        PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);
   1194        
   1195        if (fromList->immutable) {
   1196            PKIX_ERROR(PKIX_CANNOTSORTIMMUTABLELIST);
   1197        }
   1198        PKIX_CHECK(pkix_List_Duplicate
   1199                ((PKIX_PL_Object *) fromList,
   1200                (PKIX_PL_Object **) &sortedList,
   1201                 plContext),
   1202                PKIX_LISTDUPLICATEFAILED);
   1203 
   1204        PKIX_CHECK(PKIX_List_GetLength(sortedList, &size, plContext),
   1205                PKIX_LISTGETLENGTHFAILED);
   1206 
   1207        if (size > 1) {
   1208 
   1209        /*
   1210         * Move from the first of the item on the list, For each iteration,
   1211         * compare and swap the least value to the head of the comparisoning
   1212         * sub-list.
   1213         */
   1214            for (i = 0; i < size - 1; i++) {
   1215 
   1216                PKIX_CHECK(PKIX_List_GetItem
   1217                        (sortedList, i, &leastObj, plContext),
   1218                        PKIX_LISTGETITEMFAILED);
   1219 
   1220                for (j = i + 1; j < size; j++) {
   1221                        PKIX_CHECK(PKIX_List_GetItem
   1222                                (sortedList, j, &cmpObj, plContext),
   1223                                PKIX_LISTGETITEMFAILED);
   1224                        PKIX_CHECK(comparator
   1225                                (leastObj, cmpObj, &cmpResult, plContext),
   1226                                PKIX_COMPARATORCALLBACKFAILED);
   1227                        if (cmpResult > 0) {
   1228                                PKIX_CHECK(PKIX_List_SetItem
   1229                                           (sortedList, j, leastObj, plContext),
   1230                                           PKIX_LISTSETITEMFAILED);
   1231 
   1232                                PKIX_DECREF(leastObj);
   1233                                leastObj = cmpObj;
   1234                                cmpObj = NULL;
   1235                        } else {
   1236                                PKIX_DECREF(cmpObj);
   1237                        }
   1238                }
   1239                PKIX_CHECK(PKIX_List_SetItem
   1240                           (sortedList, i, leastObj, plContext),
   1241                           PKIX_LISTSETITEMFAILED);
   1242 
   1243                PKIX_DECREF(leastObj);
   1244            }
   1245                
   1246        }
   1247 
   1248        *pSortedList = sortedList;
   1249        sortedList = NULL;
   1250 cleanup:
   1251 
   1252        PKIX_DECREF(sortedList);
   1253        PKIX_DECREF(leastObj);
   1254        PKIX_DECREF(cmpObj);
   1255 
   1256        PKIX_RETURN(LIST);
   1257 }
   1258 
   1259 /* --Public-List-Functions--------------------------------------------- */
   1260 
   1261 /*
   1262 * FUNCTION: PKIX_List_Create (see comments in pkix_util.h)
   1263 */
   1264 PKIX_Error *
   1265 PKIX_List_Create(
   1266        PKIX_List **pList,
   1267        void *plContext)
   1268 {
   1269        PKIX_List *list = NULL;
   1270 
   1271        PKIX_ENTER(LIST, "PKIX_List_Create");
   1272        PKIX_NULLCHECK_ONE(pList);
   1273 
   1274        PKIX_CHECK(pkix_List_Create_Internal(PKIX_TRUE, &list, plContext),
   1275                    PKIX_LISTCREATEINTERNALFAILED);
   1276 
   1277        *pList = list;
   1278 
   1279 cleanup:
   1280 
   1281        PKIX_RETURN(LIST);
   1282 }
   1283 
   1284 /*
   1285 * FUNCTION: PKIX_List_SetImmutable (see comments in pkix_util.h)
   1286 */
   1287 PKIX_Error *
   1288 PKIX_List_SetImmutable(
   1289        PKIX_List *list,
   1290        void *plContext)
   1291 {
   1292        PKIX_ENTER(LIST, "PKIX_List_SetImmutable");
   1293        PKIX_NULLCHECK_ONE(list);
   1294 
   1295        if (!list->isHeader){
   1296                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1297        }
   1298 
   1299        list->immutable = PKIX_TRUE;
   1300 
   1301 cleanup:
   1302 
   1303        PKIX_RETURN(LIST);
   1304 }
   1305 
   1306 /*
   1307 * FUNCTION: PKIX_List_IsImmutable (see comments in pkix_util.h)
   1308 */
   1309 PKIX_Error *
   1310 PKIX_List_IsImmutable(
   1311        PKIX_List *list,
   1312        PKIX_Boolean *pImmutable,
   1313        void *plContext)
   1314 {
   1315        PKIX_ENTER(LIST, "PKIX_List_IsImmutable");
   1316        PKIX_NULLCHECK_TWO(list, pImmutable);
   1317 
   1318        if (!list->isHeader){
   1319                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1320        }
   1321 
   1322        *pImmutable = list->immutable;
   1323 
   1324 cleanup:
   1325 
   1326        PKIX_RETURN(LIST);
   1327 }
   1328 
   1329 /*
   1330 * FUNCTION: PKIX_List_GetLength (see comments in pkix_util.h)
   1331 */
   1332 PKIX_Error *
   1333 PKIX_List_GetLength(
   1334        PKIX_List *list,
   1335        PKIX_UInt32 *pLength,
   1336        void *plContext)
   1337 {
   1338        PKIX_ENTER(LIST, "PKIX_List_GetLength");
   1339        PKIX_NULLCHECK_TWO(list, pLength);
   1340 
   1341        if (!list->isHeader){
   1342                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1343        }
   1344 
   1345        *pLength = list->length;
   1346 
   1347 cleanup:
   1348 
   1349        PKIX_RETURN(LIST);
   1350 }
   1351 
   1352 /*
   1353 * FUNCTION: PKIX_List_IsEmpty (see comments in pkix_util.h)
   1354 */
   1355 PKIX_Error *
   1356 PKIX_List_IsEmpty(
   1357        PKIX_List *list,
   1358        PKIX_Boolean *pEmpty,
   1359        void *plContext)
   1360 {
   1361        PKIX_UInt32 length;
   1362 
   1363        PKIX_ENTER(LIST, "PKIX_List_IsEmpty");
   1364        PKIX_NULLCHECK_TWO(list, pEmpty);
   1365 
   1366        if (!list->isHeader){
   1367                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1368        }
   1369 
   1370        length = list->length;
   1371 
   1372        if (length == 0){
   1373                *pEmpty = PKIX_TRUE;
   1374        } else {
   1375                *pEmpty = PKIX_FALSE;
   1376        }
   1377 
   1378 cleanup:
   1379 
   1380        PKIX_RETURN(LIST);
   1381 }
   1382 
   1383 /*
   1384 * FUNCTION: PKIX_List_AppendItem (see comments in pkix_util.h)
   1385 */
   1386 PKIX_Error *
   1387 PKIX_List_AppendItem(
   1388        PKIX_List *list,
   1389        PKIX_PL_Object *item,
   1390        void *plContext)
   1391 {
   1392        PKIX_List *lastElement = NULL;
   1393        PKIX_List *newElement = NULL;
   1394        PKIX_UInt32 length, i;
   1395 
   1396        PKIX_ENTER(LIST, "PKIX_List_AppendItem");
   1397        PKIX_NULLCHECK_ONE(list);
   1398 
   1399        if (list->immutable){
   1400                PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
   1401        }
   1402 
   1403        if (!list->isHeader){
   1404                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1405        }
   1406 
   1407        length = list->length;
   1408 
   1409        /* find last element of list and create new element there */
   1410 
   1411        lastElement = list;
   1412        for (i = 0; i < length; i++){
   1413                lastElement = lastElement->next;
   1414        }
   1415 
   1416        PKIX_CHECK(pkix_List_Create_Internal
   1417                    (PKIX_FALSE, &newElement, plContext),
   1418                    PKIX_LISTCREATEINTERNALFAILED);
   1419 
   1420        PKIX_INCREF(item);
   1421        newElement->item = item;
   1422 
   1423        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
   1424                    ((PKIX_PL_Object *)list, plContext),
   1425                    PKIX_OBJECTINVALIDATECACHEFAILED);
   1426 
   1427        lastElement->next = newElement;
   1428        newElement = NULL;
   1429        list->length += 1;
   1430 
   1431 cleanup:
   1432 
   1433        PKIX_DECREF(newElement);
   1434 
   1435        PKIX_RETURN(LIST);
   1436 }
   1437 
   1438 /*
   1439 * FUNCTION: PKIX_List_InsertItem (see comments in pkix_util.h)
   1440 */
   1441 PKIX_Error *
   1442 PKIX_List_InsertItem(
   1443        PKIX_List *list,
   1444        PKIX_UInt32 index,
   1445        PKIX_PL_Object *item,
   1446        void *plContext)
   1447 {
   1448        PKIX_List *element = NULL;
   1449        PKIX_List *newElem = NULL;
   1450 
   1451        PKIX_ENTER(LIST, "PKIX_List_InsertItem");
   1452        PKIX_NULLCHECK_ONE(list);
   1453 
   1454 
   1455        if (list->immutable){
   1456                PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
   1457        }
   1458 
   1459        if (!list->isHeader){
   1460                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1461        }
   1462 
   1463        /* Create a new list object */
   1464        PKIX_CHECK(pkix_List_Create_Internal(PKIX_FALSE, &newElem, plContext),
   1465                    PKIX_LISTCREATEINTERNALFAILED);
   1466 
   1467        if (list->length) {
   1468            PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
   1469                       PKIX_LISTGETELEMENTFAILED);
   1470            /* Copy the old element's contents into the new element */
   1471            newElem->item = element->item;
   1472            /* Add new item to the list */
   1473            PKIX_INCREF(item);
   1474            element->item = item;
   1475            /* Set the new element's next pointer to the old element's next */
   1476            newElem->next = element->next;
   1477            /* Set the old element's next pointer to the new element */
   1478            element->next = newElem;
   1479            newElem = NULL;
   1480        } else {
   1481            PKIX_INCREF(item);
   1482            newElem->item = item;
   1483            newElem->next = NULL;
   1484            list->next = newElem;
   1485            newElem = NULL;
   1486        }
   1487        list->length++;
   1488 
   1489        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
   1490                    ((PKIX_PL_Object *)list, plContext),
   1491                    PKIX_OBJECTINVALIDATECACHEFAILED);
   1492 cleanup:
   1493        PKIX_DECREF(newElem);
   1494 
   1495        PKIX_RETURN(LIST);
   1496 }
   1497 
   1498 /*
   1499 * FUNCTION: PKIX_List_GetItem (see comments in pkix_util.h)
   1500 */
   1501 PKIX_Error *
   1502 PKIX_List_GetItem(
   1503        PKIX_List *list,
   1504        PKIX_UInt32 index,
   1505        PKIX_PL_Object **pItem,
   1506        void *plContext)
   1507 {
   1508        PKIX_List *element = NULL;
   1509 
   1510        PKIX_ENTER(LIST, "PKIX_List_GetItem");
   1511        PKIX_NULLCHECK_TWO(list, pItem);
   1512 
   1513        if (!list->isHeader){
   1514                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1515        }
   1516 
   1517        PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
   1518                    PKIX_LISTGETELEMENTFAILED);
   1519 
   1520        PKIX_INCREF(element->item);
   1521        *pItem = element->item;
   1522 
   1523 cleanup:
   1524 
   1525        PKIX_RETURN(LIST);
   1526 }
   1527 
   1528 /*
   1529 * FUNCTION: PKIX_List_SetItem (see comments in pkix_util.h)
   1530 */
   1531 PKIX_Error *
   1532 PKIX_List_SetItem(
   1533        PKIX_List *list,
   1534        PKIX_UInt32 index,
   1535        PKIX_PL_Object *item,
   1536        void *plContext)
   1537 {
   1538        PKIX_List *element;
   1539 
   1540        PKIX_ENTER(LIST, "PKIX_List_SetItem");
   1541        PKIX_NULLCHECK_ONE(list);
   1542 
   1543        if (list->immutable){
   1544                PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
   1545        }
   1546 
   1547        if (!list->isHeader){
   1548                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1549        }
   1550 
   1551        PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
   1552                    PKIX_LISTGETELEMENTFAILED);
   1553 
   1554        /* DecRef old contents */
   1555        PKIX_DECREF(element->item);
   1556 
   1557        /* Set New Contents */
   1558        PKIX_INCREF(item);
   1559        element->item = item;
   1560 
   1561        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
   1562                    ((PKIX_PL_Object *)list, plContext),
   1563                    PKIX_OBJECTINVALIDATECACHEFAILED);
   1564 
   1565 cleanup:
   1566 
   1567        PKIX_RETURN(LIST);
   1568 }
   1569 
   1570 /*
   1571 * FUNCTION: PKIX_List_DeleteItem (see comments in pkix_util.h)
   1572 */
   1573 PKIX_Error *
   1574 PKIX_List_DeleteItem(
   1575        PKIX_List *list,
   1576        PKIX_UInt32 index,
   1577        void *plContext)
   1578 {
   1579        PKIX_List *element = NULL;
   1580        PKIX_List *prevElement = NULL;
   1581        PKIX_List *nextElement = NULL;
   1582 
   1583        PKIX_ENTER(LIST, "PKIX_List_DeleteItem");
   1584        PKIX_NULLCHECK_ONE(list);
   1585 
   1586        if (list->immutable){
   1587                PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
   1588        }
   1589 
   1590        if (!list->isHeader){
   1591                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1592        }
   1593 
   1594        PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
   1595                    PKIX_LISTGETELEMENTFAILED);
   1596 
   1597        /* DecRef old contents */
   1598        PKIX_DECREF(element->item);
   1599 
   1600        nextElement = element->next;
   1601 
   1602        if (nextElement != NULL) {
   1603                /* If the next element exists, splice it out. */
   1604 
   1605                /* Don't need to change ref counts for targets of next */
   1606                element->item = nextElement->item;
   1607                nextElement->item = NULL;
   1608 
   1609                /* Don't need to change ref counts for targets of next */
   1610                element->next = nextElement->next;
   1611                nextElement->next = NULL;
   1612 
   1613                PKIX_DECREF(nextElement);
   1614 
   1615        } else { /* The element is at the tail of the list */
   1616                if (index != 0) {
   1617                        PKIX_CHECK(pkix_List_GetElement
   1618                                    (list, index-1, &prevElement, plContext),
   1619                                    PKIX_LISTGETELEMENTFAILED);
   1620                } else if (index == 0){ /* prevElement must be header */
   1621                        prevElement = list;
   1622                }
   1623                prevElement->next = NULL;
   1624 
   1625                /* Delete the element */
   1626                PKIX_DECREF(element);
   1627        }
   1628 
   1629        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
   1630                    ((PKIX_PL_Object *)list, plContext),
   1631                    PKIX_OBJECTINVALIDATECACHEFAILED);
   1632 
   1633        list->length = list->length - 1;
   1634 
   1635 cleanup:
   1636 
   1637        PKIX_RETURN(LIST);
   1638 }
   1639 
   1640 /*
   1641 * FUNCTION: PKIX_List_ReverseList (see comments in pkix_util.h)
   1642 */
   1643 PKIX_Error *
   1644 PKIX_List_ReverseList(
   1645        PKIX_List *list,
   1646        PKIX_List **pReversedList,
   1647        void *plContext)
   1648 {
   1649        PKIX_List *reversedList = NULL;
   1650        PKIX_PL_Object *item = NULL;
   1651        PKIX_PL_Object *duplicateItem = NULL;
   1652        PKIX_UInt32 length, i;
   1653 
   1654        PKIX_ENTER(LIST, "pkix_List_ReverseList");
   1655        PKIX_NULLCHECK_TWO(list, pReversedList);
   1656 
   1657        if (!list->isHeader){
   1658                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
   1659        }
   1660 
   1661        length = list->length;
   1662 
   1663        /* Create a new list object */
   1664        PKIX_CHECK(PKIX_List_Create(&reversedList, plContext),
   1665                    PKIX_LISTCREATEINTERNALFAILED);
   1666 
   1667        /*
   1668         * Starting with the last item and traversing backwards (from
   1669         * the original list), append each item to the reversed list
   1670         */
   1671 
   1672        for (i = 1; i <= length; i++){
   1673                PKIX_CHECK(PKIX_List_GetItem
   1674                            (list, (length - i), &item, plContext),
   1675                            PKIX_LISTGETITEMFAILED);
   1676 
   1677                PKIX_CHECK(PKIX_PL_Object_Duplicate
   1678                            (item, &duplicateItem, plContext),
   1679                            PKIX_LISTDUPLICATEFAILED);
   1680 
   1681                PKIX_CHECK(PKIX_List_AppendItem
   1682                            (reversedList, duplicateItem, plContext),
   1683                            PKIX_LISTAPPENDITEMFAILED);
   1684 
   1685                PKIX_DECREF(item);
   1686                PKIX_DECREF(duplicateItem);
   1687        }
   1688 
   1689        *pReversedList = reversedList;
   1690 
   1691 cleanup:
   1692 
   1693        PKIX_DECREF(item);
   1694        PKIX_DECREF(duplicateItem);
   1695 
   1696        if (PKIX_ERROR_RECEIVED){
   1697                PKIX_DECREF(reversedList);
   1698        }
   1699 
   1700        PKIX_RETURN(LIST);
   1701 }