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
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.
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 ***** */
40 * List Object Functions
44 #include "pkix_list.h"
46 /* --Private-Functions-------------------------------------------- */
49 * FUNCTION: pkix_List_Create_Internal
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.
59 * Boolean value indicating whether new List should be a header.
61 * Address where object pointer will be stored. Must be non-NULL.
63 * Platform-specific context pointer.
65 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
67 * Returns NULL if the function succeeds.
68 * Returns a Fatal Error if the function fails in an unrecoverable way.
71 pkix_List_Create_Internal(
72 PKIX_Boolean isHeader
,
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
83 ((PKIX_UInt32
)(sizeof (PKIX_List
))),
84 (PKIX_PL_Object
**)&list
, plContext
),
85 PKIX_ERRORCREATINGLISTITEM
);
89 list
->immutable
= PKIX_FALSE
;
91 list
->isHeader
= isHeader
;
101 * FUNCTION: pkix_List_Destroy
102 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
106 PKIX_PL_Object
*object
,
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
),
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
;
125 list
->isHeader
= PKIX_FALSE
;
133 * FUNCTION: pkix_List_ToString_Helper
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".
141 * Address of List whose string representation is desired.
144 * Address of object pointer's destination. Must be non-NULL.
146 * Platform-specific context pointer.
148 * Conditionally Thread Safe
149 * (see Thread Safety Definitions in Programmer's Guide)
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.
156 pkix_List_ToString_Helper(
158 PKIX_PL_String
**pString
,
161 PKIX_PL_String
*itemString
= NULL
;
162 PKIX_PL_String
*nextString
= NULL
;
163 PKIX_PL_String
*format
= NULL
;
166 PKIX_ENTER(LIST
, "pkix_List_ToString_Helper");
167 PKIX_NULLCHECK_TWO(list
, pString
);
169 /* special case when list is the header */
172 PKIX_CHECK(PKIX_List_IsEmpty(list
, &empty
, plContext
),
173 PKIX_LISTISEMPTYFAILED
);
176 PKIX_CHECK(PKIX_PL_String_Create
182 PKIX_ERRORCREATINGITEMSTRING
);
183 (*pString
) = itemString
;
184 PKIX_DEBUG_EXIT(LIST
);
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
),
201 /* Get a string for this list's item */
202 if (list
->item
== NULL
) {
203 PKIX_CHECK(PKIX_PL_String_Create
209 PKIX_STRINGCREATEFAILED
);
211 PKIX_CHECK(PKIX_PL_Object_ToString
212 ((PKIX_PL_Object
*)list
->item
,
215 PKIX_OBJECTTOSTRINGFAILED
);
217 if (list
->next
== NULL
) {
218 /* Just return the itemstring */
219 (*pString
) = itemString
;
220 PKIX_DEBUG_EXIT(LIST
);
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
236 PKIX_STRINGCREATEFAILED
);
238 PKIX_CHECK(PKIX_PL_Sprintf
249 PKIX_DECREF(itemString
);
250 PKIX_DECREF(nextString
);
257 * FUNCTION: pkix_List_ToString
258 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
262 PKIX_PL_Object
*object
,
263 PKIX_PL_String
**pString
,
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
),
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
),
294 PKIX_DECREF(listString
);
301 * FUNCTION: pkix_List_Equals
302 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
306 PKIX_PL_Object
*first
,
307 PKIX_PL_Object
*second
,
308 PKIX_Boolean
*pResult
,
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
;
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
;
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
);
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
){
375 PKIX_CHECK(PKIX_PL_Object_Equals
380 PKIX_OBJECTEQUALSFAILED
);
382 PKIX_DECREF(firstItem
);
383 PKIX_DECREF(secondItem
);
388 *pResult
= cmpResult
;
392 PKIX_DECREF(firstItem
);
393 PKIX_DECREF(secondItem
);
399 * FUNCTION: pkix_List_Hashcode
400 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
404 PKIX_PL_Object
*object
,
405 PKIX_UInt32
*pHashcode
,
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
),
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
);
435 PKIX_CHECK(PKIX_PL_Object_Hashcode
436 (element
, &tempHash
, plContext
),
437 PKIX_LISTHASHCODEFAILED
);
440 hash
= 31 * hash
+ tempHash
;
442 PKIX_DECREF(element
);
449 PKIX_DECREF(element
);
454 * FUNCTION: pkix_List_Duplicate
455 * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h)
459 PKIX_PL_Object
*object
,
460 PKIX_PL_Object
**pNewObject
,
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
),
472 list
= (PKIX_List
*)object
;
474 if (list
->immutable
){
475 PKIX_CHECK(pkix_duplicateImmutable
476 (object
, pNewObject
, plContext
),
477 PKIX_DUPLICATEIMMUTABLEFAILED
);
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
;
492 /* Recursively Duplicate list */
493 PKIX_CHECK(pkix_List_Duplicate
494 ((PKIX_PL_Object
*)list
->next
,
495 (PKIX_PL_Object
**)&listDuplicate
->next
,
497 PKIX_LISTDUPLICATEFAILED
);
500 *pNewObject
= (PKIX_PL_Object
*)listDuplicate
;
505 if (PKIX_ERROR_RECEIVED
){
506 PKIX_DECREF(listDuplicate
);
514 * FUNCTION: pkix_List_GetElement
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
526 * Address of List (must be header) to get element from. Must be non-NULL.
528 * Index of list to get element from. Must be less than List's length.
530 * Address where object pointer will be stored. Must be non-NULL.
532 * Platform-specific context pointer.
534 * Conditionally Thread Safe
535 * (see Thread Safety Definitions in Programmer's Guide)
537 * Returns NULL if the function succeeds.
538 * Returns a Fatal Error if the function fails in an unrecoverable way.
541 pkix_List_GetElement(
544 PKIX_List
**pElement
,
547 PKIX_List
*iterator
= NULL
;
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
;
576 * FUNCTION: pkix_List_RegisterSelf
578 * Registers PKIX_LIST_TYPE and its related functions with systemClasses[]
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
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
;
608 * FUNCTION: pkix_List_Contains
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".
617 * List to be searched; may be empty; must be non-NULL
619 * Object to be checked for; must be non-NULL
621 * Address where the result of the search will be stored. Must
624 * platform-specific context pointer
626 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
628 * Returns NULL if the function succeeds
629 * Returns a Fatal Error if the function fails in an unrecoverable way
634 PKIX_PL_Object
*object
,
635 PKIX_Boolean
*pFound
,
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
, ¤t
, plContext
),
652 PKIX_LISTGETITEMFAILED
);
655 PKIX_CHECK(PKIX_PL_Object_Equals
656 (object
, current
, &match
, plContext
),
657 PKIX_OBJECTEQUALSFAILED
);
659 PKIX_DECREF(current
);
671 PKIX_DECREF(current
);
676 * FUNCTION: pkix_List_Remove
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.
685 * List to be searched; may be empty; must be non-NULL
687 * Object to be checked for and deleted, if found; must be non-NULL
689 * platform-specific context pointer
691 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
700 PKIX_PL_Object
*object
,
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
, ¤t
, plContext
),
717 PKIX_LISTGETITEMFAILED
);
720 PKIX_CHECK(PKIX_PL_Object_Equals
721 (object
, current
, &match
, plContext
),
722 PKIX_OBJECTEQUALSFAILED
);
724 PKIX_DECREF(current
);
728 PKIX_CHECK(PKIX_List_DeleteItem
729 (list
, index
, plContext
),
730 PKIX_LISTDELETEITEMFAILED
);
737 PKIX_DECREF(current
);
742 * FUNCTION: pkix_List_RemoveItems
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.
751 * Object in "list" is checked for object in "deleteList" and deleted if
752 * found; may be empty; must be non-NULL
754 * List of objects to be searched ; may be empty; must be non-NULL
756 * platform-specific context pointer
758 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
765 pkix_List_RemoveItems(
767 PKIX_List
*deleteList
,
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
, ¤t
, plContext
),
783 PKIX_LISTGETITEMFAILED
);
786 PKIX_CHECK(pkix_List_Remove
787 (list
, current
, plContext
),
788 PKIX_OBJECTEQUALSFAILED
);
790 PKIX_DECREF(current
);
796 PKIX_DECREF(current
);
801 * FUNCTION: pkix_List_MergeLists
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.
811 * Address of list to be merged from. May be NULL or empty.
813 * Address of list to be merged from. May be NULL or empty.
815 * Address where returned object is stored.
817 * platform-specific context pointer * THREAD SAFETY:
818 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
825 pkix_List_MergeLists(
826 PKIX_List
*firstList
,
827 PKIX_List
*secondList
,
828 PKIX_List
**pMergedList
,
831 PKIX_List
*list
= NULL
;
832 PKIX_PL_Object
*item
= NULL
;
833 PKIX_UInt32 numItems
= 0;
836 PKIX_ENTER(LIST
, "pkix_List_MergeLists");
837 PKIX_NULLCHECK_ONE(pMergedList
);
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
);
862 if (secondList
!= NULL
) {
864 PKIX_CHECK(PKIX_List_GetLength
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
);
888 if (PKIX_ERROR_RECEIVED
){
896 * FUNCTION: pkix_List_AppendList
899 * Append items on "fromList" to the "toList". Item reference count on
900 * "toList" is not incremented, but items appended from "fromList" are
905 * Address of list to be appended to. Must be non-NULL.
907 * Address of list to be appended from. May be NULL or empty.
909 * platform-specific context pointer
911 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
918 pkix_List_AppendList(
923 PKIX_PL_Object
*item
= NULL
;
924 PKIX_UInt32 numItems
= 0;
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
) {
936 PKIX_CHECK(PKIX_List_GetLength(fromList
, &numItems
, plContext
),
937 PKIX_LISTGETLENGTHFAILED
);
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
);
961 * FUNCTION: pkix_List_AppendUnique
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.
970 * Address of a List of Objects to be augmented by "fromList". Must be
971 * non-NULL, but may be empty.
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.
976 * Platform-specific context pointer.
978 * Not Thread Safe - assumes exclusive access to "toList"
979 * (see Thread Safety Definitions in Programmer's Guide)
981 * Returns NULL if the function succeeds
982 * Returns a Fatal Error if the function fails in an unrecoverable way
985 pkix_List_AppendUnique(
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
);
1022 PKIX_DECREF(object
);
1028 * FUNCTION: pkix_List_QuickSort
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).
1037 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
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
1045 * Address of a List of Objects that shall be sorted and returned. Must be
1046 * non-NULL, but may be empty.
1048 * Platform-specific context pointer.
1050 * Not Thread Safe - assumes exclusive access to "toList"
1051 * (see Thread Safety Definitions in Programmer's Guide)
1053 * Returns NULL if the function succeeds
1054 * Returns a Fatal Error if the function fails in an unrecoverable way
1057 pkix_List_QuickSort(
1058 PKIX_List
*fromList
,
1059 PKIX_List_SortComparatorCallback comparator
,
1060 PKIX_List
**pSortedList
,
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;
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
);
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
);
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
);
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
);
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
);
1155 PKIX_CHECK(pkix_List_AppendList
1156 (sortedList
, greaterList
, plContext
),
1157 PKIX_LISTAPPENDLISTFAILED
);
1160 *pSortedList
= sortedList
;
1164 PKIX_DECREF(cmpObj
);
1165 PKIX_DECREF(object
);
1166 PKIX_DECREF(sortedGreaterList
);
1167 PKIX_DECREF(sortedLessList
);
1168 PKIX_DECREF(greaterList
);
1169 PKIX_DECREF(lessList
);
1175 * FUNCTION: pkix_List_BubbleSort
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).
1184 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
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
1192 * Address of a List of Objects that shall be sorted and returned. Must be
1193 * non-NULL, but may be empty.
1195 * Platform-specific context pointer.
1197 * Not Thread Safe - assumes exclusive access to "toList"
1198 * (see Thread Safety Definitions in Programmer's Guide)
1200 * Returns NULL if the function succeeds
1201 * Returns a Fatal Error if the function fails in an unrecoverable way
1204 pkix_List_BubbleSort(
1205 PKIX_List
*fromList
,
1206 PKIX_List_SortComparatorCallback comparator
,
1207 PKIX_List
**pSortedList
,
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;
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
,
1224 PKIX_LISTDUPLICATEFAILED
);
1226 PKIX_CHECK(PKIX_List_GetLength(sortedList
, &size
, plContext
),
1227 PKIX_LISTGETLENGTHFAILED
);
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
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
);
1267 PKIX_DECREF(cmpObj
);
1270 PKIX_DECREF(leastObj
);
1275 *pSortedList
= sortedList
;
1279 PKIX_DECREF(leastObj
);
1280 PKIX_DECREF(cmpObj
);
1285 /* --Public-List-Functions--------------------------------------------- */
1288 * FUNCTION: PKIX_List_Create (see comments in pkix_util.h)
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
);
1312 * FUNCTION: PKIX_List_SetImmutable (see comments in pkix_util.h)
1315 PKIX_List_SetImmutable(
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
;
1334 * FUNCTION: PKIX_List_IsImmutable (see comments in pkix_util.h)
1337 PKIX_List_IsImmutable(
1339 PKIX_Boolean
*pImmutable
,
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
;
1357 * FUNCTION: PKIX_List_GetLength (see comments in pkix_util.h)
1360 PKIX_List_GetLength(
1362 PKIX_UInt32
*pLength
,
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
;
1380 * FUNCTION: PKIX_List_IsEmpty (see comments in pkix_util.h)
1385 PKIX_Boolean
*pEmpty
,
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
;
1400 *pEmpty
= PKIX_TRUE
;
1402 *pEmpty
= PKIX_FALSE
;
1411 * FUNCTION: PKIX_List_AppendItem (see comments in pkix_util.h)
1414 PKIX_List_AppendItem(
1416 PKIX_PL_Object
*item
,
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 */
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
);
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;
1461 * FUNCTION: PKIX_List_InsertItem (see comments in pkix_util.h)
1464 PKIX_List_InsertItem(
1467 PKIX_PL_Object
*item
,
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
;
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;
1512 if (PKIX_ERROR_RECEIVED
){
1513 PKIX_DECREF(newElem
);
1520 * FUNCTION: PKIX_List_GetItem (see comments in pkix_util.h)
1526 PKIX_PL_Object
**pItem
,
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
;
1550 * FUNCTION: PKIX_List_SetItem (see comments in pkix_util.h)
1556 PKIX_PL_Object
*item
,
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 */
1580 element
->item
= item
;
1582 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1583 ((PKIX_PL_Object
*)list
, plContext
),
1584 PKIX_OBJECTINVALIDATECACHEFAILED
);
1592 * FUNCTION: PKIX_List_DeleteItem (see comments in pkix_util.h)
1595 PKIX_List_DeleteItem(
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 */
1638 PKIX_CHECK(pkix_List_GetElement
1639 (list
, index
-1, &prevElement
, plContext
),
1640 PKIX_LISTGETELEMENTFAILED
);
1641 } else if (index
== 0){ /* prevElement must be header */
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;
1662 * FUNCTION: PKIX_List_ReverseList (see comments in pkix_util.h)
1665 PKIX_List_ReverseList(
1667 PKIX_List
**pReversedList
,
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
);
1707 PKIX_DECREF(duplicateItem
);
1710 *pReversedList
= reversedList
;
1715 PKIX_DECREF(duplicateItem
);
1717 if (PKIX_ERROR_RECEIVED
){
1718 PKIX_DECREF(reversedList
);