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 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.
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 ***** */
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
.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
;
610 * FUNCTION: pkix_List_Contains
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".
619 * List to be searched; may be empty; must be non-NULL
621 * Object to be checked for; must be non-NULL
623 * Address where the result of the search will be stored. Must
626 * platform-specific context pointer
628 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
630 * Returns NULL if the function succeeds
631 * Returns a Fatal Error if the function fails in an unrecoverable way
636 PKIX_PL_Object
*object
,
637 PKIX_Boolean
*pFound
,
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
, ¤t
, plContext
),
654 PKIX_LISTGETITEMFAILED
);
657 PKIX_CHECK(PKIX_PL_Object_Equals
658 (object
, current
, &match
, plContext
),
659 PKIX_OBJECTEQUALSFAILED
);
661 PKIX_DECREF(current
);
673 PKIX_DECREF(current
);
678 * FUNCTION: pkix_List_Remove
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.
687 * List to be searched; may be empty; must be non-NULL
689 * Object to be checked for and deleted, if found; must be non-NULL
691 * platform-specific context pointer
693 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
702 PKIX_PL_Object
*object
,
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
, ¤t
, plContext
),
719 PKIX_LISTGETITEMFAILED
);
722 PKIX_CHECK(PKIX_PL_Object_Equals
723 (object
, current
, &match
, plContext
),
724 PKIX_OBJECTEQUALSFAILED
);
726 PKIX_DECREF(current
);
730 PKIX_CHECK(PKIX_List_DeleteItem
731 (list
, index
, plContext
),
732 PKIX_LISTDELETEITEMFAILED
);
739 PKIX_DECREF(current
);
744 * FUNCTION: pkix_List_RemoveItems
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.
753 * Object in "list" is checked for object in "deleteList" and deleted if
754 * found; may be empty; must be non-NULL
756 * List of objects to be searched ; may be empty; must be non-NULL
758 * platform-specific context pointer
760 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
767 pkix_List_RemoveItems(
769 PKIX_List
*deleteList
,
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
, ¤t
, plContext
),
785 PKIX_LISTGETITEMFAILED
);
788 PKIX_CHECK(pkix_List_Remove
789 (list
, current
, plContext
),
790 PKIX_OBJECTEQUALSFAILED
);
792 PKIX_DECREF(current
);
798 PKIX_DECREF(current
);
803 * FUNCTION: pkix_List_MergeLists
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.
813 * Address of list to be merged from. May be NULL or empty.
815 * Address of list to be merged from. May be NULL or empty.
817 * Address where returned object is stored.
819 * platform-specific context pointer * THREAD SAFETY:
820 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
827 pkix_List_MergeLists(
828 PKIX_List
*firstList
,
829 PKIX_List
*secondList
,
830 PKIX_List
**pMergedList
,
833 PKIX_List
*list
= NULL
;
834 PKIX_PL_Object
*item
= NULL
;
835 PKIX_UInt32 numItems
= 0;
838 PKIX_ENTER(LIST
, "pkix_List_MergeLists");
839 PKIX_NULLCHECK_ONE(pMergedList
);
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
);
864 if (secondList
!= NULL
) {
866 PKIX_CHECK(PKIX_List_GetLength
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
);
890 if (PKIX_ERROR_RECEIVED
){
898 * FUNCTION: pkix_List_AppendList
901 * Append items on "fromList" to the "toList". Item reference count on
902 * "toList" is not incremented, but items appended from "fromList" are
907 * Address of list to be appended to. Must be non-NULL.
909 * Address of list to be appended from. May be NULL or empty.
911 * platform-specific context pointer
913 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
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
920 pkix_List_AppendList(
925 PKIX_PL_Object
*item
= NULL
;
926 PKIX_UInt32 numItems
= 0;
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
) {
938 PKIX_CHECK(PKIX_List_GetLength(fromList
, &numItems
, plContext
),
939 PKIX_LISTGETLENGTHFAILED
);
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
);
963 * FUNCTION: pkix_List_AppendUnique
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.
972 * Address of a List of Objects to be augmented by "fromList". Must be
973 * non-NULL, but may be empty.
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.
978 * Platform-specific context pointer.
980 * Not Thread Safe - assumes exclusive access to "toList"
981 * (see Thread Safety Definitions in Programmer's Guide)
983 * Returns NULL if the function succeeds
984 * Returns a Fatal Error if the function fails in an unrecoverable way
987 pkix_List_AppendUnique(
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
);
1024 PKIX_DECREF(object
);
1030 * FUNCTION: pkix_List_QuickSort
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).
1039 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
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
1047 * Address of a List of Objects that shall be sorted and returned. Must be
1048 * non-NULL, but may be empty.
1050 * Platform-specific context pointer.
1052 * Not Thread Safe - assumes exclusive access to "toList"
1053 * (see Thread Safety Definitions in Programmer's Guide)
1055 * Returns NULL if the function succeeds
1056 * Returns a Fatal Error if the function fails in an unrecoverable way
1059 pkix_List_QuickSort(
1060 PKIX_List
*fromList
,
1061 PKIX_List_SortComparatorCallback comparator
,
1062 PKIX_List
**pSortedList
,
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;
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
);
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
);
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
);
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
);
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
);
1157 PKIX_CHECK(pkix_List_AppendList
1158 (sortedList
, greaterList
, plContext
),
1159 PKIX_LISTAPPENDLISTFAILED
);
1162 *pSortedList
= sortedList
;
1166 PKIX_DECREF(cmpObj
);
1167 PKIX_DECREF(object
);
1168 PKIX_DECREF(sortedGreaterList
);
1169 PKIX_DECREF(sortedLessList
);
1170 PKIX_DECREF(greaterList
);
1171 PKIX_DECREF(lessList
);
1177 * FUNCTION: pkix_List_BubbleSort
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).
1186 * Address of a List of Objects to be sorted. Must be non-NULL, but may be
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
1194 * Address of a List of Objects that shall be sorted and returned. Must be
1195 * non-NULL, but may be empty.
1197 * Platform-specific context pointer.
1199 * Not Thread Safe - assumes exclusive access to "toList"
1200 * (see Thread Safety Definitions in Programmer's Guide)
1202 * Returns NULL if the function succeeds
1203 * Returns a Fatal Error if the function fails in an unrecoverable way
1206 pkix_List_BubbleSort(
1207 PKIX_List
*fromList
,
1208 PKIX_List_SortComparatorCallback comparator
,
1209 PKIX_List
**pSortedList
,
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;
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
,
1226 PKIX_LISTDUPLICATEFAILED
);
1228 PKIX_CHECK(PKIX_List_GetLength(sortedList
, &size
, plContext
),
1229 PKIX_LISTGETLENGTHFAILED
);
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
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
);
1269 PKIX_DECREF(cmpObj
);
1272 PKIX_DECREF(leastObj
);
1277 *pSortedList
= sortedList
;
1281 PKIX_DECREF(leastObj
);
1282 PKIX_DECREF(cmpObj
);
1287 /* --Public-List-Functions--------------------------------------------- */
1290 * FUNCTION: PKIX_List_Create (see comments in pkix_util.h)
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
);
1314 * FUNCTION: PKIX_List_SetImmutable (see comments in pkix_util.h)
1317 PKIX_List_SetImmutable(
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
;
1336 * FUNCTION: PKIX_List_IsImmutable (see comments in pkix_util.h)
1339 PKIX_List_IsImmutable(
1341 PKIX_Boolean
*pImmutable
,
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
;
1359 * FUNCTION: PKIX_List_GetLength (see comments in pkix_util.h)
1362 PKIX_List_GetLength(
1364 PKIX_UInt32
*pLength
,
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
;
1382 * FUNCTION: PKIX_List_IsEmpty (see comments in pkix_util.h)
1387 PKIX_Boolean
*pEmpty
,
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
;
1402 *pEmpty
= PKIX_TRUE
;
1404 *pEmpty
= PKIX_FALSE
;
1413 * FUNCTION: PKIX_List_AppendItem (see comments in pkix_util.h)
1416 PKIX_List_AppendItem(
1418 PKIX_PL_Object
*item
,
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 */
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
);
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;
1463 * FUNCTION: PKIX_List_InsertItem (see comments in pkix_util.h)
1466 PKIX_List_InsertItem(
1469 PKIX_PL_Object
*item
,
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
;
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;
1514 if (PKIX_ERROR_RECEIVED
){
1515 PKIX_DECREF(newElem
);
1522 * FUNCTION: PKIX_List_GetItem (see comments in pkix_util.h)
1528 PKIX_PL_Object
**pItem
,
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
;
1552 * FUNCTION: PKIX_List_SetItem (see comments in pkix_util.h)
1558 PKIX_PL_Object
*item
,
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 */
1582 element
->item
= item
;
1584 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
1585 ((PKIX_PL_Object
*)list
, plContext
),
1586 PKIX_OBJECTINVALIDATECACHEFAILED
);
1594 * FUNCTION: PKIX_List_DeleteItem (see comments in pkix_util.h)
1597 PKIX_List_DeleteItem(
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 */
1640 PKIX_CHECK(pkix_List_GetElement
1641 (list
, index
-1, &prevElement
, plContext
),
1642 PKIX_LISTGETELEMENTFAILED
);
1643 } else if (index
== 0){ /* prevElement must be header */
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;
1664 * FUNCTION: PKIX_List_ReverseList (see comments in pkix_util.h)
1667 PKIX_List_ReverseList(
1669 PKIX_List
**pReversedList
,
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
);
1709 PKIX_DECREF(duplicateItem
);
1712 *pReversedList
= reversedList
;
1717 PKIX_DECREF(duplicateItem
);
1719 if (PKIX_ERROR_RECEIVED
){
1720 PKIX_DECREF(reversedList
);