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