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