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