Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / libpkix / pkix / util / pkix_list.c
bloba5750ec0dff1545079c06347ff3954a5534e4cb0
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Sun Microsystems
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 * pkix_list.c
40 * List Object Functions
44 #include "pkix_list.h"
46 /* --Private-Functions-------------------------------------------- */
49 * FUNCTION: pkix_List_Create_Internal
50 * DESCRIPTION:
52 * Creates a new List, using the Boolean value of "isHeader" to determine
53 * whether the new List should be a header, and stores it at "pList". The
54 * List is initially empty and holds no items. To initially add items to
55 * the List, use PKIX_List_AppendItem.
57 * PARAMETERS:
58 * "isHeader"
59 * Boolean value indicating whether new List should be a header.
60 * "pList"
61 * Address where object pointer will be stored. Must be non-NULL.
62 * "plContext"
63 * Platform-specific context pointer.
64 * THREAD SAFETY:
65 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
66 * RETURNS:
67 * Returns NULL if the function succeeds.
68 * Returns a Fatal Error if the function fails in an unrecoverable way.
70 static PKIX_Error *
71 pkix_List_Create_Internal(
72 PKIX_Boolean isHeader,
73 PKIX_List **pList,
74 void *plContext)
76 PKIX_List *list = NULL;
78 PKIX_ENTER(LIST, "pkix_List_Create_Internal");
79 PKIX_NULLCHECK_ONE(pList);
81 PKIX_CHECK(PKIX_PL_Object_Alloc
82 (PKIX_LIST_TYPE,
83 ((PKIX_UInt32)(sizeof (PKIX_List))),
84 (PKIX_PL_Object **)&list, plContext),
85 PKIX_ERRORCREATINGLISTITEM);
87 list->item = NULL;
88 list->next = NULL;
89 list->immutable = PKIX_FALSE;
90 list->length = 0;
91 list->isHeader = isHeader;
93 *pList = list;
95 cleanup:
97 PKIX_RETURN(LIST);
101 * FUNCTION: pkix_List_Destroy
102 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
104 static PKIX_Error *
105 pkix_List_Destroy(
106 PKIX_PL_Object *object,
107 void *plContext)
109 PKIX_List *list = NULL;
111 PKIX_ENTER(LIST, "pkix_List_Destroy");
112 PKIX_NULLCHECK_ONE(object);
114 /* Check that this object is a list */
115 PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
116 PKIX_OBJECTNOTLIST);
118 list = (PKIX_List *)object;
120 /* We have a valid list. DecRef its item and recurse on next */
121 PKIX_DECREF(list->item);
122 PKIX_DECREF(list->next);
123 list->immutable = PKIX_FALSE;
124 list->length = 0;
125 list->isHeader = PKIX_FALSE;
127 cleanup:
129 PKIX_RETURN(LIST);
133 * FUNCTION: pkix_List_ToString_Helper
134 * DESCRIPTION:
136 * Helper function that creates a string representation of the List pointed
137 * to by "list" and stores its address in the object pointed to by "pString".
139 * PARAMETERS
140 * "list"
141 * Address of List whose string representation is desired.
142 * Must be non-NULL.
143 * "pString"
144 * Address of object pointer's destination. Must be non-NULL.
145 * "plContext"
146 * Platform-specific context pointer.
147 * THREAD SAFETY:
148 * Conditionally Thread Safe
149 * (see Thread Safety Definitions in Programmer's Guide)
150 * RETURNS:
151 * Returns NULL if the function succeeds.
152 * Returns a List Error if the function fails in a non-fatal way.
153 * Returns a Fatal Error if the function fails in an unrecoverable way.
155 static PKIX_Error *
156 pkix_List_ToString_Helper(
157 PKIX_List *list,
158 PKIX_PL_String **pString,
159 void *plContext)
161 PKIX_PL_String *itemString = NULL;
162 PKIX_PL_String *nextString = NULL;
163 PKIX_PL_String *format = NULL;
164 PKIX_Boolean empty;
166 PKIX_ENTER(LIST, "pkix_List_ToString_Helper");
167 PKIX_NULLCHECK_TWO(list, pString);
169 /* special case when list is the header */
170 if (list->isHeader){
172 PKIX_CHECK(PKIX_List_IsEmpty(list, &empty, plContext),
173 PKIX_LISTISEMPTYFAILED);
175 if (empty){
176 PKIX_CHECK(PKIX_PL_String_Create
177 (PKIX_ESCASCII,
178 "EMPTY",
180 &itemString,
181 plContext),
182 PKIX_ERRORCREATINGITEMSTRING);
183 (*pString) = itemString;
184 PKIX_DEBUG_EXIT(LIST);
185 return (NULL);
186 } else {
187 PKIX_CHECK(pkix_List_ToString_Helper
188 (list->next, &itemString, plContext),
189 PKIX_LISTTOSTRINGHELPERFAILED);
192 /* Create a string object from the format */
193 PKIX_CHECK(PKIX_PL_String_Create
194 (PKIX_ESCASCII, "%s", 0, &format, plContext),
195 PKIX_STRINGCREATEFAILED);
197 PKIX_CHECK(PKIX_PL_Sprintf
198 (pString, plContext, format, itemString),
199 PKIX_SPRINTFFAILED);
200 } else {
201 /* Get a string for this list's item */
202 if (list->item == NULL) {
203 PKIX_CHECK(PKIX_PL_String_Create
204 (PKIX_ESCASCII,
205 "(null)",
207 &itemString,
208 plContext),
209 PKIX_STRINGCREATEFAILED);
210 } else {
211 PKIX_CHECK(PKIX_PL_Object_ToString
212 ((PKIX_PL_Object*)list->item,
213 &itemString,
214 plContext),
215 PKIX_OBJECTTOSTRINGFAILED);
217 if (list->next == NULL) {
218 /* Just return the itemstring */
219 (*pString) = itemString;
220 PKIX_DEBUG_EXIT(LIST);
221 return (NULL);
224 /* Recursive call to get string for this list's next pointer */
225 PKIX_CHECK(pkix_List_ToString_Helper
226 (list->next, &nextString, plContext),
227 PKIX_LISTTOSTRINGHELPERFAILED);
229 /* Create a string object from the format */
230 PKIX_CHECK(PKIX_PL_String_Create
231 (PKIX_ESCASCII,
232 "%s, %s",
234 &format,
235 plContext),
236 PKIX_STRINGCREATEFAILED);
238 PKIX_CHECK(PKIX_PL_Sprintf
239 (pString,
240 plContext,
241 format,
242 itemString,
243 nextString),
244 PKIX_SPRINTFFAILED);
247 cleanup:
249 PKIX_DECREF(itemString);
250 PKIX_DECREF(nextString);
251 PKIX_DECREF(format);
253 PKIX_RETURN(LIST);
257 * FUNCTION: pkix_List_ToString
258 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
260 static PKIX_Error *
261 pkix_List_ToString(
262 PKIX_PL_Object *object,
263 PKIX_PL_String **pString,
264 void *plContext)
266 PKIX_List *list = NULL;
267 PKIX_PL_String *listString = NULL;
268 PKIX_PL_String *format = NULL;
270 PKIX_ENTER(LIST, "pkix_List_ToString");
271 PKIX_NULLCHECK_TWO(object, pString);
273 PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
274 PKIX_OBJECTNOTLIST);
276 list = (PKIX_List *)object;
278 if (!list->isHeader){
279 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
282 PKIX_CHECK(pkix_List_ToString_Helper(list, &listString, plContext),
283 PKIX_LISTTOSTRINGHELPERFAILED);
285 PKIX_CHECK(PKIX_PL_String_Create
286 (PKIX_ESCASCII, "(%s)", 0, &format, plContext),
287 PKIX_STRINGCREATEFAILED);
289 PKIX_CHECK(PKIX_PL_Sprintf(pString, plContext, format, listString),
290 PKIX_SPRINTFFAILED);
292 cleanup:
294 PKIX_DECREF(listString);
295 PKIX_DECREF(format);
297 PKIX_RETURN(LIST);
301 * FUNCTION: pkix_List_Equals
302 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
304 static PKIX_Error *
305 pkix_List_Equals(
306 PKIX_PL_Object *first,
307 PKIX_PL_Object *second,
308 PKIX_Boolean *pResult,
309 void *plContext)
311 PKIX_UInt32 secondType;
312 PKIX_Boolean cmpResult;
313 PKIX_List *firstList = NULL;
314 PKIX_List *secondList = NULL;
315 PKIX_UInt32 firstLength = 0;
316 PKIX_UInt32 secondLength = 0;
317 PKIX_PL_Object *firstItem = NULL;
318 PKIX_PL_Object *secondItem = NULL;
319 PKIX_UInt32 i = 0;
321 PKIX_ENTER(LIST, "pkix_List_Equals");
322 PKIX_NULLCHECK_THREE(first, second, pResult);
324 /* test that first is a List */
325 PKIX_CHECK(pkix_CheckType(first, PKIX_LIST_TYPE, plContext),
326 PKIX_FIRSTOBJECTNOTLIST);
329 * Since we know first is a List, if both references are
330 * identical, they must be equal
332 if (first == second){
333 *pResult = PKIX_TRUE;
334 goto cleanup;
338 * If second isn't a List, we don't throw an error.
339 * We simply return a Boolean result of FALSE
341 *pResult = PKIX_FALSE;
342 PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
343 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
344 if (secondType != PKIX_LIST_TYPE) goto cleanup;
346 firstList = (PKIX_List *)first;
347 secondList = (PKIX_List *)second;
349 if ((!firstList->isHeader) && (!secondList->isHeader)){
350 PKIX_ERROR(PKIX_INPUTLISTSMUSTBELISTHEADERS);
353 firstLength = firstList->length;
354 secondLength = secondList->length;
356 cmpResult = PKIX_FALSE;
357 if (firstLength == secondLength){
358 for (i = 0, cmpResult = PKIX_TRUE;
359 ((i < firstLength) && cmpResult);
360 i++){
361 PKIX_CHECK(PKIX_List_GetItem
362 (firstList, i, &firstItem, plContext),
363 PKIX_LISTGETITEMFAILED);
365 PKIX_CHECK(PKIX_List_GetItem
366 (secondList, i, &secondItem, plContext),
367 PKIX_LISTGETITEMFAILED);
369 if ((!firstItem && secondItem) ||
370 (firstItem && !secondItem)){
371 cmpResult = PKIX_FALSE;
372 } else if (!firstItem && !secondItem){
373 continue;
374 } else {
375 PKIX_CHECK(PKIX_PL_Object_Equals
376 (firstItem,
377 secondItem,
378 &cmpResult,
379 plContext),
380 PKIX_OBJECTEQUALSFAILED);
382 PKIX_DECREF(firstItem);
383 PKIX_DECREF(secondItem);
388 *pResult = cmpResult;
390 cleanup:
392 PKIX_DECREF(firstItem);
393 PKIX_DECREF(secondItem);
395 PKIX_RETURN(LIST);
399 * FUNCTION: pkix_List_Hashcode
400 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
402 static PKIX_Error *
403 pkix_List_Hashcode(
404 PKIX_PL_Object *object,
405 PKIX_UInt32 *pHashcode,
406 void *plContext)
408 PKIX_List *list = NULL;
409 PKIX_PL_Object *element = NULL;
410 PKIX_UInt32 hash = 0;
411 PKIX_UInt32 tempHash = 0;
412 PKIX_UInt32 length, i;
414 PKIX_ENTER(LIST, "pkix_List_Hashcode");
415 PKIX_NULLCHECK_TWO(object, pHashcode);
417 PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
418 PKIX_OBJECTNOTLIST);
420 list = (PKIX_List *)object;
422 if (!list->isHeader){
423 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
426 length = list->length;
428 for (i = 0; i < length; i++){
429 PKIX_CHECK(PKIX_List_GetItem(list, i, &element, plContext),
430 PKIX_LISTGETITEMFAILED);
432 if (!element){
433 tempHash = 100;
434 } else {
435 PKIX_CHECK(PKIX_PL_Object_Hashcode
436 (element, &tempHash, plContext),
437 PKIX_LISTHASHCODEFAILED);
440 hash = 31 * hash + tempHash;
442 PKIX_DECREF(element);
445 *pHashcode = hash;
447 cleanup:
449 PKIX_DECREF(element);
450 PKIX_RETURN(LIST);
454 * FUNCTION: pkix_List_Duplicate
455 * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h)
457 static PKIX_Error *
458 pkix_List_Duplicate(
459 PKIX_PL_Object *object,
460 PKIX_PL_Object **pNewObject,
461 void *plContext)
463 PKIX_List *list = NULL;
464 PKIX_List *listDuplicate = NULL;
466 PKIX_ENTER(LIST, "pkix_List_Duplicate");
467 PKIX_NULLCHECK_TWO(object, pNewObject);
469 PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
470 PKIX_OBJECTNOTLIST);
472 list = (PKIX_List *)object;
474 if (list->immutable){
475 PKIX_CHECK(pkix_duplicateImmutable
476 (object, pNewObject, plContext),
477 PKIX_DUPLICATEIMMUTABLEFAILED);
478 } else {
480 PKIX_CHECK(pkix_List_Create_Internal
481 (list->isHeader, &listDuplicate, plContext),
482 PKIX_LISTCREATEINTERNALFAILED);
484 listDuplicate->length = list->length;
486 PKIX_INCREF(list->item);
487 listDuplicate->item = list->item;
489 if (list->next == NULL){
490 listDuplicate->next = NULL;
491 } else {
492 /* Recursively Duplicate list */
493 PKIX_CHECK(pkix_List_Duplicate
494 ((PKIX_PL_Object *)list->next,
495 (PKIX_PL_Object **)&listDuplicate->next,
496 plContext),
497 PKIX_LISTDUPLICATEFAILED);
500 *pNewObject = (PKIX_PL_Object *)listDuplicate;
503 cleanup:
505 if (PKIX_ERROR_RECEIVED){
506 PKIX_DECREF(listDuplicate);
509 PKIX_RETURN(LIST);
514 * FUNCTION: pkix_List_GetElement
515 * DESCRIPTION:
517 * Copies the "list"'s element at "index" into "element". The input List must
518 * be the header of the List (as opposed to being an element of the List). The
519 * index counts from zero and must be less than the List's length. This
520 * function does NOT increment the reference count of the List element since
521 * the returned element's reference will not be stored by the calling
522 * function.
524 * PARAMETERS:
525 * "list"
526 * Address of List (must be header) to get element from. Must be non-NULL.
527 * "index"
528 * Index of list to get element from. Must be less than List's length.
529 * "pElement"
530 * Address where object pointer will be stored. Must be non-NULL.
531 * "plContext"
532 * Platform-specific context pointer.
533 * THREAD SAFETY:
534 * Conditionally Thread Safe
535 * (see Thread Safety Definitions in Programmer's Guide)
536 * RETURNS:
537 * Returns NULL if the function succeeds.
538 * Returns a Fatal Error if the function fails in an unrecoverable way.
540 static PKIX_Error *
541 pkix_List_GetElement(
542 PKIX_List *list,
543 PKIX_UInt32 index,
544 PKIX_List **pElement,
545 void *plContext)
547 PKIX_List *iterator = NULL;
548 PKIX_UInt32 length;
549 PKIX_UInt32 position = 0;
551 PKIX_ENTER(LIST, "pkix_List_GetElement");
552 PKIX_NULLCHECK_TWO(list, pElement);
554 if (!list->isHeader){
555 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
558 length = list->length;
560 if (index >= length) {
561 PKIX_ERROR(PKIX_INDEXOUTOFBOUNDS);
564 for (iterator = list; position++ <= index; iterator = iterator->next)
567 (*pElement) = iterator;
569 cleanup:
571 PKIX_RETURN(LIST);
576 * FUNCTION: pkix_List_RegisterSelf
577 * DESCRIPTION:
578 * Registers PKIX_LIST_TYPE and its related functions with systemClasses[]
579 * THREAD SAFETY:
580 * Not Thread Safe - for performance and complexity reasons
582 * Since this function is only called by PKIX_PL_Initialize, which should
583 * only be called once, it is acceptable that this function is not
584 * thread-safe.
586 PKIX_Error *
587 pkix_List_RegisterSelf(void *plContext)
589 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
590 pkix_ClassTable_Entry entry;
592 PKIX_ENTER(LIST, "pkix_List_RegisterSelf");
594 entry.description = "List";
595 entry.destructor = pkix_List_Destroy;
596 entry.equalsFunction = pkix_List_Equals;
597 entry.hashcodeFunction = pkix_List_Hashcode;
598 entry.toStringFunction = pkix_List_ToString;
599 entry.comparator = NULL;
600 entry.duplicateFunction = pkix_List_Duplicate;
602 systemClasses[PKIX_LIST_TYPE] = entry;
604 PKIX_RETURN(LIST);
608 * FUNCTION: pkix_List_Contains
609 * DESCRIPTION:
611 * Checks a List pointed to by "list", to determine whether it includes
612 * an entry that is equal to the Object pointed to by "object", and stores
613 * the result in "pFound".
615 * PARAMETERS:
616 * "list"
617 * List to be searched; may be empty; must be non-NULL
618 * "object"
619 * Object to be checked for; must be non-NULL
620 * "pFound"
621 * Address where the result of the search will be stored. Must
622 * be non-NULL
623 * "plContext"
624 * platform-specific context pointer
625 * THREAD SAFETY:
626 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
627 * RETURNS:
628 * Returns NULL if the function succeeds
629 * Returns a Fatal Error if the function fails in an unrecoverable way
631 PKIX_Error *
632 pkix_List_Contains(
633 PKIX_List *list,
634 PKIX_PL_Object *object,
635 PKIX_Boolean *pFound,
636 void *plContext)
638 PKIX_PL_Object *current = NULL;
639 PKIX_UInt32 numEntries = 0;
640 PKIX_UInt32 index = 0;
641 PKIX_Boolean match = PKIX_FALSE;
643 PKIX_ENTER(LIST, "pkix_List_Contains");
644 PKIX_NULLCHECK_THREE(list, object, pFound);
646 PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext),
647 PKIX_LISTGETLENGTHFAILED);
649 for (index = 0; index < numEntries; index++) {
650 PKIX_CHECK(PKIX_List_GetItem
651 (list, index, &current, plContext),
652 PKIX_LISTGETITEMFAILED);
654 if (current) {
655 PKIX_CHECK(PKIX_PL_Object_Equals
656 (object, current, &match, plContext),
657 PKIX_OBJECTEQUALSFAILED);
659 PKIX_DECREF(current);
662 if (match) {
663 break;
667 *pFound = match;
669 cleanup:
671 PKIX_DECREF(current);
672 PKIX_RETURN(LIST);
676 * FUNCTION: pkix_List_Remove
677 * DESCRIPTION:
679 * Traverses the List pointed to by "list", to find and delete an entry
680 * that is equal to the Object pointed to by "object". If no such entry
681 * is found the function does not return an error.
683 * PARAMETERS:
684 * "list"
685 * List to be searched; may be empty; must be non-NULL
686 * "object"
687 * Object to be checked for and deleted, if found; must be non-NULL
688 * "plContext"
689 * platform-specific context pointer
690 * THREAD SAFETY:
691 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
692 * RETURNS:
693 * Returns NULL if the function succeeds
694 * Returns a Validate Error if the functions fails in a non-fatal way
695 * Returns a Fatal Error if the function fails in an unrecoverable way
697 PKIX_Error *
698 pkix_List_Remove(
699 PKIX_List *list,
700 PKIX_PL_Object *object,
701 void *plContext)
703 PKIX_PL_Object *current = NULL;
704 PKIX_UInt32 numEntries = 0;
705 PKIX_UInt32 index = 0;
706 PKIX_Boolean match = PKIX_FALSE;
708 PKIX_ENTER(LIST, "pkix_List_Remove");
709 PKIX_NULLCHECK_TWO(list, object);
711 PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext),
712 PKIX_LISTGETLENGTHFAILED);
714 for (index = 0; index < numEntries; index++) {
715 PKIX_CHECK(PKIX_List_GetItem
716 (list, index, &current, plContext),
717 PKIX_LISTGETITEMFAILED);
719 if (current) {
720 PKIX_CHECK(PKIX_PL_Object_Equals
721 (object, current, &match, plContext),
722 PKIX_OBJECTEQUALSFAILED);
724 PKIX_DECREF(current);
727 if (match) {
728 PKIX_CHECK(PKIX_List_DeleteItem
729 (list, index, plContext),
730 PKIX_LISTDELETEITEMFAILED);
731 break;
735 cleanup:
737 PKIX_DECREF(current);
738 PKIX_RETURN(LIST);
742 * FUNCTION: pkix_List_RemoveItems
743 * DESCRIPTION:
745 * Traverses the List pointed to by "list", to find and delete an entry
746 * that is equal to the Object in the "deleteList". If no such entry
747 * is found the function does not return an error.
749 * PARAMETERS:
750 * "list"
751 * Object in "list" is checked for object in "deleteList" and deleted if
752 * found; may be empty; must be non-NULL
753 * "deleteList"
754 * List of objects to be searched ; may be empty; must be non-NULL
755 * "plContext"
756 * platform-specific context pointer
757 * THREAD SAFETY:
758 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
759 * RETURNS:
760 * Returns NULL if the function succeeds
761 * Returns a Validate Error if the functions fails in a non-fatal way
762 * Returns a Fatal Error if the function fails in an unrecoverable way
764 PKIX_Error *
765 pkix_List_RemoveItems(
766 PKIX_List *list,
767 PKIX_List *deleteList,
768 void *plContext)
770 PKIX_PL_Object *current = NULL;
771 PKIX_UInt32 numEntries = 0;
772 PKIX_UInt32 index = 0;
774 PKIX_ENTER(LIST, "pkix_List_RemoveItems");
775 PKIX_NULLCHECK_TWO(list, deleteList);
777 PKIX_CHECK(PKIX_List_GetLength(deleteList, &numEntries, plContext),
778 PKIX_LISTGETLENGTHFAILED);
780 for (index = 0; index < numEntries; index++) {
781 PKIX_CHECK(PKIX_List_GetItem
782 (deleteList, index, &current, plContext),
783 PKIX_LISTGETITEMFAILED);
785 if (current) {
786 PKIX_CHECK(pkix_List_Remove
787 (list, current, plContext),
788 PKIX_OBJECTEQUALSFAILED);
790 PKIX_DECREF(current);
794 cleanup:
796 PKIX_DECREF(current);
797 PKIX_RETURN(LIST);
801 * FUNCTION: pkix_List_MergeLists
802 * DESCRIPTION:
804 * Creates a new list consisting of the items from "firstList", followed by
805 * the items on "secondList", returns the new list at "pMergedList". If
806 * both input lists are NULL or empty, the result is an empty list. If an error
807 * occurs, the result is NULL.
809 * PARAMETERS:
810 * "firstList"
811 * Address of list to be merged from. May be NULL or empty.
812 * "secondList"
813 * Address of list to be merged from. May be NULL or empty.
814 * "pMergedList"
815 * Address where returned object is stored.
816 * "plContext"
817 * platform-specific context pointer * THREAD SAFETY:
818 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
819 * RETURNS:
820 * Returns NULL if the function succeeds
821 * Returns a List Error if the functions fails in a non-fatal way
822 * Returns a Fatal Error if the function fails in an unrecoverable way
824 PKIX_Error *
825 pkix_List_MergeLists(
826 PKIX_List *firstList,
827 PKIX_List *secondList,
828 PKIX_List **pMergedList,
829 void *plContext)
831 PKIX_List *list = NULL;
832 PKIX_PL_Object *item = NULL;
833 PKIX_UInt32 numItems = 0;
834 PKIX_UInt32 i;
836 PKIX_ENTER(LIST, "pkix_List_MergeLists");
837 PKIX_NULLCHECK_ONE(pMergedList);
839 *pMergedList = NULL;
841 PKIX_CHECK(PKIX_List_Create(&list, plContext),
842 PKIX_LISTCREATEFAILED);
844 if (firstList != NULL) {
846 PKIX_CHECK(PKIX_List_GetLength(firstList, &numItems, plContext),
847 PKIX_LISTGETLENGTHFAILED);
850 for (i = 0; i < numItems; i++) {
852 PKIX_CHECK(PKIX_List_GetItem(firstList, i, &item, plContext),
853 PKIX_LISTGETITEMFAILED);
855 PKIX_CHECK(PKIX_List_AppendItem(list, item, plContext),
856 PKIX_LISTAPPENDITEMFAILED);
858 PKIX_DECREF(item);
861 numItems = 0;
862 if (secondList != NULL) {
864 PKIX_CHECK(PKIX_List_GetLength
865 (secondList,
866 &numItems,
867 plContext),
868 PKIX_LISTGETLENGTHFAILED);
872 for (i = 0; i < numItems; i++) {
874 PKIX_CHECK(PKIX_List_GetItem
875 (secondList, i, &item, plContext),
876 PKIX_LISTGETITEMFAILED);
878 PKIX_CHECK(PKIX_List_AppendItem
879 (list, item, plContext), PKIX_LISTAPPENDITEMFAILED);
881 PKIX_DECREF(item);
884 *pMergedList = list;
886 cleanup:
888 if (PKIX_ERROR_RECEIVED){
889 PKIX_DECREF(list);
892 PKIX_RETURN(LIST);
896 * FUNCTION: pkix_List_AppendList
897 * DESCRIPTION:
899 * Append items on "fromList" to the "toList". Item reference count on
900 * "toList" is not incremented, but items appended from "fromList" are
901 * incremented.
903 * PARAMETERS:
904 * "toList"
905 * Address of list to be appended to. Must be non-NULL.
906 * "fromList"
907 * Address of list to be appended from. May be NULL or empty.
908 * "plContext"
909 * platform-specific context pointer
910 * THREAD SAFETY:
911 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
912 * RETURNS:
913 * Returns NULL if the function succeeds
914 * Returns a List Error if the functions fails in a non-fatal way
915 * Returns a Fatal Error if the function fails in an unrecoverable way
917 PKIX_Error *
918 pkix_List_AppendList(
919 PKIX_List *toList,
920 PKIX_List *fromList,
921 void *plContext)
923 PKIX_PL_Object *item = NULL;
924 PKIX_UInt32 numItems = 0;
925 PKIX_UInt32 i;
927 PKIX_ENTER(LIST, "pkix_List_AppendList");
928 PKIX_NULLCHECK_ONE(toList);
930 /* if fromList is NULL or is an empty list, no action */
932 if (fromList == NULL) {
933 goto cleanup;
936 PKIX_CHECK(PKIX_List_GetLength(fromList, &numItems, plContext),
937 PKIX_LISTGETLENGTHFAILED);
939 if (numItems == 0) {
940 goto cleanup;
943 for (i = 0; i < numItems; i++) {
945 PKIX_CHECK(PKIX_List_GetItem
946 (fromList, i, &item, plContext),
947 PKIX_LISTGETITEMFAILED);
949 PKIX_CHECK(PKIX_List_AppendItem(toList, item, plContext),
950 PKIX_LISTAPPENDITEMFAILED);
952 PKIX_DECREF(item);
955 cleanup:
957 PKIX_RETURN(LIST);
961 * FUNCTION: pkix_List_AppendUnique
962 * DESCRIPTION:
964 * Adds each Object in the List pointed to by "fromList" to the List pointed
965 * to by "toList", if it is not already a member of that List. In other words,
966 * "toList" becomes the union of the two sets.
968 * PARAMETERS:
969 * "toList"
970 * Address of a List of Objects to be augmented by "fromList". Must be
971 * non-NULL, but may be empty.
972 * "fromList"
973 * Address of a List of Objects to be added, if not already present, to
974 * "toList". Must be non-NULL, but may be empty.
975 * "plContext"
976 * Platform-specific context pointer.
977 * THREAD SAFETY:
978 * Not Thread Safe - assumes exclusive access to "toList"
979 * (see Thread Safety Definitions in Programmer's Guide)
980 * RETURNS:
981 * Returns NULL if the function succeeds
982 * Returns a Fatal Error if the function fails in an unrecoverable way
984 PKIX_Error *
985 pkix_List_AppendUnique(
986 PKIX_List *toList,
987 PKIX_List *fromList,
988 void *plContext)
990 PKIX_Boolean isContained = PKIX_FALSE;
991 PKIX_UInt32 listLen = 0;
992 PKIX_UInt32 listIx = 0;
993 PKIX_PL_Object *object = NULL;
995 PKIX_ENTER(BUILD, "pkix_List_AppendUnique");
996 PKIX_NULLCHECK_TWO(fromList, toList);
998 PKIX_CHECK(PKIX_List_GetLength(fromList, &listLen, plContext),
999 PKIX_LISTGETLENGTHFAILED);
1001 for (listIx = 0; listIx < listLen; listIx++) {
1003 PKIX_CHECK(PKIX_List_GetItem
1004 (fromList, listIx, &object, plContext),
1005 PKIX_LISTGETITEMFAILED);
1007 PKIX_CHECK(pkix_List_Contains
1008 (toList, object, &isContained, plContext),
1009 PKIX_LISTCONTAINSFAILED);
1011 if (isContained == PKIX_FALSE) {
1012 PKIX_CHECK(PKIX_List_AppendItem
1013 (toList, object, plContext),
1014 PKIX_LISTAPPENDITEMFAILED);
1017 PKIX_DECREF(object);
1020 cleanup:
1022 PKIX_DECREF(object);
1024 PKIX_RETURN(LIST);
1028 * FUNCTION: pkix_List_QuickSort
1029 * DESCRIPTION:
1031 * Sorts List of Objects "fromList" using "comparatorCallback"'s result as
1032 * comasrison key and returns the sorted List at "pSortedList". The sorting
1033 * algorithm used is quick sort (n*logn).
1035 * PARAMETERS:
1036 * "fromList"
1037 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
1038 * empty.
1039 * "comparatorCallback"
1040 * Address of callback function that will compare two Objects on the List.
1041 * It should return -1 for less, 0 for equal and 1 for greater. The
1042 * callback implementation chooses what in Objects to be compared. Must be
1043 * non-NULL.
1044 * "pSortedList"
1045 * Address of a List of Objects that shall be sorted and returned. Must be
1046 * non-NULL, but may be empty.
1047 * "plContext"
1048 * Platform-specific context pointer.
1049 * THREAD SAFETY:
1050 * Not Thread Safe - assumes exclusive access to "toList"
1051 * (see Thread Safety Definitions in Programmer's Guide)
1052 * RETURNS:
1053 * Returns NULL if the function succeeds
1054 * Returns a Fatal Error if the function fails in an unrecoverable way
1056 PKIX_Error *
1057 pkix_List_QuickSort(
1058 PKIX_List *fromList,
1059 PKIX_List_SortComparatorCallback comparator,
1060 PKIX_List **pSortedList,
1061 void *plContext)
1063 PKIX_List *sortedList = NULL;
1064 PKIX_List *lessList = NULL;
1065 PKIX_List *greaterList = NULL;
1066 PKIX_List *sortedLessList = NULL;
1067 PKIX_List *sortedGreaterList = NULL;
1068 PKIX_PL_Object *object = NULL;
1069 PKIX_PL_Object *cmpObj = NULL;
1070 PKIX_Int32 cmpResult = 0;
1071 PKIX_UInt32 size = 0;
1072 PKIX_UInt32 i;
1074 PKIX_ENTER(BUILD, "pkix_List_QuickSort");
1075 PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);
1077 PKIX_CHECK(PKIX_List_GetLength(fromList, &size, plContext),
1078 PKIX_LISTGETLENGTHFAILED);
1080 PKIX_CHECK(PKIX_List_Create(&lessList, plContext),
1081 PKIX_LISTCREATEFAILED);
1083 PKIX_CHECK(PKIX_List_Create(&greaterList, plContext),
1084 PKIX_LISTCREATEFAILED);
1086 PKIX_CHECK(PKIX_List_GetItem
1087 (fromList, 0, &object, plContext),
1088 PKIX_LISTGETITEMFAILED);
1091 * Pick the first item on the list as the one to be compared.
1092 * Separate rest of the itmes into two lists: less-than or greater-
1093 * than lists. Sort those two lists recursively. Insert sorted
1094 * less-than list before the picked item and append the greater-
1095 * than list after the picked item.
1097 for (i = 1; i < size; i++) {
1099 PKIX_CHECK(PKIX_List_GetItem
1100 (fromList, i, &cmpObj, plContext),
1101 PKIX_LISTGETITEMFAILED);
1103 PKIX_CHECK(comparator(object, cmpObj, &cmpResult, plContext),
1104 PKIX_COMPARATORCALLBACKFAILED);
1106 if (cmpResult >= 0) {
1107 PKIX_CHECK(PKIX_List_AppendItem
1108 (lessList, cmpObj, plContext),
1109 PKIX_LISTAPPENDITEMFAILED);
1110 } else {
1111 PKIX_CHECK(PKIX_List_AppendItem
1112 (greaterList, cmpObj, plContext),
1113 PKIX_LISTAPPENDITEMFAILED);
1115 PKIX_DECREF(cmpObj);
1118 PKIX_CHECK(PKIX_List_Create(&sortedList, plContext),
1119 PKIX_LISTCREATEFAILED);
1121 PKIX_CHECK(PKIX_List_GetLength(lessList, &size, plContext),
1122 PKIX_LISTGETLENGTHFAILED);
1124 if (size > 1) {
1126 PKIX_CHECK(pkix_List_QuickSort
1127 (lessList, comparator, &sortedLessList, plContext),
1128 PKIX_LISTQUICKSORTFAILED);
1130 PKIX_CHECK(pkix_List_AppendList
1131 (sortedList, sortedLessList, plContext),
1132 PKIX_LISTAPPENDLISTFAILED);
1133 } else {
1134 PKIX_CHECK(pkix_List_AppendList
1135 (sortedList, lessList, plContext),
1136 PKIX_LISTAPPENDLISTFAILED);
1139 PKIX_CHECK(PKIX_List_AppendItem(sortedList, object, plContext),
1140 PKIX_LISTAPPENDFAILED);
1142 PKIX_CHECK(PKIX_List_GetLength(greaterList, &size, plContext),
1143 PKIX_LISTGETLENGTHFAILED);
1145 if (size > 1) {
1147 PKIX_CHECK(pkix_List_QuickSort
1148 (greaterList, comparator, &sortedGreaterList, plContext),
1149 PKIX_LISTQUICKSORTFAILED);
1151 PKIX_CHECK(pkix_List_AppendList
1152 (sortedList, sortedGreaterList, plContext),
1153 PKIX_LISTAPPENDLISTFAILED);
1154 } else {
1155 PKIX_CHECK(pkix_List_AppendList
1156 (sortedList, greaterList, plContext),
1157 PKIX_LISTAPPENDLISTFAILED);
1160 *pSortedList = sortedList;
1162 cleanup:
1164 PKIX_DECREF(cmpObj);
1165 PKIX_DECREF(object);
1166 PKIX_DECREF(sortedGreaterList);
1167 PKIX_DECREF(sortedLessList);
1168 PKIX_DECREF(greaterList);
1169 PKIX_DECREF(lessList);
1171 PKIX_RETURN(LIST);
1175 * FUNCTION: pkix_List_BubbleSort
1176 * DESCRIPTION:
1178 * Sorts List of Objects "fromList" using "comparatorCallback"'s result as
1179 * comasrison key and returns the sorted List at "pSortedList". The sorting
1180 * algorithm used is bubble sort (n*n).
1182 * PARAMETERS:
1183 * "fromList"
1184 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
1185 * empty.
1186 * "comparatorCallback"
1187 * Address of callback function that will compare two Objects on the List.
1188 * It should return -1 for less, 0 for equal and 1 for greater. The
1189 * callback implementation chooses what in Objects to be compared. Must be
1190 * non-NULL.
1191 * "pSortedList"
1192 * Address of a List of Objects that shall be sorted and returned. Must be
1193 * non-NULL, but may be empty.
1194 * "plContext"
1195 * Platform-specific context pointer.
1196 * THREAD SAFETY:
1197 * Not Thread Safe - assumes exclusive access to "toList"
1198 * (see Thread Safety Definitions in Programmer's Guide)
1199 * RETURNS:
1200 * Returns NULL if the function succeeds
1201 * Returns a Fatal Error if the function fails in an unrecoverable way
1203 PKIX_Error *
1204 pkix_List_BubbleSort(
1205 PKIX_List *fromList,
1206 PKIX_List_SortComparatorCallback comparator,
1207 PKIX_List **pSortedList,
1208 void *plContext)
1210 PKIX_List *sortedList = NULL;
1211 PKIX_PL_Object *cmpObj = NULL;
1212 PKIX_PL_Object *leastObj = NULL;
1213 PKIX_Int32 cmpResult = 0;
1214 PKIX_UInt32 size = 0;
1215 PKIX_UInt32 i, j;
1217 PKIX_ENTER(BUILD, "pkix_List_BubbleSort");
1218 PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);
1220 PKIX_CHECK(pkix_List_Duplicate
1221 ((PKIX_PL_Object *) fromList,
1222 (PKIX_PL_Object **) &sortedList,
1223 plContext),
1224 PKIX_LISTDUPLICATEFAILED);
1226 PKIX_CHECK(PKIX_List_GetLength(sortedList, &size, plContext),
1227 PKIX_LISTGETLENGTHFAILED);
1229 if (size > 1) {
1232 * Move from the first of the item on the list, For each iteration,
1233 * compare and swap the least value to the head of the comparisoning
1234 * sub-list.
1236 for (i = 0; i < size - 1; i++) {
1238 PKIX_CHECK(PKIX_List_GetItem
1239 (fromList, i, &leastObj, plContext),
1240 PKIX_LISTGETITEMFAILED);
1242 for (j = i + 1; j < size; j++) {
1244 PKIX_CHECK(PKIX_List_GetItem
1245 (fromList, j, &cmpObj, plContext),
1246 PKIX_LISTGETITEMFAILED);
1248 PKIX_CHECK(comparator
1249 (leastObj, cmpObj, &cmpResult, plContext),
1250 PKIX_COMPARATORCALLBACKFAILED);
1252 if (cmpResult > 0) {
1254 PKIX_CHECK(PKIX_List_SetItem
1255 (sortedList, i, cmpObj, plContext),
1256 PKIX_LISTSETITEMFAILED);
1257 PKIX_CHECK(PKIX_List_SetItem
1258 (sortedList, j, leastObj, plContext),
1259 PKIX_LISTSETITEMFAILED);
1261 PKIX_DECREF(leastObj);
1262 PKIX_INCREF(cmpObj);
1263 leastObj = cmpObj;
1267 PKIX_DECREF(cmpObj);
1270 PKIX_DECREF(leastObj);
1275 *pSortedList = sortedList;
1277 cleanup:
1279 PKIX_DECREF(leastObj);
1280 PKIX_DECREF(cmpObj);
1282 PKIX_RETURN(LIST);
1285 /* --Public-List-Functions--------------------------------------------- */
1288 * FUNCTION: PKIX_List_Create (see comments in pkix_util.h)
1290 PKIX_Error *
1291 PKIX_List_Create(
1292 PKIX_List **pList,
1293 void *plContext)
1295 PKIX_List *list = NULL;
1296 PKIX_Boolean isHeader = PKIX_TRUE;
1298 PKIX_ENTER(LIST, "PKIX_List_Create");
1299 PKIX_NULLCHECK_ONE(pList);
1301 PKIX_CHECK(pkix_List_Create_Internal(isHeader, &list, plContext),
1302 PKIX_LISTCREATEINTERNALFAILED);
1304 *pList = list;
1306 cleanup:
1308 PKIX_RETURN(LIST);
1312 * FUNCTION: PKIX_List_SetImmutable (see comments in pkix_util.h)
1314 PKIX_Error *
1315 PKIX_List_SetImmutable(
1316 PKIX_List *list,
1317 void *plContext)
1319 PKIX_ENTER(LIST, "PKIX_List_SetImmutable");
1320 PKIX_NULLCHECK_ONE(list);
1322 if (!list->isHeader){
1323 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1326 list->immutable = PKIX_TRUE;
1328 cleanup:
1330 PKIX_RETURN(LIST);
1334 * FUNCTION: PKIX_List_IsImmutable (see comments in pkix_util.h)
1336 PKIX_Error *
1337 PKIX_List_IsImmutable(
1338 PKIX_List *list,
1339 PKIX_Boolean *pImmutable,
1340 void *plContext)
1342 PKIX_ENTER(LIST, "PKIX_List_IsImmutable");
1343 PKIX_NULLCHECK_TWO(list, pImmutable);
1345 if (!list->isHeader){
1346 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1349 *pImmutable = list->immutable;
1351 cleanup:
1353 PKIX_RETURN(LIST);
1357 * FUNCTION: PKIX_List_GetLength (see comments in pkix_util.h)
1359 PKIX_Error *
1360 PKIX_List_GetLength(
1361 PKIX_List *list,
1362 PKIX_UInt32 *pLength,
1363 void *plContext)
1365 PKIX_ENTER(LIST, "PKIX_List_GetLength");
1366 PKIX_NULLCHECK_TWO(list, pLength);
1368 if (!list->isHeader){
1369 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1372 *pLength = list->length;
1374 cleanup:
1376 PKIX_RETURN(LIST);
1380 * FUNCTION: PKIX_List_IsEmpty (see comments in pkix_util.h)
1382 PKIX_Error *
1383 PKIX_List_IsEmpty(
1384 PKIX_List *list,
1385 PKIX_Boolean *pEmpty,
1386 void *plContext)
1388 PKIX_UInt32 length;
1390 PKIX_ENTER(LIST, "PKIX_List_IsEmpty");
1391 PKIX_NULLCHECK_TWO(list, pEmpty);
1393 if (!list->isHeader){
1394 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1397 length = list->length;
1399 if (length == 0){
1400 *pEmpty = PKIX_TRUE;
1401 } else {
1402 *pEmpty = PKIX_FALSE;
1405 cleanup:
1407 PKIX_RETURN(LIST);
1411 * FUNCTION: PKIX_List_AppendItem (see comments in pkix_util.h)
1413 PKIX_Error *
1414 PKIX_List_AppendItem(
1415 PKIX_List *list,
1416 PKIX_PL_Object *item,
1417 void *plContext)
1419 PKIX_List *lastElement = NULL;
1420 PKIX_UInt32 length, i;
1422 PKIX_ENTER(LIST, "PKIX_List_AppendItem");
1423 PKIX_NULLCHECK_ONE(list);
1425 if (list->immutable){
1426 PKIX_ERROR(PKIX_CANNOTCALLAPPENDITEMONIMMUTABLELIST);
1429 if (!list->isHeader){
1430 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1433 length = list->length;
1435 /* find last element of list and create new element there */
1437 lastElement = list;
1438 for (i = 0; i < length; i++){
1439 lastElement = lastElement->next;
1442 PKIX_CHECK(pkix_List_Create_Internal
1443 (PKIX_FALSE, &lastElement->next, plContext),
1444 PKIX_LISTCREATEINTERNALFAILED);
1446 PKIX_INCREF(item);
1447 lastElement->next->item = item;
1449 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1450 ((PKIX_PL_Object *)list, plContext),
1451 PKIX_OBJECTINVALIDATECACHEFAILED);
1453 list->length = list->length + 1;
1455 cleanup:
1457 PKIX_RETURN(LIST);
1461 * FUNCTION: PKIX_List_InsertItem (see comments in pkix_util.h)
1463 PKIX_Error *
1464 PKIX_List_InsertItem(
1465 PKIX_List *list,
1466 PKIX_UInt32 index,
1467 PKIX_PL_Object *item,
1468 void *plContext)
1470 PKIX_List *element = NULL;
1471 PKIX_List *newElem = NULL;
1473 PKIX_ENTER(LIST, "PKIX_List_InsertItem");
1474 PKIX_NULLCHECK_ONE(list);
1477 if (list->immutable){
1478 PKIX_ERROR(PKIX_CANNOTCALLINSERTITEMONIMMUTABLELIST);
1481 if (!list->isHeader){
1482 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1485 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1486 PKIX_LISTGETELEMENTFAILED);
1488 /* Create a new list object */
1489 PKIX_CHECK(pkix_List_Create_Internal(PKIX_FALSE, &newElem, plContext),
1490 PKIX_LISTCREATEINTERNALFAILED);
1492 /* Copy the old element's contents into the new element */
1493 newElem->item = element->item;
1495 /* Set the new element's next pointer to the old element's next */
1496 newElem->next = element->next;
1498 /* Set the old element's next pointer to the new element */
1499 element->next = newElem;
1501 PKIX_INCREF(item);
1502 element->item = item;
1504 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1505 ((PKIX_PL_Object *)list, plContext),
1506 PKIX_OBJECTINVALIDATECACHEFAILED);
1508 list->length = list->length + 1;
1510 cleanup:
1512 if (PKIX_ERROR_RECEIVED){
1513 PKIX_DECREF(newElem);
1516 PKIX_RETURN(LIST);
1520 * FUNCTION: PKIX_List_GetItem (see comments in pkix_util.h)
1522 PKIX_Error *
1523 PKIX_List_GetItem(
1524 PKIX_List *list,
1525 PKIX_UInt32 index,
1526 PKIX_PL_Object **pItem,
1527 void *plContext)
1529 PKIX_List *element = NULL;
1531 PKIX_ENTER(LIST, "PKIX_List_GetItem");
1532 PKIX_NULLCHECK_TWO(list, pItem);
1534 if (!list->isHeader){
1535 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1538 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1539 PKIX_LISTGETELEMENTFAILED);
1541 PKIX_INCREF(element->item);
1542 *pItem = element->item;
1544 cleanup:
1546 PKIX_RETURN(LIST);
1550 * FUNCTION: PKIX_List_SetItem (see comments in pkix_util.h)
1552 PKIX_Error *
1553 PKIX_List_SetItem(
1554 PKIX_List *list,
1555 PKIX_UInt32 index,
1556 PKIX_PL_Object *item,
1557 void *plContext)
1559 PKIX_List *element;
1561 PKIX_ENTER(LIST, "PKIX_List_SetItem");
1562 PKIX_NULLCHECK_ONE(list);
1564 if (list->immutable){
1565 PKIX_ERROR(PKIX_CANNOTCALLSETITEMONIMMUTABLELIST);
1568 if (!list->isHeader){
1569 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1572 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1573 PKIX_LISTGETELEMENTFAILED);
1575 /* DecRef old contents */
1576 PKIX_DECREF(element->item);
1578 /* Set New Contents */
1579 PKIX_INCREF(item);
1580 element->item = item;
1582 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1583 ((PKIX_PL_Object *)list, plContext),
1584 PKIX_OBJECTINVALIDATECACHEFAILED);
1586 cleanup:
1588 PKIX_RETURN(LIST);
1592 * FUNCTION: PKIX_List_DeleteItem (see comments in pkix_util.h)
1594 PKIX_Error *
1595 PKIX_List_DeleteItem(
1596 PKIX_List *list,
1597 PKIX_UInt32 index,
1598 void *plContext)
1600 PKIX_List *element = NULL;
1601 PKIX_List *prevElement = NULL;
1602 PKIX_List *nextElement = NULL;
1604 PKIX_ENTER(LIST, "PKIX_List_DeleteItem");
1605 PKIX_NULLCHECK_ONE(list);
1607 if (list->immutable){
1608 PKIX_ERROR(PKIX_CANNOTCALLDELETEITEMONIMMUTABLELIST);
1611 if (!list->isHeader){
1612 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1615 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1616 PKIX_LISTGETELEMENTFAILED);
1618 /* DecRef old contents */
1619 PKIX_DECREF(element->item);
1621 nextElement = element->next;
1623 if (nextElement != NULL) {
1624 /* If the next element exists, splice it out. */
1626 /* Don't need to change ref counts for targets of next */
1627 element->item = nextElement->item;
1628 nextElement->item = NULL;
1630 /* Don't need to change ref counts for targets of next */
1631 element->next = nextElement->next;
1632 nextElement->next = NULL;
1634 PKIX_DECREF(nextElement);
1636 } else { /* The element is at the tail of the list */
1637 if (index != 0) {
1638 PKIX_CHECK(pkix_List_GetElement
1639 (list, index-1, &prevElement, plContext),
1640 PKIX_LISTGETELEMENTFAILED);
1641 } else if (index == 0){ /* prevElement must be header */
1642 prevElement = list;
1644 prevElement->next = NULL;
1646 /* Delete the element */
1647 PKIX_DECREF(element);
1650 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1651 ((PKIX_PL_Object *)list, plContext),
1652 PKIX_OBJECTINVALIDATECACHEFAILED);
1654 list->length = list->length - 1;
1656 cleanup:
1658 PKIX_RETURN(LIST);
1662 * FUNCTION: PKIX_List_ReverseList (see comments in pkix_util.h)
1664 PKIX_Error *
1665 PKIX_List_ReverseList(
1666 PKIX_List *list,
1667 PKIX_List **pReversedList,
1668 void *plContext)
1670 PKIX_List *reversedList = NULL;
1671 PKIX_PL_Object *item = NULL;
1672 PKIX_PL_Object *duplicateItem = NULL;
1673 PKIX_UInt32 length, i;
1675 PKIX_ENTER(LIST, "pkix_List_ReverseList");
1676 PKIX_NULLCHECK_TWO(list, pReversedList);
1678 if (!list->isHeader){
1679 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1682 length = list->length;
1684 /* Create a new list object */
1685 PKIX_CHECK(PKIX_List_Create(&reversedList, plContext),
1686 PKIX_LISTCREATEINTERNALFAILED);
1689 * Starting with the last item and traversing backwards (from
1690 * the original list), append each item to the reversed list
1693 for (i = 1; i <= length; i++){
1694 PKIX_CHECK(PKIX_List_GetItem
1695 (list, (length - i), &item, plContext),
1696 PKIX_LISTGETITEMFAILED);
1698 PKIX_CHECK(PKIX_PL_Object_Duplicate
1699 (item, &duplicateItem, plContext),
1700 PKIX_LISTDUPLICATEFAILED);
1702 PKIX_CHECK(PKIX_List_AppendItem
1703 (reversedList, duplicateItem, plContext),
1704 PKIX_LISTAPPENDITEMFAILED);
1706 PKIX_DECREF(item);
1707 PKIX_DECREF(duplicateItem);
1710 *pReversedList = reversedList;
1712 cleanup:
1714 PKIX_DECREF(item);
1715 PKIX_DECREF(duplicateItem);
1717 if (PKIX_ERROR_RECEIVED){
1718 PKIX_DECREF(reversedList);
1721 PKIX_RETURN(LIST);