| 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 |