pkix_list.c (50944B)
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 }