security/nss/lib/libpkix/pkix/util/pkix_list.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial