nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / lib / libpkix / pkix / util / pkix_list.c
blob7584a1f3b1eb806f8c999067fc20705b680c0b67
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 PKIX-C library.
16 * The Initial Developer of the Original Code is
17 * Sun Microsystems, Inc.
18 * Portions created by the Initial Developer are
19 * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
21 * Contributor(s):
22 * Sun Microsystems, Inc.
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.objCounter = 0;
596 entry.typeObjectSize = sizeof(PKIX_List);
597 entry.destructor = pkix_List_Destroy;
598 entry.equalsFunction = pkix_List_Equals;
599 entry.hashcodeFunction = pkix_List_Hashcode;
600 entry.toStringFunction = pkix_List_ToString;
601 entry.comparator = NULL;
602 entry.duplicateFunction = pkix_List_Duplicate;
604 systemClasses[PKIX_LIST_TYPE] = entry;
606 PKIX_RETURN(LIST);
610 * FUNCTION: pkix_List_Contains
611 * DESCRIPTION:
613 * Checks a List pointed to by "list", to determine whether it includes
614 * an entry that is equal to the Object pointed to by "object", and stores
615 * the result in "pFound".
617 * PARAMETERS:
618 * "list"
619 * List to be searched; may be empty; must be non-NULL
620 * "object"
621 * Object to be checked for; must be non-NULL
622 * "pFound"
623 * Address where the result of the search will be stored. Must
624 * be non-NULL
625 * "plContext"
626 * platform-specific context pointer
627 * THREAD SAFETY:
628 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
629 * RETURNS:
630 * Returns NULL if the function succeeds
631 * Returns a Fatal Error if the function fails in an unrecoverable way
633 PKIX_Error *
634 pkix_List_Contains(
635 PKIX_List *list,
636 PKIX_PL_Object *object,
637 PKIX_Boolean *pFound,
638 void *plContext)
640 PKIX_PL_Object *current = NULL;
641 PKIX_UInt32 numEntries = 0;
642 PKIX_UInt32 index = 0;
643 PKIX_Boolean match = PKIX_FALSE;
645 PKIX_ENTER(LIST, "pkix_List_Contains");
646 PKIX_NULLCHECK_THREE(list, object, pFound);
648 PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext),
649 PKIX_LISTGETLENGTHFAILED);
651 for (index = 0; index < numEntries; index++) {
652 PKIX_CHECK(PKIX_List_GetItem
653 (list, index, &current, plContext),
654 PKIX_LISTGETITEMFAILED);
656 if (current) {
657 PKIX_CHECK(PKIX_PL_Object_Equals
658 (object, current, &match, plContext),
659 PKIX_OBJECTEQUALSFAILED);
661 PKIX_DECREF(current);
664 if (match) {
665 break;
669 *pFound = match;
671 cleanup:
673 PKIX_DECREF(current);
674 PKIX_RETURN(LIST);
678 * FUNCTION: pkix_List_Remove
679 * DESCRIPTION:
681 * Traverses the List pointed to by "list", to find and delete an entry
682 * that is equal to the Object pointed to by "object". If no such entry
683 * is found the function does not return an error.
685 * PARAMETERS:
686 * "list"
687 * List to be searched; may be empty; must be non-NULL
688 * "object"
689 * Object to be checked for and deleted, if found; must be non-NULL
690 * "plContext"
691 * platform-specific context pointer
692 * THREAD SAFETY:
693 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
694 * RETURNS:
695 * Returns NULL if the function succeeds
696 * Returns a Validate Error if the functions fails in a non-fatal way
697 * Returns a Fatal Error if the function fails in an unrecoverable way
699 PKIX_Error *
700 pkix_List_Remove(
701 PKIX_List *list,
702 PKIX_PL_Object *object,
703 void *plContext)
705 PKIX_PL_Object *current = NULL;
706 PKIX_UInt32 numEntries = 0;
707 PKIX_UInt32 index = 0;
708 PKIX_Boolean match = PKIX_FALSE;
710 PKIX_ENTER(LIST, "pkix_List_Remove");
711 PKIX_NULLCHECK_TWO(list, object);
713 PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext),
714 PKIX_LISTGETLENGTHFAILED);
716 for (index = 0; index < numEntries; index++) {
717 PKIX_CHECK(PKIX_List_GetItem
718 (list, index, &current, plContext),
719 PKIX_LISTGETITEMFAILED);
721 if (current) {
722 PKIX_CHECK(PKIX_PL_Object_Equals
723 (object, current, &match, plContext),
724 PKIX_OBJECTEQUALSFAILED);
726 PKIX_DECREF(current);
729 if (match) {
730 PKIX_CHECK(PKIX_List_DeleteItem
731 (list, index, plContext),
732 PKIX_LISTDELETEITEMFAILED);
733 break;
737 cleanup:
739 PKIX_DECREF(current);
740 PKIX_RETURN(LIST);
744 * FUNCTION: pkix_List_RemoveItems
745 * DESCRIPTION:
747 * Traverses the List pointed to by "list", to find and delete an entry
748 * that is equal to the Object in the "deleteList". If no such entry
749 * is found the function does not return an error.
751 * PARAMETERS:
752 * "list"
753 * Object in "list" is checked for object in "deleteList" and deleted if
754 * found; may be empty; must be non-NULL
755 * "deleteList"
756 * List of objects to be searched ; may be empty; must be non-NULL
757 * "plContext"
758 * platform-specific context pointer
759 * THREAD SAFETY:
760 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
761 * RETURNS:
762 * Returns NULL if the function succeeds
763 * Returns a Validate Error if the functions fails in a non-fatal way
764 * Returns a Fatal Error if the function fails in an unrecoverable way
766 PKIX_Error *
767 pkix_List_RemoveItems(
768 PKIX_List *list,
769 PKIX_List *deleteList,
770 void *plContext)
772 PKIX_PL_Object *current = NULL;
773 PKIX_UInt32 numEntries = 0;
774 PKIX_UInt32 index = 0;
776 PKIX_ENTER(LIST, "pkix_List_RemoveItems");
777 PKIX_NULLCHECK_TWO(list, deleteList);
779 PKIX_CHECK(PKIX_List_GetLength(deleteList, &numEntries, plContext),
780 PKIX_LISTGETLENGTHFAILED);
782 for (index = 0; index < numEntries; index++) {
783 PKIX_CHECK(PKIX_List_GetItem
784 (deleteList, index, &current, plContext),
785 PKIX_LISTGETITEMFAILED);
787 if (current) {
788 PKIX_CHECK(pkix_List_Remove
789 (list, current, plContext),
790 PKIX_OBJECTEQUALSFAILED);
792 PKIX_DECREF(current);
796 cleanup:
798 PKIX_DECREF(current);
799 PKIX_RETURN(LIST);
803 * FUNCTION: pkix_List_MergeLists
804 * DESCRIPTION:
806 * Creates a new list consisting of the items from "firstList", followed by
807 * the items on "secondList", returns the new list at "pMergedList". If
808 * both input lists are NULL or empty, the result is an empty list. If an error
809 * occurs, the result is NULL.
811 * PARAMETERS:
812 * "firstList"
813 * Address of list to be merged from. May be NULL or empty.
814 * "secondList"
815 * Address of list to be merged from. May be NULL or empty.
816 * "pMergedList"
817 * Address where returned object is stored.
818 * "plContext"
819 * platform-specific context pointer * THREAD SAFETY:
820 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
821 * RETURNS:
822 * Returns NULL if the function succeeds
823 * Returns a List Error if the functions fails in a non-fatal way
824 * Returns a Fatal Error if the function fails in an unrecoverable way
826 PKIX_Error *
827 pkix_List_MergeLists(
828 PKIX_List *firstList,
829 PKIX_List *secondList,
830 PKIX_List **pMergedList,
831 void *plContext)
833 PKIX_List *list = NULL;
834 PKIX_PL_Object *item = NULL;
835 PKIX_UInt32 numItems = 0;
836 PKIX_UInt32 i;
838 PKIX_ENTER(LIST, "pkix_List_MergeLists");
839 PKIX_NULLCHECK_ONE(pMergedList);
841 *pMergedList = NULL;
843 PKIX_CHECK(PKIX_List_Create(&list, plContext),
844 PKIX_LISTCREATEFAILED);
846 if (firstList != NULL) {
848 PKIX_CHECK(PKIX_List_GetLength(firstList, &numItems, plContext),
849 PKIX_LISTGETLENGTHFAILED);
852 for (i = 0; i < numItems; i++) {
854 PKIX_CHECK(PKIX_List_GetItem(firstList, i, &item, plContext),
855 PKIX_LISTGETITEMFAILED);
857 PKIX_CHECK(PKIX_List_AppendItem(list, item, plContext),
858 PKIX_LISTAPPENDITEMFAILED);
860 PKIX_DECREF(item);
863 numItems = 0;
864 if (secondList != NULL) {
866 PKIX_CHECK(PKIX_List_GetLength
867 (secondList,
868 &numItems,
869 plContext),
870 PKIX_LISTGETLENGTHFAILED);
874 for (i = 0; i < numItems; i++) {
876 PKIX_CHECK(PKIX_List_GetItem
877 (secondList, i, &item, plContext),
878 PKIX_LISTGETITEMFAILED);
880 PKIX_CHECK(PKIX_List_AppendItem
881 (list, item, plContext), PKIX_LISTAPPENDITEMFAILED);
883 PKIX_DECREF(item);
886 *pMergedList = list;
888 cleanup:
890 if (PKIX_ERROR_RECEIVED){
891 PKIX_DECREF(list);
894 PKIX_RETURN(LIST);
898 * FUNCTION: pkix_List_AppendList
899 * DESCRIPTION:
901 * Append items on "fromList" to the "toList". Item reference count on
902 * "toList" is not incremented, but items appended from "fromList" are
903 * incremented.
905 * PARAMETERS:
906 * "toList"
907 * Address of list to be appended to. Must be non-NULL.
908 * "fromList"
909 * Address of list to be appended from. May be NULL or empty.
910 * "plContext"
911 * platform-specific context pointer
912 * THREAD SAFETY:
913 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
914 * RETURNS:
915 * Returns NULL if the function succeeds
916 * Returns a List Error if the functions fails in a non-fatal way
917 * Returns a Fatal Error if the function fails in an unrecoverable way
919 PKIX_Error *
920 pkix_List_AppendList(
921 PKIX_List *toList,
922 PKIX_List *fromList,
923 void *plContext)
925 PKIX_PL_Object *item = NULL;
926 PKIX_UInt32 numItems = 0;
927 PKIX_UInt32 i;
929 PKIX_ENTER(LIST, "pkix_List_AppendList");
930 PKIX_NULLCHECK_ONE(toList);
932 /* if fromList is NULL or is an empty list, no action */
934 if (fromList == NULL) {
935 goto cleanup;
938 PKIX_CHECK(PKIX_List_GetLength(fromList, &numItems, plContext),
939 PKIX_LISTGETLENGTHFAILED);
941 if (numItems == 0) {
942 goto cleanup;
945 for (i = 0; i < numItems; i++) {
947 PKIX_CHECK(PKIX_List_GetItem
948 (fromList, i, &item, plContext),
949 PKIX_LISTGETITEMFAILED);
951 PKIX_CHECK(PKIX_List_AppendItem(toList, item, plContext),
952 PKIX_LISTAPPENDITEMFAILED);
954 PKIX_DECREF(item);
957 cleanup:
959 PKIX_RETURN(LIST);
963 * FUNCTION: pkix_List_AppendUnique
964 * DESCRIPTION:
966 * Adds each Object in the List pointed to by "fromList" to the List pointed
967 * to by "toList", if it is not already a member of that List. In other words,
968 * "toList" becomes the union of the two sets.
970 * PARAMETERS:
971 * "toList"
972 * Address of a List of Objects to be augmented by "fromList". Must be
973 * non-NULL, but may be empty.
974 * "fromList"
975 * Address of a List of Objects to be added, if not already present, to
976 * "toList". Must be non-NULL, but may be empty.
977 * "plContext"
978 * Platform-specific context pointer.
979 * THREAD SAFETY:
980 * Not Thread Safe - assumes exclusive access to "toList"
981 * (see Thread Safety Definitions in Programmer's Guide)
982 * RETURNS:
983 * Returns NULL if the function succeeds
984 * Returns a Fatal Error if the function fails in an unrecoverable way
986 PKIX_Error *
987 pkix_List_AppendUnique(
988 PKIX_List *toList,
989 PKIX_List *fromList,
990 void *plContext)
992 PKIX_Boolean isContained = PKIX_FALSE;
993 PKIX_UInt32 listLen = 0;
994 PKIX_UInt32 listIx = 0;
995 PKIX_PL_Object *object = NULL;
997 PKIX_ENTER(BUILD, "pkix_List_AppendUnique");
998 PKIX_NULLCHECK_TWO(fromList, toList);
1000 PKIX_CHECK(PKIX_List_GetLength(fromList, &listLen, plContext),
1001 PKIX_LISTGETLENGTHFAILED);
1003 for (listIx = 0; listIx < listLen; listIx++) {
1005 PKIX_CHECK(PKIX_List_GetItem
1006 (fromList, listIx, &object, plContext),
1007 PKIX_LISTGETITEMFAILED);
1009 PKIX_CHECK(pkix_List_Contains
1010 (toList, object, &isContained, plContext),
1011 PKIX_LISTCONTAINSFAILED);
1013 if (isContained == PKIX_FALSE) {
1014 PKIX_CHECK(PKIX_List_AppendItem
1015 (toList, object, plContext),
1016 PKIX_LISTAPPENDITEMFAILED);
1019 PKIX_DECREF(object);
1022 cleanup:
1024 PKIX_DECREF(object);
1026 PKIX_RETURN(LIST);
1030 * FUNCTION: pkix_List_QuickSort
1031 * DESCRIPTION:
1033 * Sorts List of Objects "fromList" using "comparatorCallback"'s result as
1034 * comasrison key and returns the sorted List at "pSortedList". The sorting
1035 * algorithm used is quick sort (n*logn).
1037 * PARAMETERS:
1038 * "fromList"
1039 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
1040 * empty.
1041 * "comparatorCallback"
1042 * Address of callback function that will compare two Objects on the List.
1043 * It should return -1 for less, 0 for equal and 1 for greater. The
1044 * callback implementation chooses what in Objects to be compared. Must be
1045 * non-NULL.
1046 * "pSortedList"
1047 * Address of a List of Objects that shall be sorted and returned. Must be
1048 * non-NULL, but may be empty.
1049 * "plContext"
1050 * Platform-specific context pointer.
1051 * THREAD SAFETY:
1052 * Not Thread Safe - assumes exclusive access to "toList"
1053 * (see Thread Safety Definitions in Programmer's Guide)
1054 * RETURNS:
1055 * Returns NULL if the function succeeds
1056 * Returns a Fatal Error if the function fails in an unrecoverable way
1058 PKIX_Error *
1059 pkix_List_QuickSort(
1060 PKIX_List *fromList,
1061 PKIX_List_SortComparatorCallback comparator,
1062 PKIX_List **pSortedList,
1063 void *plContext)
1065 PKIX_List *sortedList = NULL;
1066 PKIX_List *lessList = NULL;
1067 PKIX_List *greaterList = NULL;
1068 PKIX_List *sortedLessList = NULL;
1069 PKIX_List *sortedGreaterList = NULL;
1070 PKIX_PL_Object *object = NULL;
1071 PKIX_PL_Object *cmpObj = NULL;
1072 PKIX_Int32 cmpResult = 0;
1073 PKIX_UInt32 size = 0;
1074 PKIX_UInt32 i;
1076 PKIX_ENTER(BUILD, "pkix_List_QuickSort");
1077 PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);
1079 PKIX_CHECK(PKIX_List_GetLength(fromList, &size, plContext),
1080 PKIX_LISTGETLENGTHFAILED);
1082 PKIX_CHECK(PKIX_List_Create(&lessList, plContext),
1083 PKIX_LISTCREATEFAILED);
1085 PKIX_CHECK(PKIX_List_Create(&greaterList, plContext),
1086 PKIX_LISTCREATEFAILED);
1088 PKIX_CHECK(PKIX_List_GetItem
1089 (fromList, 0, &object, plContext),
1090 PKIX_LISTGETITEMFAILED);
1093 * Pick the first item on the list as the one to be compared.
1094 * Separate rest of the itmes into two lists: less-than or greater-
1095 * than lists. Sort those two lists recursively. Insert sorted
1096 * less-than list before the picked item and append the greater-
1097 * than list after the picked item.
1099 for (i = 1; i < size; i++) {
1101 PKIX_CHECK(PKIX_List_GetItem
1102 (fromList, i, &cmpObj, plContext),
1103 PKIX_LISTGETITEMFAILED);
1105 PKIX_CHECK(comparator(object, cmpObj, &cmpResult, plContext),
1106 PKIX_COMPARATORCALLBACKFAILED);
1108 if (cmpResult >= 0) {
1109 PKIX_CHECK(PKIX_List_AppendItem
1110 (lessList, cmpObj, plContext),
1111 PKIX_LISTAPPENDITEMFAILED);
1112 } else {
1113 PKIX_CHECK(PKIX_List_AppendItem
1114 (greaterList, cmpObj, plContext),
1115 PKIX_LISTAPPENDITEMFAILED);
1117 PKIX_DECREF(cmpObj);
1120 PKIX_CHECK(PKIX_List_Create(&sortedList, plContext),
1121 PKIX_LISTCREATEFAILED);
1123 PKIX_CHECK(PKIX_List_GetLength(lessList, &size, plContext),
1124 PKIX_LISTGETLENGTHFAILED);
1126 if (size > 1) {
1128 PKIX_CHECK(pkix_List_QuickSort
1129 (lessList, comparator, &sortedLessList, plContext),
1130 PKIX_LISTQUICKSORTFAILED);
1132 PKIX_CHECK(pkix_List_AppendList
1133 (sortedList, sortedLessList, plContext),
1134 PKIX_LISTAPPENDLISTFAILED);
1135 } else {
1136 PKIX_CHECK(pkix_List_AppendList
1137 (sortedList, lessList, plContext),
1138 PKIX_LISTAPPENDLISTFAILED);
1141 PKIX_CHECK(PKIX_List_AppendItem(sortedList, object, plContext),
1142 PKIX_LISTAPPENDFAILED);
1144 PKIX_CHECK(PKIX_List_GetLength(greaterList, &size, plContext),
1145 PKIX_LISTGETLENGTHFAILED);
1147 if (size > 1) {
1149 PKIX_CHECK(pkix_List_QuickSort
1150 (greaterList, comparator, &sortedGreaterList, plContext),
1151 PKIX_LISTQUICKSORTFAILED);
1153 PKIX_CHECK(pkix_List_AppendList
1154 (sortedList, sortedGreaterList, plContext),
1155 PKIX_LISTAPPENDLISTFAILED);
1156 } else {
1157 PKIX_CHECK(pkix_List_AppendList
1158 (sortedList, greaterList, plContext),
1159 PKIX_LISTAPPENDLISTFAILED);
1162 *pSortedList = sortedList;
1164 cleanup:
1166 PKIX_DECREF(cmpObj);
1167 PKIX_DECREF(object);
1168 PKIX_DECREF(sortedGreaterList);
1169 PKIX_DECREF(sortedLessList);
1170 PKIX_DECREF(greaterList);
1171 PKIX_DECREF(lessList);
1173 PKIX_RETURN(LIST);
1177 * FUNCTION: pkix_List_BubbleSort
1178 * DESCRIPTION:
1180 * Sorts List of Objects "fromList" using "comparatorCallback"'s result as
1181 * comasrison key and returns the sorted List at "pSortedList". The sorting
1182 * algorithm used is bubble sort (n*n).
1184 * PARAMETERS:
1185 * "fromList"
1186 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
1187 * empty.
1188 * "comparatorCallback"
1189 * Address of callback function that will compare two Objects on the List.
1190 * It should return -1 for less, 0 for equal and 1 for greater. The
1191 * callback implementation chooses what in Objects to be compared. Must be
1192 * non-NULL.
1193 * "pSortedList"
1194 * Address of a List of Objects that shall be sorted and returned. Must be
1195 * non-NULL, but may be empty.
1196 * "plContext"
1197 * Platform-specific context pointer.
1198 * THREAD SAFETY:
1199 * Not Thread Safe - assumes exclusive access to "toList"
1200 * (see Thread Safety Definitions in Programmer's Guide)
1201 * RETURNS:
1202 * Returns NULL if the function succeeds
1203 * Returns a Fatal Error if the function fails in an unrecoverable way
1205 PKIX_Error *
1206 pkix_List_BubbleSort(
1207 PKIX_List *fromList,
1208 PKIX_List_SortComparatorCallback comparator,
1209 PKIX_List **pSortedList,
1210 void *plContext)
1212 PKIX_List *sortedList = NULL;
1213 PKIX_PL_Object *cmpObj = NULL;
1214 PKIX_PL_Object *leastObj = NULL;
1215 PKIX_Int32 cmpResult = 0;
1216 PKIX_UInt32 size = 0;
1217 PKIX_UInt32 i, j;
1219 PKIX_ENTER(BUILD, "pkix_List_BubbleSort");
1220 PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);
1222 PKIX_CHECK(pkix_List_Duplicate
1223 ((PKIX_PL_Object *) fromList,
1224 (PKIX_PL_Object **) &sortedList,
1225 plContext),
1226 PKIX_LISTDUPLICATEFAILED);
1228 PKIX_CHECK(PKIX_List_GetLength(sortedList, &size, plContext),
1229 PKIX_LISTGETLENGTHFAILED);
1231 if (size > 1) {
1234 * Move from the first of the item on the list, For each iteration,
1235 * compare and swap the least value to the head of the comparisoning
1236 * sub-list.
1238 for (i = 0; i < size - 1; i++) {
1240 PKIX_CHECK(PKIX_List_GetItem
1241 (fromList, i, &leastObj, plContext),
1242 PKIX_LISTGETITEMFAILED);
1244 for (j = i + 1; j < size; j++) {
1246 PKIX_CHECK(PKIX_List_GetItem
1247 (fromList, j, &cmpObj, plContext),
1248 PKIX_LISTGETITEMFAILED);
1250 PKIX_CHECK(comparator
1251 (leastObj, cmpObj, &cmpResult, plContext),
1252 PKIX_COMPARATORCALLBACKFAILED);
1254 if (cmpResult > 0) {
1256 PKIX_CHECK(PKIX_List_SetItem
1257 (sortedList, i, cmpObj, plContext),
1258 PKIX_LISTSETITEMFAILED);
1259 PKIX_CHECK(PKIX_List_SetItem
1260 (sortedList, j, leastObj, plContext),
1261 PKIX_LISTSETITEMFAILED);
1263 PKIX_DECREF(leastObj);
1264 PKIX_INCREF(cmpObj);
1265 leastObj = cmpObj;
1269 PKIX_DECREF(cmpObj);
1272 PKIX_DECREF(leastObj);
1277 *pSortedList = sortedList;
1279 cleanup:
1281 PKIX_DECREF(leastObj);
1282 PKIX_DECREF(cmpObj);
1284 PKIX_RETURN(LIST);
1287 /* --Public-List-Functions--------------------------------------------- */
1290 * FUNCTION: PKIX_List_Create (see comments in pkix_util.h)
1292 PKIX_Error *
1293 PKIX_List_Create(
1294 PKIX_List **pList,
1295 void *plContext)
1297 PKIX_List *list = NULL;
1298 PKIX_Boolean isHeader = PKIX_TRUE;
1300 PKIX_ENTER(LIST, "PKIX_List_Create");
1301 PKIX_NULLCHECK_ONE(pList);
1303 PKIX_CHECK(pkix_List_Create_Internal(isHeader, &list, plContext),
1304 PKIX_LISTCREATEINTERNALFAILED);
1306 *pList = list;
1308 cleanup:
1310 PKIX_RETURN(LIST);
1314 * FUNCTION: PKIX_List_SetImmutable (see comments in pkix_util.h)
1316 PKIX_Error *
1317 PKIX_List_SetImmutable(
1318 PKIX_List *list,
1319 void *plContext)
1321 PKIX_ENTER(LIST, "PKIX_List_SetImmutable");
1322 PKIX_NULLCHECK_ONE(list);
1324 if (!list->isHeader){
1325 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1328 list->immutable = PKIX_TRUE;
1330 cleanup:
1332 PKIX_RETURN(LIST);
1336 * FUNCTION: PKIX_List_IsImmutable (see comments in pkix_util.h)
1338 PKIX_Error *
1339 PKIX_List_IsImmutable(
1340 PKIX_List *list,
1341 PKIX_Boolean *pImmutable,
1342 void *plContext)
1344 PKIX_ENTER(LIST, "PKIX_List_IsImmutable");
1345 PKIX_NULLCHECK_TWO(list, pImmutable);
1347 if (!list->isHeader){
1348 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1351 *pImmutable = list->immutable;
1353 cleanup:
1355 PKIX_RETURN(LIST);
1359 * FUNCTION: PKIX_List_GetLength (see comments in pkix_util.h)
1361 PKIX_Error *
1362 PKIX_List_GetLength(
1363 PKIX_List *list,
1364 PKIX_UInt32 *pLength,
1365 void *plContext)
1367 PKIX_ENTER(LIST, "PKIX_List_GetLength");
1368 PKIX_NULLCHECK_TWO(list, pLength);
1370 if (!list->isHeader){
1371 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1374 *pLength = list->length;
1376 cleanup:
1378 PKIX_RETURN(LIST);
1382 * FUNCTION: PKIX_List_IsEmpty (see comments in pkix_util.h)
1384 PKIX_Error *
1385 PKIX_List_IsEmpty(
1386 PKIX_List *list,
1387 PKIX_Boolean *pEmpty,
1388 void *plContext)
1390 PKIX_UInt32 length;
1392 PKIX_ENTER(LIST, "PKIX_List_IsEmpty");
1393 PKIX_NULLCHECK_TWO(list, pEmpty);
1395 if (!list->isHeader){
1396 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1399 length = list->length;
1401 if (length == 0){
1402 *pEmpty = PKIX_TRUE;
1403 } else {
1404 *pEmpty = PKIX_FALSE;
1407 cleanup:
1409 PKIX_RETURN(LIST);
1413 * FUNCTION: PKIX_List_AppendItem (see comments in pkix_util.h)
1415 PKIX_Error *
1416 PKIX_List_AppendItem(
1417 PKIX_List *list,
1418 PKIX_PL_Object *item,
1419 void *plContext)
1421 PKIX_List *lastElement = NULL;
1422 PKIX_UInt32 length, i;
1424 PKIX_ENTER(LIST, "PKIX_List_AppendItem");
1425 PKIX_NULLCHECK_ONE(list);
1427 if (list->immutable){
1428 PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
1431 if (!list->isHeader){
1432 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1435 length = list->length;
1437 /* find last element of list and create new element there */
1439 lastElement = list;
1440 for (i = 0; i < length; i++){
1441 lastElement = lastElement->next;
1444 PKIX_CHECK(pkix_List_Create_Internal
1445 (PKIX_FALSE, &lastElement->next, plContext),
1446 PKIX_LISTCREATEINTERNALFAILED);
1448 PKIX_INCREF(item);
1449 lastElement->next->item = item;
1451 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1452 ((PKIX_PL_Object *)list, plContext),
1453 PKIX_OBJECTINVALIDATECACHEFAILED);
1455 list->length = list->length + 1;
1457 cleanup:
1459 PKIX_RETURN(LIST);
1463 * FUNCTION: PKIX_List_InsertItem (see comments in pkix_util.h)
1465 PKIX_Error *
1466 PKIX_List_InsertItem(
1467 PKIX_List *list,
1468 PKIX_UInt32 index,
1469 PKIX_PL_Object *item,
1470 void *plContext)
1472 PKIX_List *element = NULL;
1473 PKIX_List *newElem = NULL;
1475 PKIX_ENTER(LIST, "PKIX_List_InsertItem");
1476 PKIX_NULLCHECK_ONE(list);
1479 if (list->immutable){
1480 PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
1483 if (!list->isHeader){
1484 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1487 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1488 PKIX_LISTGETELEMENTFAILED);
1490 /* Create a new list object */
1491 PKIX_CHECK(pkix_List_Create_Internal(PKIX_FALSE, &newElem, plContext),
1492 PKIX_LISTCREATEINTERNALFAILED);
1494 /* Copy the old element's contents into the new element */
1495 newElem->item = element->item;
1497 /* Set the new element's next pointer to the old element's next */
1498 newElem->next = element->next;
1500 /* Set the old element's next pointer to the new element */
1501 element->next = newElem;
1503 PKIX_INCREF(item);
1504 element->item = item;
1506 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1507 ((PKIX_PL_Object *)list, plContext),
1508 PKIX_OBJECTINVALIDATECACHEFAILED);
1510 list->length = list->length + 1;
1512 cleanup:
1514 if (PKIX_ERROR_RECEIVED){
1515 PKIX_DECREF(newElem);
1518 PKIX_RETURN(LIST);
1522 * FUNCTION: PKIX_List_GetItem (see comments in pkix_util.h)
1524 PKIX_Error *
1525 PKIX_List_GetItem(
1526 PKIX_List *list,
1527 PKIX_UInt32 index,
1528 PKIX_PL_Object **pItem,
1529 void *plContext)
1531 PKIX_List *element = NULL;
1533 PKIX_ENTER(LIST, "PKIX_List_GetItem");
1534 PKIX_NULLCHECK_TWO(list, pItem);
1536 if (!list->isHeader){
1537 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1540 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1541 PKIX_LISTGETELEMENTFAILED);
1543 PKIX_INCREF(element->item);
1544 *pItem = element->item;
1546 cleanup:
1548 PKIX_RETURN(LIST);
1552 * FUNCTION: PKIX_List_SetItem (see comments in pkix_util.h)
1554 PKIX_Error *
1555 PKIX_List_SetItem(
1556 PKIX_List *list,
1557 PKIX_UInt32 index,
1558 PKIX_PL_Object *item,
1559 void *plContext)
1561 PKIX_List *element;
1563 PKIX_ENTER(LIST, "PKIX_List_SetItem");
1564 PKIX_NULLCHECK_ONE(list);
1566 if (list->immutable){
1567 PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
1570 if (!list->isHeader){
1571 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1574 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1575 PKIX_LISTGETELEMENTFAILED);
1577 /* DecRef old contents */
1578 PKIX_DECREF(element->item);
1580 /* Set New Contents */
1581 PKIX_INCREF(item);
1582 element->item = item;
1584 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1585 ((PKIX_PL_Object *)list, plContext),
1586 PKIX_OBJECTINVALIDATECACHEFAILED);
1588 cleanup:
1590 PKIX_RETURN(LIST);
1594 * FUNCTION: PKIX_List_DeleteItem (see comments in pkix_util.h)
1596 PKIX_Error *
1597 PKIX_List_DeleteItem(
1598 PKIX_List *list,
1599 PKIX_UInt32 index,
1600 void *plContext)
1602 PKIX_List *element = NULL;
1603 PKIX_List *prevElement = NULL;
1604 PKIX_List *nextElement = NULL;
1606 PKIX_ENTER(LIST, "PKIX_List_DeleteItem");
1607 PKIX_NULLCHECK_ONE(list);
1609 if (list->immutable){
1610 PKIX_ERROR(PKIX_OPERATIONNOTPERMITTEDONIMMUTABLELIST);
1613 if (!list->isHeader){
1614 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1617 PKIX_CHECK(pkix_List_GetElement(list, index, &element, plContext),
1618 PKIX_LISTGETELEMENTFAILED);
1620 /* DecRef old contents */
1621 PKIX_DECREF(element->item);
1623 nextElement = element->next;
1625 if (nextElement != NULL) {
1626 /* If the next element exists, splice it out. */
1628 /* Don't need to change ref counts for targets of next */
1629 element->item = nextElement->item;
1630 nextElement->item = NULL;
1632 /* Don't need to change ref counts for targets of next */
1633 element->next = nextElement->next;
1634 nextElement->next = NULL;
1636 PKIX_DECREF(nextElement);
1638 } else { /* The element is at the tail of the list */
1639 if (index != 0) {
1640 PKIX_CHECK(pkix_List_GetElement
1641 (list, index-1, &prevElement, plContext),
1642 PKIX_LISTGETELEMENTFAILED);
1643 } else if (index == 0){ /* prevElement must be header */
1644 prevElement = list;
1646 prevElement->next = NULL;
1648 /* Delete the element */
1649 PKIX_DECREF(element);
1652 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1653 ((PKIX_PL_Object *)list, plContext),
1654 PKIX_OBJECTINVALIDATECACHEFAILED);
1656 list->length = list->length - 1;
1658 cleanup:
1660 PKIX_RETURN(LIST);
1664 * FUNCTION: PKIX_List_ReverseList (see comments in pkix_util.h)
1666 PKIX_Error *
1667 PKIX_List_ReverseList(
1668 PKIX_List *list,
1669 PKIX_List **pReversedList,
1670 void *plContext)
1672 PKIX_List *reversedList = NULL;
1673 PKIX_PL_Object *item = NULL;
1674 PKIX_PL_Object *duplicateItem = NULL;
1675 PKIX_UInt32 length, i;
1677 PKIX_ENTER(LIST, "pkix_List_ReverseList");
1678 PKIX_NULLCHECK_TWO(list, pReversedList);
1680 if (!list->isHeader){
1681 PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
1684 length = list->length;
1686 /* Create a new list object */
1687 PKIX_CHECK(PKIX_List_Create(&reversedList, plContext),
1688 PKIX_LISTCREATEINTERNALFAILED);
1691 * Starting with the last item and traversing backwards (from
1692 * the original list), append each item to the reversed list
1695 for (i = 1; i <= length; i++){
1696 PKIX_CHECK(PKIX_List_GetItem
1697 (list, (length - i), &item, plContext),
1698 PKIX_LISTGETITEMFAILED);
1700 PKIX_CHECK(PKIX_PL_Object_Duplicate
1701 (item, &duplicateItem, plContext),
1702 PKIX_LISTDUPLICATEFAILED);
1704 PKIX_CHECK(PKIX_List_AppendItem
1705 (reversedList, duplicateItem, plContext),
1706 PKIX_LISTAPPENDITEMFAILED);
1708 PKIX_DECREF(item);
1709 PKIX_DECREF(duplicateItem);
1712 *pReversedList = reversedList;
1714 cleanup:
1716 PKIX_DECREF(item);
1717 PKIX_DECREF(duplicateItem);
1719 if (PKIX_ERROR_RECEIVED){
1720 PKIX_DECREF(reversedList);
1723 PKIX_RETURN(LIST);