| 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 /* | |
| 6 * Support routines for SECItem data structure. | |
| 7 */ | |
| 8 | |
| 9 #include "seccomon.h" | |
| 10 #include "secitem.h" | |
| 11 #include "secerr.h" | |
| 12 #include "secport.h" | |
| 13 | |
| 14 SECItem * | |
| 15 SECITEM_AllocItem(PLArenaPool *arena, SECItem *item, unsigned int len) | |
| 16 { | |
| 17 SECItem *result = NULL; | |
| 18 void *mark = NULL; | |
| 19 | |
| 20 if (arena != NULL) { | |
| 21 mark = PORT_ArenaMark(arena); | |
| 22 } | |
| 23 | |
| 24 if (item == NULL) { | |
| 25 if (arena != NULL) { | |
| 26 result = PORT_ArenaZAlloc(arena, sizeof(SECItem)); | |
| 27 } else { | |
| 28 result = PORT_ZAlloc(sizeof(SECItem)); | |
| 29 } | |
| 30 if (result == NULL) { | |
| 31 goto loser; | |
| 32 } | |
| 33 } else { | |
| 34 PORT_Assert(item->data == NULL); | |
| 35 result = item; | |
| 36 } | |
| 37 | |
| 38 result->len = len; | |
| 39 if (len) { | |
| 40 if (arena != NULL) { | |
| 41 result->data = PORT_ArenaAlloc(arena, len); | |
| 42 } else { | |
| 43 result->data = PORT_Alloc(len); | |
| 44 } | |
| 45 if (result->data == NULL) { | |
| 46 goto loser; | |
| 47 } | |
| 48 } else { | |
| 49 result->data = NULL; | |
| 50 } | |
| 51 | |
| 52 if (mark) { | |
| 53 PORT_ArenaUnmark(arena, mark); | |
| 54 } | |
| 55 return(result); | |
| 56 | |
| 57 loser: | |
| 58 if ( arena != NULL ) { | |
| 59 if (mark) { | |
| 60 PORT_ArenaRelease(arena, mark); | |
| 61 } | |
| 62 if (item != NULL) { | |
| 63 item->data = NULL; | |
| 64 item->len = 0; | |
| 65 } | |
| 66 } else { | |
| 67 if (result != NULL) { | |
| 68 SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE); | |
| 69 } | |
| 70 /* | |
| 71 * If item is not NULL, the above has set item->data and | |
| 72 * item->len to 0. | |
| 73 */ | |
| 74 } | |
| 75 return(NULL); | |
| 76 } | |
| 77 | |
| 78 SECStatus | |
| 79 SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item, unsigned int oldlen, | |
| 80 unsigned int newlen) | |
| 81 { | |
| 82 PORT_Assert(item != NULL); | |
| 83 if (item == NULL) { | |
| 84 /* XXX Set error. But to what? */ | |
| 85 return SECFailure; | |
| 86 } | |
| 87 | |
| 88 /* | |
| 89 * If no old length, degenerate to just plain alloc. | |
| 90 */ | |
| 91 if (oldlen == 0) { | |
| 92 PORT_Assert(item->data == NULL || item->len == 0); | |
| 93 if (newlen == 0) { | |
| 94 /* Nothing to do. Weird, but not a failure. */ | |
| 95 return SECSuccess; | |
| 96 } | |
| 97 item->len = newlen; | |
| 98 if (arena != NULL) { | |
| 99 item->data = PORT_ArenaAlloc(arena, newlen); | |
| 100 } else { | |
| 101 item->data = PORT_Alloc(newlen); | |
| 102 } | |
| 103 } else { | |
| 104 if (arena != NULL) { | |
| 105 item->data = PORT_ArenaGrow(arena, item->data, oldlen, newlen); | |
| 106 } else { | |
| 107 item->data = PORT_Realloc(item->data, newlen); | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 if (item->data == NULL) { | |
| 112 return SECFailure; | |
| 113 } | |
| 114 | |
| 115 return SECSuccess; | |
| 116 } | |
| 117 | |
| 118 SECStatus | |
| 119 SECITEM_ReallocItemV2(PLArenaPool *arena, SECItem *item, unsigned int newlen) | |
| 120 { | |
| 121 unsigned char *newdata = NULL; | |
| 122 | |
| 123 PORT_Assert(item); | |
| 124 if (!item) { | |
| 125 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 126 return SECFailure; | |
| 127 } | |
| 128 | |
| 129 if (item->len == newlen) { | |
| 130 return SECSuccess; | |
| 131 } | |
| 132 | |
| 133 if (!newlen) { | |
| 134 if (!arena) { | |
| 135 PORT_Free(item->data); | |
| 136 } | |
| 137 item->data = NULL; | |
| 138 item->len = 0; | |
| 139 return SECSuccess; | |
| 140 } | |
| 141 | |
| 142 if (!item->data) { | |
| 143 /* allocate fresh block of memory */ | |
| 144 PORT_Assert(!item->len); | |
| 145 if (arena) { | |
| 146 newdata = PORT_ArenaAlloc(arena, newlen); | |
| 147 } else { | |
| 148 newdata = PORT_Alloc(newlen); | |
| 149 } | |
| 150 } else { | |
| 151 /* reallocate or adjust existing block of memory */ | |
| 152 if (arena) { | |
| 153 if (item->len > newlen) { | |
| 154 /* There's no need to realloc a shorter block from the arena, | |
| 155 * because it would result in using even more memory! | |
| 156 * Therefore we'll continue to use the old block and | |
| 157 * set the item to the shorter size. | |
| 158 */ | |
| 159 item->len = newlen; | |
| 160 return SECSuccess; | |
| 161 } | |
| 162 newdata = PORT_ArenaGrow(arena, item->data, item->len, newlen); | |
| 163 } else { | |
| 164 newdata = PORT_Realloc(item->data, newlen); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 if (!newdata) { | |
| 169 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
| 170 return SECFailure; | |
| 171 } | |
| 172 | |
| 173 item->len = newlen; | |
| 174 item->data = newdata; | |
| 175 return SECSuccess; | |
| 176 } | |
| 177 | |
| 178 SECComparison | |
| 179 SECITEM_CompareItem(const SECItem *a, const SECItem *b) | |
| 180 { | |
| 181 unsigned m; | |
| 182 int rv; | |
| 183 | |
| 184 if (a == b) | |
| 185 return SECEqual; | |
| 186 if (!a || !a->len || !a->data) | |
| 187 return (!b || !b->len || !b->data) ? SECEqual : SECLessThan; | |
| 188 if (!b || !b->len || !b->data) | |
| 189 return SECGreaterThan; | |
| 190 | |
| 191 m = ( ( a->len < b->len ) ? a->len : b->len ); | |
| 192 | |
| 193 rv = PORT_Memcmp(a->data, b->data, m); | |
| 194 if (rv) { | |
| 195 return rv < 0 ? SECLessThan : SECGreaterThan; | |
| 196 } | |
| 197 if (a->len < b->len) { | |
| 198 return SECLessThan; | |
| 199 } | |
| 200 if (a->len == b->len) { | |
| 201 return SECEqual; | |
| 202 } | |
| 203 return SECGreaterThan; | |
| 204 } | |
| 205 | |
| 206 PRBool | |
| 207 SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b) | |
| 208 { | |
| 209 if (a->len != b->len) | |
| 210 return PR_FALSE; | |
| 211 if (!a->len) | |
| 212 return PR_TRUE; | |
| 213 if (!a->data || !b->data) { | |
| 214 /* avoid null pointer crash. */ | |
| 215 return (PRBool)(a->data == b->data); | |
| 216 } | |
| 217 return (PRBool)!PORT_Memcmp(a->data, b->data, a->len); | |
| 218 } | |
| 219 | |
| 220 SECItem * | |
| 221 SECITEM_DupItem(const SECItem *from) | |
| 222 { | |
| 223 return SECITEM_ArenaDupItem(NULL, from); | |
| 224 } | |
| 225 | |
| 226 SECItem * | |
| 227 SECITEM_ArenaDupItem(PLArenaPool *arena, const SECItem *from) | |
| 228 { | |
| 229 SECItem *to; | |
| 230 | |
| 231 if ( from == NULL ) { | |
| 232 return(NULL); | |
| 233 } | |
| 234 | |
| 235 if ( arena != NULL ) { | |
| 236 to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem)); | |
| 237 } else { | |
| 238 to = (SECItem *)PORT_Alloc(sizeof(SECItem)); | |
| 239 } | |
| 240 if ( to == NULL ) { | |
| 241 return(NULL); | |
| 242 } | |
| 243 | |
| 244 if ( arena != NULL ) { | |
| 245 to->data = (unsigned char *)PORT_ArenaAlloc(arena, from->len); | |
| 246 } else { | |
| 247 to->data = (unsigned char *)PORT_Alloc(from->len); | |
| 248 } | |
| 249 if ( to->data == NULL ) { | |
| 250 PORT_Free(to); | |
| 251 return(NULL); | |
| 252 } | |
| 253 | |
| 254 to->len = from->len; | |
| 255 to->type = from->type; | |
| 256 if ( to->len ) { | |
| 257 PORT_Memcpy(to->data, from->data, to->len); | |
| 258 } | |
| 259 | |
| 260 return(to); | |
| 261 } | |
| 262 | |
| 263 SECStatus | |
| 264 SECITEM_CopyItem(PLArenaPool *arena, SECItem *to, const SECItem *from) | |
| 265 { | |
| 266 to->type = from->type; | |
| 267 if (from->data && from->len) { | |
| 268 if ( arena ) { | |
| 269 to->data = (unsigned char*) PORT_ArenaAlloc(arena, from->len); | |
| 270 } else { | |
| 271 to->data = (unsigned char*) PORT_Alloc(from->len); | |
| 272 } | |
| 273 | |
| 274 if (!to->data) { | |
| 275 return SECFailure; | |
| 276 } | |
| 277 PORT_Memcpy(to->data, from->data, from->len); | |
| 278 to->len = from->len; | |
| 279 } else { | |
| 280 /* | |
| 281 * If from->data is NULL but from->len is nonzero, this function | |
| 282 * will succeed. Is this right? | |
| 283 */ | |
| 284 to->data = 0; | |
| 285 to->len = 0; | |
| 286 } | |
| 287 return SECSuccess; | |
| 288 } | |
| 289 | |
| 290 void | |
| 291 SECITEM_FreeItem(SECItem *zap, PRBool freeit) | |
| 292 { | |
| 293 if (zap) { | |
| 294 PORT_Free(zap->data); | |
| 295 zap->data = 0; | |
| 296 zap->len = 0; | |
| 297 if (freeit) { | |
| 298 PORT_Free(zap); | |
| 299 } | |
| 300 } | |
| 301 } | |
| 302 | |
| 303 void | |
| 304 SECITEM_ZfreeItem(SECItem *zap, PRBool freeit) | |
| 305 { | |
| 306 if (zap) { | |
| 307 PORT_ZFree(zap->data, zap->len); | |
| 308 zap->data = 0; | |
| 309 zap->len = 0; | |
| 310 if (freeit) { | |
| 311 PORT_ZFree(zap, sizeof(SECItem)); | |
| 312 } | |
| 313 } | |
| 314 } | |
| 315 /* these reroutines were taken from pkix oid.c, which is supposed to | |
| 316 * replace this file some day */ | |
| 317 /* | |
| 318 * This is the hash function. We simply XOR the encoded form with | |
| 319 * itself in sizeof(PLHashNumber)-byte chunks. Improving this | |
| 320 * routine is left as an excercise for the more mathematically | |
| 321 * inclined student. | |
| 322 */ | |
| 323 PLHashNumber PR_CALLBACK | |
| 324 SECITEM_Hash ( const void *key) | |
| 325 { | |
| 326 const SECItem *item = (const SECItem *)key; | |
| 327 PLHashNumber rv = 0; | |
| 328 | |
| 329 PRUint8 *data = (PRUint8 *)item->data; | |
| 330 PRUint32 i; | |
| 331 PRUint8 *rvc = (PRUint8 *)&rv; | |
| 332 | |
| 333 for( i = 0; i < item->len; i++ ) { | |
| 334 rvc[ i % sizeof(rv) ] ^= *data; | |
| 335 data++; | |
| 336 } | |
| 337 | |
| 338 return rv; | |
| 339 } | |
| 340 | |
| 341 /* | |
| 342 * This is the key-compare function. It simply does a lexical | |
| 343 * comparison on the item data. This does not result in | |
| 344 * quite the same ordering as the "sequence of numbers" order, | |
| 345 * but heck it's only used internally by the hash table anyway. | |
| 346 */ | |
| 347 PRIntn PR_CALLBACK | |
| 348 SECITEM_HashCompare ( const void *k1, const void *k2) | |
| 349 { | |
| 350 const SECItem *i1 = (const SECItem *)k1; | |
| 351 const SECItem *i2 = (const SECItem *)k2; | |
| 352 | |
| 353 return SECITEM_ItemsAreEqual(i1,i2); | |
| 354 } | |
| 355 | |
| 356 SECItemArray * | |
| 357 SECITEM_AllocArray(PLArenaPool *arena, SECItemArray *array, unsigned int len) | |
| 358 { | |
| 359 SECItemArray *result = NULL; | |
| 360 void *mark = NULL; | |
| 361 | |
| 362 if (array != NULL && array->items != NULL) { | |
| 363 PORT_Assert(0); | |
| 364 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
| 365 return NULL; | |
| 366 } | |
| 367 | |
| 368 if (arena != NULL) { | |
| 369 mark = PORT_ArenaMark(arena); | |
| 370 } | |
| 371 | |
| 372 if (array == NULL) { | |
| 373 if (arena != NULL) { | |
| 374 result = PORT_ArenaZAlloc(arena, sizeof(SECItemArray)); | |
| 375 } else { | |
| 376 result = PORT_ZAlloc(sizeof(SECItemArray)); | |
| 377 } | |
| 378 if (result == NULL) { | |
| 379 goto loser; | |
| 380 } | |
| 381 } else { | |
| 382 result = array; | |
| 383 } | |
| 384 | |
| 385 result->len = len; | |
| 386 if (len) { | |
| 387 if (arena != NULL) { | |
| 388 result->items = PORT_ArenaZNewArray(arena, SECItem, len); | |
| 389 } else { | |
| 390 result->items = PORT_ZNewArray(SECItem, len); | |
| 391 } | |
| 392 if (result->items == NULL) { | |
| 393 goto loser; | |
| 394 } | |
| 395 } else { | |
| 396 result->items = NULL; | |
| 397 } | |
| 398 | |
| 399 if (mark) { | |
| 400 PORT_ArenaUnmark(arena, mark); | |
| 401 } | |
| 402 return result; | |
| 403 | |
| 404 loser: | |
| 405 if ( arena != NULL ) { | |
| 406 if (mark) { | |
| 407 PORT_ArenaRelease(arena, mark); | |
| 408 } | |
| 409 } else { | |
| 410 if (result != NULL && array == NULL) { | |
| 411 PORT_Free(result); | |
| 412 } | |
| 413 } | |
| 414 if (array != NULL) { | |
| 415 array->items = NULL; | |
| 416 array->len = 0; | |
| 417 } | |
| 418 return NULL; | |
| 419 } | |
| 420 | |
| 421 static void | |
| 422 secitem_FreeArray(SECItemArray *array, PRBool zero_items, PRBool freeit) | |
| 423 { | |
| 424 unsigned int i; | |
| 425 | |
| 426 if (!array || !array->len || !array->items) | |
| 427 return; | |
| 428 | |
| 429 for (i = 0; i < array->len; ++i) { | |
| 430 SECItem *item = &array->items[i]; | |
| 431 | |
| 432 if (item->data) { | |
| 433 if (zero_items) { | |
| 434 SECITEM_ZfreeItem(item, PR_FALSE); | |
| 435 } else { | |
| 436 SECITEM_FreeItem(item, PR_FALSE); | |
| 437 } | |
| 438 } | |
| 439 } | |
| 440 PORT_Free(array->items); | |
| 441 array->items = NULL; | |
| 442 array->len = 0; | |
| 443 | |
| 444 if (freeit) | |
| 445 PORT_Free(array); | |
| 446 } | |
| 447 | |
| 448 void SECITEM_FreeArray(SECItemArray *array, PRBool freeit) | |
| 449 { | |
| 450 secitem_FreeArray(array, PR_FALSE, freeit); | |
| 451 } | |
| 452 | |
| 453 void SECITEM_ZfreeArray(SECItemArray *array, PRBool freeit) | |
| 454 { | |
| 455 secitem_FreeArray(array, PR_TRUE, freeit); | |
| 456 } | |
| 457 | |
| 458 SECItemArray * | |
| 459 SECITEM_DupArray(PLArenaPool *arena, const SECItemArray *from) | |
| 460 { | |
| 461 SECItemArray *result; | |
| 462 unsigned int i; | |
| 463 | |
| 464 /* Require a "from" array. | |
| 465 * Reject an inconsistent "from" array with NULL data and nonzero length. | |
| 466 * However, allow a "from" array of zero length. | |
| 467 */ | |
| 468 if (!from || (!from->items && from->len)) | |
| 469 return NULL; | |
| 470 | |
| 471 result = SECITEM_AllocArray(arena, NULL, from->len); | |
| 472 if (!result) | |
| 473 return NULL; | |
| 474 | |
| 475 for (i = 0; i < from->len; ++i) { | |
| 476 SECStatus rv = SECITEM_CopyItem(arena, | |
| 477 &result->items[i], &from->items[i]); | |
| 478 if (rv != SECSuccess) { | |
| 479 SECITEM_ZfreeArray(result, PR_TRUE); | |
| 480 return NULL; | |
| 481 } | |
| 482 } | |
| 483 | |
| 484 return result; | |
| 485 } | |
| OLD | NEW |