]> git.saurik.com Git - apple/libinfo.git/blob - lookup.subproj/kvbuf.c
Libinfo-324.tar.gz
[apple/libinfo.git] / lookup.subproj / kvbuf.c
1 /*
2 * Copyright (c) 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <kvbuf.h>
29
30 #define KVBUF_CHUNK 256
31
32 /*
33 * kvbuf_t is a list of key/value dictionaries.
34 *
35 * First 4 bytes are the number of dictionaries.
36 * For each dictionary, first 4 bytes is the key / value list count.
37 * For each value list, first 4 bytes is the list length.
38 * Keys and values are a 4-byte length followed by a nul-terminated string
39 *
40 * When the databuf needs to grow, we add memory in KVBUF_CHUNK size
41 * increments to reduce malloc / realloc activity.
42 * The _size variable stores the actual allocated size.
43 * The datalen variable stores the used data size.
44 *
45 * The _dict variable holds an offset from the start of the buffer
46 * to the "current" dictionary. kvbuf_reset() resets this,
47 * and kvbuf_next_dict() bumps the offset so that databuf + _dict
48 * points to the next dictionary.
49 *
50 * The _key variable holds an offset from the start of the buffer
51 * to the "current" key. kvbuf_reset() resets this, and
52 * kvbuf_next_key() bumps the offset so that databuf + _key
53 * points to the next key.
54 *
55 * The _val variable holds an offset from the start of the buffer
56 * to the "current" value. kvbuf_reset() resets this, and
57 * kvbuf_next_val() bumps the offset so that databuf + _val
58 * points to the next value.
59 *
60 * The cache_entry_list_to_kvbuf() routine contains the only
61 * code that builds an array.
62 *
63 */
64
65 /*
66 * kvbuf_query is a simple utility for constructing a
67 * kvbuf with a single dictionary. The format string may
68 * contain the chars "k", "s", "i", and "u". "k" denotes a key
69 * (keys are always strings), "s" denotes a string value,
70 * "i" denotes a 32 bit signed int, and "u" denotes an unsigned.
71 */
72 __private_extern__ kvbuf_t *
73 kvbuf_query(char *fmt, ...)
74 {
75 va_list ap;
76 char *arg, *f, str[32];
77 int32_t iarg;
78 uint32_t uarg;
79 kvbuf_t *kv;
80
81 if (fmt == NULL) return NULL;
82
83 kv = kvbuf_new();
84 if (kv == NULL) return NULL;
85
86 kvbuf_add_dict(kv);
87
88 va_start(ap, fmt);
89 for (f = fmt; (*f) != '\0'; f++)
90 {
91 if (*f == 'k')
92 {
93 arg = va_arg(ap, char *);
94 kvbuf_add_key(kv, arg);
95 }
96 else if (*f == 's')
97 {
98 arg = va_arg(ap, char *);
99 kvbuf_add_val(kv, arg);
100 }
101 else if (*f == 'i')
102 {
103 iarg = va_arg(ap, int32_t);
104 snprintf(str, sizeof(str), "%d", iarg);
105 kvbuf_add_val(kv, str);
106 }
107 else if (*f == 'u')
108 {
109 uarg = va_arg(ap,uint32_t);
110 snprintf(str, sizeof(str), "%u", uarg);
111 kvbuf_add_val(kv, str);
112 }
113 }
114 va_end(ap);
115
116 return kv;
117 }
118
119 kvbuf_t *
120 kvbuf_query_key_val(const char *key, const char *val)
121 {
122 kvbuf_t *kv;
123 uint32_t x, kl, vl, vc;
124 char *p;
125
126 if (key == NULL) return NULL;
127
128 kl = strlen(key) + 1;
129
130 vl = 0;
131 vc = 0;
132
133 if (val != NULL)
134 {
135 vl = strlen(val) + 1;
136 vc = 1;
137 }
138
139 kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
140 if (kv == NULL) return NULL;
141
142 kv->_size = (5 * sizeof(uint32_t)) + kl + vl;
143 kv->datalen = kv->_size;
144
145 kv->databuf = calloc(1, kv->_size);
146 if (kv->databuf == NULL)
147 {
148 free(kv);
149 return NULL;
150 }
151
152 p = kv->databuf;
153
154 /* 1 dict */
155 x = htonl(1);
156 memcpy(p, &x, sizeof(uint32_t));
157 p += sizeof(uint32_t);
158
159 /* 1 key */
160 memcpy(p, &x, sizeof(uint32_t));
161 p += sizeof(uint32_t);
162
163 /* key length */
164 x = htonl(kl);
165 memcpy(p, &x, sizeof(uint32_t));
166 p += sizeof(uint32_t);
167
168 /* key */
169 memcpy(p, key, kl);
170 p += kl;
171
172 /* number of values */
173 x = htonl(vc);
174 memcpy(p, &x, sizeof(uint32_t));
175 p += sizeof(uint32_t);
176
177 if (vc > 0)
178 {
179 /* value length */
180 x = htonl(vl);
181 memcpy(p, &x, sizeof(uint32_t));
182 p += sizeof(uint32_t);
183
184 /* value */
185 memcpy(p, val, vl);
186 }
187
188 return kv;
189 }
190
191 __private_extern__ kvbuf_t *
192 kvbuf_query_key_int(const char *key, int32_t i)
193 {
194 char str[32];
195
196 snprintf(str, sizeof(str), "%d", i);
197 return kvbuf_query_key_val(key, str);
198 }
199
200 __private_extern__ kvbuf_t *
201 kvbuf_query_key_uint(const char *key, uint32_t u)
202 {
203 char str[32];
204
205 snprintf(str, sizeof(str), "%u", u);
206 return kvbuf_query_key_val(key, str);
207 }
208
209 kvbuf_t *
210 kvbuf_new_zone(malloc_zone_t *zone)
211 {
212 kvbuf_t *kv;
213
214 if (zone == NULL) return NULL;
215
216 kv = (kvbuf_t *)malloc_zone_calloc(zone, 1, sizeof(kvbuf_t));
217 if (kv == NULL) return NULL;
218
219 kv->_size = KVBUF_START_SIZE;
220 kv->databuf = malloc_zone_calloc(zone, 1, kv->_size);
221 if (kv->databuf == NULL)
222 {
223 free(kv);
224 return NULL;
225 }
226
227 kv->datalen = sizeof(uint32_t);
228 kv->_dict = kv->datalen;
229
230 return kv;
231 }
232
233 kvbuf_t *
234 kvbuf_new(void)
235 {
236 return kvbuf_new_zone(malloc_default_zone());
237 }
238
239 kvbuf_t *
240 kvbuf_init_zone(malloc_zone_t *zone, char *buffer, uint32_t length)
241 {
242 kvbuf_t *kv;
243
244 if (zone == NULL) return NULL;
245
246 kv = (kvbuf_t *)malloc_zone_calloc(zone, 1, sizeof(kvbuf_t));
247 if (kv == NULL) return NULL;
248
249 kv->_size = length;
250 kv->datalen = length;
251 kv->databuf = malloc_zone_calloc(zone, 1, length);
252 if (kv->databuf == NULL)
253 {
254 free(kv);
255 kv = NULL;
256 }
257 else
258 {
259 memcpy(kv->databuf, buffer, length);
260 }
261
262 return kv;
263 }
264
265 kvbuf_t *
266 kvbuf_init(char *buffer, uint32_t length)
267 {
268 return kvbuf_init_zone(malloc_default_zone(), buffer, length);
269 }
270
271 static void
272 kvbuf_grow(kvbuf_t *kv, uint32_t delta)
273 {
274 uint32_t newlen, n;
275 char *p;
276
277 if (kv == NULL) return;
278 if (delta == 0) return;
279
280 if (kv->databuf == NULL) delta += sizeof(uint32_t);
281
282 n = (delta + KVBUF_CHUNK - 1) / KVBUF_CHUNK;
283 newlen = kv->datalen + (n * KVBUF_CHUNK);
284
285 if (newlen <= kv->_size) return;
286
287 kv->_size = newlen;
288
289 if (kv->databuf == NULL)
290 {
291 kv->databuf = calloc(1, kv->_size);
292 if (kv->databuf == NULL)
293 {
294 memset(kv, 0, sizeof(kvbuf_t));
295 return;
296 }
297
298 kv->datalen = sizeof(uint32_t);
299 kv->_dict = sizeof(uint32_t);
300 }
301 else
302 {
303 kv->databuf = reallocf(kv->databuf, kv->_size);
304 if (kv->databuf == NULL)
305 {
306 memset(kv, 0, sizeof(kvbuf_t));
307 return;
308 }
309
310 p = kv->databuf + kv->datalen;
311 memset(p, 0, kv->_size - kv->datalen);
312 }
313 }
314
315 void
316 kvbuf_add_dict(kvbuf_t *kv)
317 {
318 char *p;
319 uint32_t x, dict_count;
320
321 if (kv == NULL) return;
322
323 /* Add a key count */
324 kvbuf_grow(kv, sizeof(uint32_t));
325 if (kv->databuf == NULL) return;
326
327 kv->_dict = kv->datalen;
328 kv->datalen += sizeof(uint32_t);
329
330 kv->_key = kv->datalen;
331 kv->_vlist = 0;
332 kv->_val = 0;
333
334 /* increment and rewrite the dict count */
335 p = kv->databuf;
336
337 x = 0;
338 memcpy(&x, p, sizeof(uint32_t));
339 dict_count = ntohl(x);
340
341 dict_count++;
342 x = htonl(dict_count);
343 memcpy(p, &x, sizeof(uint32_t));
344 }
345
346 void
347 kvbuf_add_key(kvbuf_t *kv, const char *key)
348 {
349 uint32_t kl, x, key_count, delta;
350 char *p;
351
352 if (kv == NULL) return;
353 if (key == NULL) return;
354
355 kl = strlen(key) + 1;
356
357 /* Grow to hold key len, key, and value list count. */
358 delta = (2 * sizeof(uint32_t)) + kl;
359 kvbuf_grow(kv, delta);
360
361 if (kv->databuf == NULL) return;
362
363 /* increment and rewrite the key count for the current dictionary */
364 p = kv->databuf + kv->_dict;
365
366 x = 0;
367 memcpy(&x, p, sizeof(uint32_t));
368 key_count = ntohl(x);
369
370 if (key_count == 0) kv->_key = kv->_dict + sizeof(uint32_t);
371 else kv->_key = kv->datalen;
372
373 key_count++;
374 x = htonl(key_count);
375 memcpy(p, &x, sizeof(uint32_t));
376
377 /* append key to data buffer */
378 p = kv->databuf + kv->datalen;
379
380 x = htonl(kl);
381 memcpy(p, &x, sizeof(uint32_t));
382 p += sizeof(uint32_t);
383 memcpy(p, key, kl);
384 p += kl;
385
386 kv->_vlist = kv->datalen + sizeof(uint32_t) + kl;
387
388 x = 0;
389 memcpy(p, &x, sizeof(uint32_t));
390
391 kv->datalen += delta;
392 kv->_val = kv->datalen;
393 }
394
395 void
396 kvbuf_add_val_len(kvbuf_t *kv, const char *val, uint32_t len)
397 {
398 uint32_t x, val_count, delta;
399 char *p;
400
401 if (kv == NULL) return;
402 if (val == NULL) return;
403 if (len == 0) return;
404
405 /* Grow to hold val len and value. */
406 delta = sizeof(uint32_t) + len;
407 kvbuf_grow(kv, delta);
408
409 if (kv->databuf == NULL) return;
410
411 /* increment and rewrite the value count for the value_list dictionary */
412 p = kv->databuf + kv->_vlist;
413
414 x = 0;
415 memcpy(&x, p, sizeof(uint32_t));
416 val_count = ntohl(x);
417 val_count++;
418 x = htonl(val_count);
419 memcpy(p, &x, sizeof(uint32_t));
420
421 /* append val to data buffer */
422 p = kv->databuf + kv->_val;
423
424 x = htonl(len);
425 memcpy(p, &x, sizeof(uint32_t));
426 p += sizeof(uint32_t);
427 memcpy(p, val, len);
428 p += len;
429
430 kv->datalen += delta;
431 kv->_val = kv->datalen;
432 }
433
434 /*
435 * WARNING! Kludge Alert!
436 *
437 * This call just looks for the buffer length encoded into a serialized kvbuf_t,
438 * which preceeds a pointer to a key or value. Obviously, calling it with anything
439 * other than a pointer value which is embedded in a kvbuf_t is asking for trouble.
440 */
441 uint32_t
442 kvbuf_get_len(const char *p)
443 {
444 uint32_t x;
445
446 x = 0;
447 memcpy(&x, p - sizeof(uint32_t), sizeof(uint32_t));
448 return ntohl(x);
449 }
450
451 void
452 kvbuf_add_val(kvbuf_t *kv, const char *val)
453 {
454 if (kv == NULL) return;
455 if (val == NULL) return;
456
457 kvbuf_add_val_len(kv, val, strlen(val) + 1);
458 }
459
460 void
461 kvbuf_make_purgeable(kvbuf_t *kv)
462 {
463 if (kv == NULL) return;
464
465 if (kv->databuf != NULL) malloc_make_purgeable(kv->databuf);
466 }
467
468 int
469 kvbuf_make_nonpurgeable(kvbuf_t *kv)
470 {
471 if (kv == NULL) return 0;
472
473 /*
474 * malloc_make_nonpurgeable returns 0 even if memory was not
475 * allocated from the purgeable zone, so this is safe to call.
476 */
477 if ((kv->databuf == NULL) || (malloc_make_nonpurgeable(kv->databuf) == 0)) return 0;
478
479 /* return non-zero since something failed */
480 return 1;
481 }
482
483 void
484 kvbuf_free(kvbuf_t *kv)
485 {
486 if (kv == NULL) return;
487
488 if (kv->databuf != NULL) free(kv->databuf);
489 memset(kv, 0, sizeof(kvbuf_t));
490 free(kv);
491 }
492
493 /* appends a kvbuf to an existing kvbuf */
494 void
495 kvbuf_append_kvbuf(kvbuf_t *kv, const kvbuf_t *kv2)
496 {
497 uint32_t curr_count, new_count, temp;
498
499 if (kv == NULL) return;
500 if (kv2 == NULL) return;
501
502 curr_count = 0;
503 new_count = 0;
504
505 memcpy(&temp, kv->databuf, sizeof(uint32_t));
506 curr_count = ntohl(temp);
507
508 memcpy(&temp, kv2->databuf, sizeof(uint32_t));
509 new_count = ntohl(temp);
510
511 /* nothing to do */
512 if (new_count == 0) return;
513
514 /* add the dictionary count to the current dictionary counts */
515 curr_count += new_count;
516
517 temp = htonl(curr_count);
518 memcpy(kv->databuf, &temp, sizeof(uint32_t));
519
520 /* grow the current buffer so we can append the new buffer */
521 temp = kv2->datalen - sizeof(uint32_t);
522
523 kvbuf_grow(kv, temp);
524
525 memcpy(kv->databuf + kv->datalen, kv2->databuf + sizeof(uint32_t), temp);
526 kv->datalen += temp;
527 }
528
529 /* returns number of dictionaries */
530 uint32_t
531 kvbuf_reset(kvbuf_t *kv)
532 {
533 uint32_t x;
534
535 if (kv == NULL) return 0;
536 if (kv->databuf == NULL) return 0;
537
538 kv->_dict = 0;
539 kv->_key = 0;
540 kv->_vlist = 0;
541 kv->_val = 0;
542
543 if (kv->datalen < sizeof(uint32_t)) return 0;
544
545 x = 0;
546 memcpy(&x, kv->databuf, sizeof(uint32_t));
547 return ntohl(x);
548 }
549
550 /* advance to next dictionary, returns key count */
551 uint32_t
552 kvbuf_next_dict(kvbuf_t *kv)
553 {
554 uint32_t x, k, v, kcount, vcount, kl, vl;
555 char *p;
556
557 if (kv == NULL) return 0;
558 if (kv->databuf == NULL) return 0;
559
560 kv->_key = 0;
561 kv->_vlist = 0;
562 kv->_val = 0;
563
564 if (kv->_dict == 0)
565 {
566 /* first dict */
567 if (kv->datalen < sizeof(uint32_t)) return 0;
568 kv->_dict = sizeof(uint32_t);
569
570 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
571
572 p = kv->databuf + kv->_dict;
573 x = 0;
574 memcpy(&x, p, sizeof(uint32_t));
575 kcount = ntohl(x);
576
577 return kcount;
578 }
579
580 p = kv->databuf + kv->_dict;
581
582 x = 0;
583 memcpy(&x, p, sizeof(uint32_t));
584 p += sizeof(uint32_t);
585 kv->_dict += sizeof(uint32_t);
586 kcount = ntohl(x);
587
588 for (k = 0; k < kcount; k++)
589 {
590 x = 0;
591 memcpy(&x, p, sizeof(uint32_t));
592 p += sizeof(uint32_t);
593 kv->_dict += sizeof(uint32_t);
594 kl = ntohl(x);
595 p += kl;
596 kv->_dict += kl;
597
598 x = 0;
599 memcpy(&x, p, sizeof(uint32_t));
600 p += sizeof(uint32_t);
601 kv->_dict += sizeof(uint32_t);
602 vcount = ntohl(x);
603
604 for (v = 0; v < vcount; v++)
605 {
606 x = 0;
607 memcpy(&x, p, sizeof(uint32_t));
608 p += sizeof(uint32_t);
609 kv->_dict += sizeof(uint32_t);
610 vl = ntohl(x);
611 p += vl;
612 kv->_dict += vl;
613 }
614 }
615
616 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
617
618 p = kv->databuf + kv->_dict;
619 x = 0;
620 memcpy(&x, p, sizeof(uint32_t));
621 kcount = ntohl(x);
622
623 return kcount;
624 }
625
626 /* advance to next key, returns key and sets val_count */
627 char *
628 kvbuf_next_key(kvbuf_t *kv, uint32_t *val_count)
629 {
630 uint32_t x, kl, v, vl, vc;
631 char *p, *out;
632
633 if (kv == NULL) return NULL;
634 if (val_count == NULL) return NULL;
635
636 *val_count = 0;
637
638 if (kv->databuf == NULL) return NULL;
639 if (kv->_dict == 0) return NULL;
640
641 kv->_vlist = 0;
642 kv->_val = 0;
643
644 if (kv->_key == 0)
645 {
646 /* first key */
647 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return NULL;
648 kv->_key = kv->_dict + sizeof(uint32_t);
649 }
650 else
651 {
652 p = kv->databuf + kv->_key;
653
654 x = 0;
655 memcpy(&x, p, sizeof(uint32_t));
656 kl = ntohl(x);
657
658 if (kv->datalen < (kv->_key + sizeof(uint32_t) + kl)) return NULL;
659
660 p += (sizeof(uint32_t) + kl);
661 kv->_key += (sizeof(uint32_t) + kl);
662
663 /* skip over values */
664 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
665
666 x = 0;
667 memcpy(&x, p, sizeof(uint32_t));
668 vc = ntohl(x);
669
670 p += sizeof(uint32_t);
671 kv->_key += sizeof(uint32_t);
672
673 for (v = 0; v < vc; v++)
674 {
675 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
676
677 x = 0;
678 memcpy(&x, p, sizeof(uint32_t));
679 vl = ntohl(x);
680
681 if (kv->datalen < (kv->_key + kl)) return NULL;
682
683 p += (sizeof(uint32_t) + vl);
684 kv->_key += (sizeof(uint32_t) + vl);
685 }
686 }
687
688 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
689
690 p = kv->databuf + kv->_key;
691 x = 0;
692 memcpy(&x, p, sizeof(uint32_t));
693 kl = ntohl(x);
694
695 p += sizeof(uint32_t);
696 out = p;
697
698 kv->_vlist = kv->_key + sizeof(uint32_t) + kl;
699 if (kv->datalen < (kv->_vlist + sizeof(uint32_t)))
700 {
701 kv->_vlist = 0;
702 return NULL;
703 }
704
705 p = kv->databuf + kv->_vlist;
706 x = 0;
707 memcpy(&x, p, sizeof(uint32_t));
708 *val_count = ntohl(x);
709
710 return out;
711 }
712
713 char *
714 kvbuf_next_val(kvbuf_t *kv)
715 {
716 return kvbuf_next_val_len(kv, NULL);
717 }
718
719 char *
720 kvbuf_next_val_len(kvbuf_t *kv, uint32_t *len)
721 {
722 uint32_t x = 0;
723 uint32_t vltemp = 0;
724 char *p;
725
726 if (kv == NULL) return NULL;
727 if (kv->databuf == NULL) return NULL;
728 if (kv->_vlist == 0) return NULL;
729
730 if (kv->_val == 0)
731 {
732 /* first val */
733 if (kv->datalen < (kv->_vlist + sizeof(uint32_t))) return NULL;
734 kv->_val = kv->_vlist + sizeof(uint32_t);
735
736 p = kv->databuf + kv->_val;
737
738 memcpy(&x, p, sizeof(uint32_t));
739 vltemp = ntohl(x);
740 }
741 else
742 {
743 p = kv->databuf + kv->_val;
744
745 memcpy(&x, p, sizeof(uint32_t));
746 vltemp = ntohl(x);
747
748 if (kv->datalen < (kv->_val + sizeof(uint32_t) + vltemp)) return NULL;
749
750 p += (sizeof(uint32_t) + vltemp);
751 kv->_val += (sizeof(uint32_t) + vltemp);
752 }
753
754 if (kv->datalen < (kv->_val + sizeof(uint32_t))) return NULL;
755
756 if (len != NULL) (*len) = vltemp;
757 p = kv->databuf + kv->_val + sizeof(uint32_t);
758 return p;
759 }
760
761 /*
762 * Builds a kvarray_t / kvdict_t structure on top of a kvbuf_t.
763 * It allocates the appropriate number of kvdict_t structures
764 * for the array, sets all the counters, and fills in pointers
765 * for keys and valuse. The pointers are NOT to newly allocated
766 * strings: they just point into the kvbuf data buffer.
767 *
768 * To dispose of the kvarray_t and all of the associated
769 * memory AND to free the original kvbuf, clients only
770 * need to call kvarray_free().
771 */
772 kvarray_t *
773 kvbuf_decode(kvbuf_t *kv)
774 {
775 kvarray_t *a;
776 uint32_t x, d, k, v;
777 char *p;
778
779 if (kv == NULL) return NULL;
780 if (kv->databuf == NULL) return NULL;
781
782 if (kv->datalen < sizeof(uint32_t)) return NULL;
783
784 p = kv->databuf;
785 kv->_size = kv->datalen;
786
787 /* array count */
788 x = 0;
789 memcpy(&x, p, sizeof(uint32_t));
790 p += sizeof(uint32_t);
791 kv->_size -= sizeof(uint32_t);
792 x = ntohl(x);
793
794 if (x == 0) return NULL;
795
796 a = (kvarray_t *)calloc(1, sizeof(kvarray_t));
797 if (a == NULL) return NULL;
798
799 a->count = x;
800 a->dict = (kvdict_t *)calloc(a->count, sizeof(kvdict_t));
801 if (a->dict == NULL)
802 {
803 free(a);
804 return NULL;
805 }
806
807 for (d = 0; d < a->count; d++)
808 {
809 if (kv->_size < sizeof(uint32_t))
810 {
811 kvarray_free(a);
812 return NULL;
813 }
814
815 /* key count */
816 x = 0;
817 memcpy(&x, p, sizeof(uint32_t));
818 p += sizeof(uint32_t);
819 kv->_size -= sizeof(uint32_t);
820 a->dict[d].kcount = ntohl(x);
821
822 if (a->dict[d].kcount > 0)
823 {
824 a->dict[d].key = (const char **)calloc(a->dict[d].kcount, sizeof(const char *));
825 if (a->dict[d].key == NULL)
826 {
827 kvarray_free(a);
828 return NULL;
829 }
830
831 a->dict[d].vcount = (uint32_t *)calloc(a->dict[d].kcount, sizeof(uint32_t));
832 if (a->dict[d].vcount == NULL)
833 {
834 kvarray_free(a);
835 return NULL;
836 }
837
838 a->dict[d].val = (const char ***)calloc(a->dict[d].kcount, sizeof(char **));
839 if (a->dict[d].val == NULL)
840 {
841 kvarray_free(a);
842 return NULL;
843 }
844 }
845
846 for (k = 0; k < a->dict[d].kcount; k++)
847 {
848 /* get key */
849 if (kv->_size < sizeof(uint32_t))
850 {
851 kvarray_free(a);
852 return NULL;
853 }
854
855 /* key length */
856 x = 0;
857 memcpy(&x, p, sizeof(uint32_t));
858 p += sizeof(uint32_t);
859 kv->_size -= sizeof(uint32_t);
860 x = ntohl(x);
861
862 if (kv->_size < x)
863 {
864 kvarray_free(a);
865 return NULL;
866 }
867
868 /* key data */
869 a->dict[d].key[k] = p;
870
871 p += x;
872 kv->_size -= x;
873
874 if (kv->_size < sizeof(uint32_t))
875 {
876 kvarray_free(a);
877 return NULL;
878 }
879
880 /* val count */
881 x = 0;
882 memcpy(&x, p, sizeof(uint32_t));
883 p += sizeof(uint32_t);
884 kv->_size -= sizeof(uint32_t);
885 a->dict[d].vcount[k] = ntohl(x);
886
887 if (a->dict[d].vcount[k] > 0)
888 {
889 /* N.B. we add a NULL pointer at the end of the list */
890 a->dict[d].val[k] = (const char **)calloc(a->dict[d].vcount[k] + 1, sizeof(const char *));
891 if (a->dict[d].val[k] == NULL)
892 {
893 kvarray_free(a);
894 return NULL;
895 }
896 }
897
898 for (v = 0; v < a->dict[d].vcount[k]; v++)
899 {
900 /* get val */
901 if (kv->_size < sizeof(uint32_t))
902 {
903 kvarray_free(a);
904 return NULL;
905 }
906
907 /* val length */
908 x = 0;
909 memcpy(&x, p, sizeof(uint32_t));
910 p += sizeof(uint32_t);
911 kv->_size -= sizeof(uint32_t);
912 x = ntohl(x);
913
914 if (kv->_size < x)
915 {
916 kvarray_free(a);
917 return NULL;
918 }
919
920 /* val data */
921 a->dict[d].val[k][v] = p;
922
923 p += x;
924 kv->_size -= x;
925 }
926 }
927 }
928
929 a->kv = kv;
930 return a;
931 }
932
933 void
934 kvarray_free(kvarray_t *a)
935 {
936 uint32_t d, k;
937
938 if (a == NULL) return;
939
940 for (d = 0; d < a->count; d++)
941 {
942 for (k = 0; k < a->dict[d].kcount; k++)
943 {
944 if (a->dict[d].val == NULL) continue;
945 if (a->dict[d].val[k] != NULL) free(a->dict[d].val[k]);
946 }
947
948 if (a->dict[d].key != NULL) free(a->dict[d].key);
949 if (a->dict[d].vcount != NULL) free(a->dict[d].vcount);
950 if (a->dict[d].val != NULL) free(a->dict[d].val);
951 }
952
953 a->count = 0;
954
955 if (a->dict != NULL) free(a->dict);
956 a->dict = NULL;
957
958 if (a->kv != NULL) kvbuf_free(a->kv);
959 a->kv = NULL;
960
961 free(a);
962 }
963