Libinfo-391.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 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 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 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 if (length > 0)
252 {
253 kv->databuf = malloc_zone_calloc(zone, 1, length);
254 if (kv->databuf == NULL)
255 {
256 free(kv);
257 kv = NULL;
258 }
259 else
260 {
261 memcpy(kv->databuf, buffer, length);
262 }
263 }
264
265 return kv;
266 }
267
268 kvbuf_t *
269 kvbuf_init(char *buffer, uint32_t length)
270 {
271 return kvbuf_init_zone(malloc_default_zone(), buffer, length);
272 }
273
274 static void
275 kvbuf_grow(kvbuf_t *kv, uint32_t delta)
276 {
277 uint32_t newlen;
278 char *p, *newbuf;
279 malloc_zone_t *zone;
280
281 if (kv == NULL) return;
282 if (delta == 0) return;
283
284 if (kv->databuf == NULL) delta += sizeof(uint32_t);
285
286 newlen = kv->datalen + delta;
287 if (newlen <= kv->_size) return;
288
289 kv->_size = ((newlen + KVBUF_CHUNK - 1) / KVBUF_CHUNK) * KVBUF_CHUNK;
290
291 zone = malloc_zone_from_ptr(kv);
292 if (kv->databuf == NULL)
293 {
294 kv->databuf = malloc_zone_calloc(zone, 1, kv->_size);
295 if (kv->databuf == NULL)
296 {
297 memset(kv, 0, sizeof(kvbuf_t));
298 return;
299 }
300
301 kv->datalen = sizeof(uint32_t);
302 kv->_dict = sizeof(uint32_t);
303 }
304 else
305 {
306 newbuf = malloc_zone_realloc(zone, kv->databuf, kv->_size);
307 if (newbuf == NULL) free(kv->databuf);
308 kv->databuf = newbuf;
309 if (kv->databuf == NULL)
310 {
311 memset(kv, 0, sizeof(kvbuf_t));
312 return;
313 }
314
315 p = kv->databuf + kv->datalen;
316 memset(p, 0, kv->_size - kv->datalen);
317 }
318 }
319
320 void
321 kvbuf_add_dict(kvbuf_t *kv)
322 {
323 char *p;
324 uint32_t x, dict_count;
325
326 if (kv == NULL) return;
327
328 /* Add a key count */
329 kvbuf_grow(kv, sizeof(uint32_t));
330 if (kv->databuf == NULL) return;
331
332 kv->_dict = kv->datalen;
333 kv->datalen += sizeof(uint32_t);
334
335 kv->_key = kv->datalen;
336 kv->_vlist = 0;
337 kv->_val = 0;
338
339 /* increment and rewrite the dict count */
340 p = kv->databuf;
341
342 x = 0;
343 memcpy(&x, p, sizeof(uint32_t));
344 dict_count = ntohl(x);
345
346 dict_count++;
347 x = htonl(dict_count);
348 memcpy(p, &x, sizeof(uint32_t));
349 }
350
351 void
352 kvbuf_add_key(kvbuf_t *kv, const char *key)
353 {
354 uint32_t kl, x, key_count, delta;
355 char *p;
356
357 if (kv == NULL) return;
358 if (key == NULL) return;
359
360 kl = strlen(key) + 1;
361
362 /* Grow to hold key len, key, and value list count. */
363 delta = (2 * sizeof(uint32_t)) + kl;
364 kvbuf_grow(kv, delta);
365
366 if (kv->databuf == NULL) return;
367
368 /* increment and rewrite the key count for the current dictionary */
369 p = kv->databuf + kv->_dict;
370
371 x = 0;
372 memcpy(&x, p, sizeof(uint32_t));
373 key_count = ntohl(x);
374
375 if (key_count == 0) kv->_key = kv->_dict + sizeof(uint32_t);
376 else kv->_key = kv->datalen;
377
378 key_count++;
379 x = htonl(key_count);
380 memcpy(p, &x, sizeof(uint32_t));
381
382 /* append key to data buffer */
383 p = kv->databuf + kv->datalen;
384
385 x = htonl(kl);
386 memcpy(p, &x, sizeof(uint32_t));
387 p += sizeof(uint32_t);
388 memcpy(p, key, kl);
389 p += kl;
390
391 kv->_vlist = kv->datalen + sizeof(uint32_t) + kl;
392
393 x = 0;
394 memcpy(p, &x, sizeof(uint32_t));
395
396 kv->datalen += delta;
397 kv->_val = kv->datalen;
398 }
399
400 void
401 kvbuf_add_val_len(kvbuf_t *kv, const char *val, uint32_t len)
402 {
403 uint32_t x, val_count, delta;
404 char *p;
405
406 if (kv == NULL) return;
407 if (val == NULL) return;
408 if (len == 0) return;
409
410 /* Grow to hold val len and value. */
411 delta = sizeof(uint32_t) + len;
412 kvbuf_grow(kv, delta);
413
414 if (kv->databuf == NULL) return;
415
416 /* increment and rewrite the value count for the value_list dictionary */
417 p = kv->databuf + kv->_vlist;
418
419 x = 0;
420 memcpy(&x, p, sizeof(uint32_t));
421 val_count = ntohl(x);
422 val_count++;
423 x = htonl(val_count);
424 memcpy(p, &x, sizeof(uint32_t));
425
426 /* append val to data buffer */
427 p = kv->databuf + kv->_val;
428
429 x = htonl(len);
430 memcpy(p, &x, sizeof(uint32_t));
431 p += sizeof(uint32_t);
432 memcpy(p, val, len);
433 p += len;
434
435 kv->datalen += delta;
436 kv->_val = kv->datalen;
437 }
438
439 /*
440 * WARNING! Kludge Alert!
441 *
442 * This call just looks for the buffer length encoded into a serialized kvbuf_t,
443 * which preceeds a pointer to a key or value. Obviously, calling it with anything
444 * other than a pointer value which is embedded in a kvbuf_t is asking for trouble.
445 */
446 uint32_t
447 kvbuf_get_len(const char *p)
448 {
449 uint32_t x;
450
451 x = 0;
452 memcpy(&x, p - sizeof(uint32_t), sizeof(uint32_t));
453 return ntohl(x);
454 }
455
456 void
457 kvbuf_add_val(kvbuf_t *kv, const char *val)
458 {
459 if (kv == NULL) return;
460 if (val == NULL) return;
461
462 kvbuf_add_val_len(kv, val, strlen(val) + 1);
463 }
464
465 void
466 kvbuf_make_purgeable(kvbuf_t *kv)
467 {
468 if (kv == NULL) return;
469
470 if (kv->databuf != NULL) malloc_make_purgeable(kv->databuf);
471 }
472
473 int
474 kvbuf_make_nonpurgeable(kvbuf_t *kv)
475 {
476 if (kv == NULL) return 0;
477
478 /*
479 * malloc_make_nonpurgeable returns 0 even if memory was not
480 * allocated from the purgeable zone, so this is safe to call.
481 */
482 if ((kv->databuf == NULL) || (malloc_make_nonpurgeable(kv->databuf) == 0)) return 0;
483
484 /* return non-zero since something failed */
485 return 1;
486 }
487
488 void
489 kvbuf_free(kvbuf_t *kv)
490 {
491 if (kv == NULL) return;
492
493 if (kv->databuf != NULL) free(kv->databuf);
494 memset(kv, 0, sizeof(kvbuf_t));
495 free(kv);
496 }
497
498 /* appends a kvbuf to an existing kvbuf */
499 void
500 kvbuf_append_kvbuf(kvbuf_t *kv, const kvbuf_t *kv2)
501 {
502 uint32_t curr_count, new_count, temp;
503
504 if (kv == NULL) return;
505 if (kv2 == NULL) return;
506
507 curr_count = 0;
508 new_count = 0;
509
510 memcpy(&temp, kv->databuf, sizeof(uint32_t));
511 curr_count = ntohl(temp);
512
513 memcpy(&temp, kv2->databuf, sizeof(uint32_t));
514 new_count = ntohl(temp);
515
516 /* nothing to do */
517 if (new_count == 0) return;
518
519 /* add the dictionary count to the current dictionary counts */
520 curr_count += new_count;
521
522 temp = htonl(curr_count);
523 memcpy(kv->databuf, &temp, sizeof(uint32_t));
524
525 /* grow the current buffer so we can append the new buffer */
526 temp = kv2->datalen - sizeof(uint32_t);
527
528 kvbuf_grow(kv, temp);
529
530 memcpy(kv->databuf + kv->datalen, kv2->databuf + sizeof(uint32_t), temp);
531 kv->datalen += temp;
532 }
533
534 /* returns number of dictionaries */
535 uint32_t
536 kvbuf_reset(kvbuf_t *kv)
537 {
538 uint32_t x;
539
540 if (kv == NULL) return 0;
541 if (kv->databuf == NULL) return 0;
542
543 kv->_dict = 0;
544 kv->_key = 0;
545 kv->_vlist = 0;
546 kv->_val = 0;
547
548 if (kv->datalen < sizeof(uint32_t)) return 0;
549
550 x = 0;
551 memcpy(&x, kv->databuf, sizeof(uint32_t));
552 return ntohl(x);
553 }
554
555 /* advance to next dictionary, returns key count */
556 uint32_t
557 kvbuf_next_dict(kvbuf_t *kv)
558 {
559 uint32_t x, k, v, kcount, vcount, kl, vl;
560 char *p;
561
562 if (kv == NULL) return 0;
563 if (kv->databuf == NULL) return 0;
564
565 kv->_key = 0;
566 kv->_vlist = 0;
567 kv->_val = 0;
568
569 if (kv->_dict == 0)
570 {
571 /* first dict */
572 if (kv->datalen < sizeof(uint32_t)) return 0;
573 kv->_dict = sizeof(uint32_t);
574
575 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
576
577 p = kv->databuf + kv->_dict;
578 x = 0;
579 memcpy(&x, p, sizeof(uint32_t));
580 kcount = ntohl(x);
581
582 return kcount;
583 }
584
585 p = kv->databuf + kv->_dict;
586
587 x = 0;
588 memcpy(&x, p, sizeof(uint32_t));
589 p += sizeof(uint32_t);
590 kv->_dict += sizeof(uint32_t);
591 kcount = ntohl(x);
592
593 for (k = 0; k < kcount; k++)
594 {
595 x = 0;
596 memcpy(&x, p, sizeof(uint32_t));
597 p += sizeof(uint32_t);
598 kv->_dict += sizeof(uint32_t);
599 kl = ntohl(x);
600 p += kl;
601 kv->_dict += kl;
602
603 x = 0;
604 memcpy(&x, p, sizeof(uint32_t));
605 p += sizeof(uint32_t);
606 kv->_dict += sizeof(uint32_t);
607 vcount = ntohl(x);
608
609 for (v = 0; v < vcount; v++)
610 {
611 x = 0;
612 memcpy(&x, p, sizeof(uint32_t));
613 p += sizeof(uint32_t);
614 kv->_dict += sizeof(uint32_t);
615 vl = ntohl(x);
616 p += vl;
617 kv->_dict += vl;
618 }
619 }
620
621 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
622
623 p = kv->databuf + kv->_dict;
624 x = 0;
625 memcpy(&x, p, sizeof(uint32_t));
626 kcount = ntohl(x);
627
628 return kcount;
629 }
630
631 /* advance to next key, returns key and sets val_count */
632 char *
633 kvbuf_next_key(kvbuf_t *kv, uint32_t *val_count)
634 {
635 uint32_t x, kl, v, vl, vc;
636 char *p, *out;
637
638 if (kv == NULL) return NULL;
639 if (val_count == NULL) return NULL;
640
641 *val_count = 0;
642
643 if (kv->databuf == NULL) return NULL;
644 if (kv->_dict == 0) return NULL;
645
646 kv->_vlist = 0;
647 kv->_val = 0;
648
649 if (kv->_key == 0)
650 {
651 /* first key */
652 if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return NULL;
653 kv->_key = kv->_dict + sizeof(uint32_t);
654 }
655 else
656 {
657 p = kv->databuf + kv->_key;
658
659 x = 0;
660 memcpy(&x, p, sizeof(uint32_t));
661 kl = ntohl(x);
662
663 if (kv->datalen < (kv->_key + sizeof(uint32_t) + kl)) return NULL;
664
665 p += (sizeof(uint32_t) + kl);
666 kv->_key += (sizeof(uint32_t) + kl);
667
668 /* skip over values */
669 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
670
671 x = 0;
672 memcpy(&x, p, sizeof(uint32_t));
673 vc = ntohl(x);
674
675 p += sizeof(uint32_t);
676 kv->_key += sizeof(uint32_t);
677
678 for (v = 0; v < vc; v++)
679 {
680 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
681
682 x = 0;
683 memcpy(&x, p, sizeof(uint32_t));
684 vl = ntohl(x);
685
686 if (kv->datalen < (kv->_key + kl)) return NULL;
687
688 p += (sizeof(uint32_t) + vl);
689 kv->_key += (sizeof(uint32_t) + vl);
690 }
691 }
692
693 if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
694
695 p = kv->databuf + kv->_key;
696 x = 0;
697 memcpy(&x, p, sizeof(uint32_t));
698 kl = ntohl(x);
699
700 p += sizeof(uint32_t);
701 out = p;
702
703 kv->_vlist = kv->_key + sizeof(uint32_t) + kl;
704 if (kv->datalen < (kv->_vlist + sizeof(uint32_t)))
705 {
706 kv->_vlist = 0;
707 return NULL;
708 }
709
710 p = kv->databuf + kv->_vlist;
711 x = 0;
712 memcpy(&x, p, sizeof(uint32_t));
713 *val_count = ntohl(x);
714
715 return out;
716 }
717
718 char *
719 kvbuf_next_val(kvbuf_t *kv)
720 {
721 return kvbuf_next_val_len(kv, NULL);
722 }
723
724 char *
725 kvbuf_next_val_len(kvbuf_t *kv, uint32_t *len)
726 {
727 uint32_t x = 0;
728 uint32_t vltemp = 0;
729 char *p;
730
731 if (kv == NULL) return NULL;
732 if (kv->databuf == NULL) return NULL;
733 if (kv->_vlist == 0) return NULL;
734
735 if (kv->_val == 0)
736 {
737 /* first val */
738 if (kv->datalen < (kv->_vlist + sizeof(uint32_t))) return NULL;
739 kv->_val = kv->_vlist + sizeof(uint32_t);
740
741 p = kv->databuf + kv->_val;
742
743 memcpy(&x, p, sizeof(uint32_t));
744 vltemp = ntohl(x);
745 }
746 else
747 {
748 p = kv->databuf + kv->_val;
749
750 memcpy(&x, p, sizeof(uint32_t));
751 vltemp = ntohl(x);
752
753 if (kv->datalen < (kv->_val + sizeof(uint32_t) + vltemp)) return NULL;
754
755 p += (sizeof(uint32_t) + vltemp);
756 kv->_val += (sizeof(uint32_t) + vltemp);
757 }
758
759 if (kv->datalen < (kv->_val + sizeof(uint32_t))) return NULL;
760
761 if (len != NULL) (*len) = vltemp;
762 p = kv->databuf + kv->_val + sizeof(uint32_t);
763 return p;
764 }
765
766 /*
767 * Builds a kvarray_t / kvdict_t structure on top of a kvbuf_t.
768 * It allocates the appropriate number of kvdict_t structures
769 * for the array, sets all the counters, and fills in pointers
770 * for keys and valuse. The pointers are NOT to newly allocated
771 * strings: they just point into the kvbuf data buffer.
772 *
773 * To dispose of the kvarray_t and all of the associated
774 * memory AND to free the original kvbuf, clients only
775 * need to call kvarray_free().
776 */
777 kvarray_t *
778 kvbuf_decode(kvbuf_t *kv)
779 {
780 kvarray_t *a;
781 uint32_t x, d, k, v;
782 char *p;
783
784 if (kv == NULL) return NULL;
785 if (kv->databuf == NULL) return NULL;
786
787 if (kv->datalen < sizeof(uint32_t)) return NULL;
788
789 p = kv->databuf;
790 kv->_size = kv->datalen;
791
792 /* array count */
793 x = 0;
794 memcpy(&x, p, sizeof(uint32_t));
795 p += sizeof(uint32_t);
796 kv->_size -= sizeof(uint32_t);
797 x = ntohl(x);
798
799 if (x == 0) return NULL;
800
801 a = (kvarray_t *)calloc(1, sizeof(kvarray_t));
802 if (a == NULL) return NULL;
803
804 a->count = x;
805 a->dict = (kvdict_t *)calloc(a->count, sizeof(kvdict_t));
806 if (a->dict == NULL)
807 {
808 free(a);
809 return NULL;
810 }
811
812 for (d = 0; d < a->count; d++)
813 {
814 if (kv->_size < sizeof(uint32_t))
815 {
816 kvarray_free(a);
817 return NULL;
818 }
819
820 /* key count */
821 x = 0;
822 memcpy(&x, p, sizeof(uint32_t));
823 p += sizeof(uint32_t);
824 kv->_size -= sizeof(uint32_t);
825 a->dict[d].kcount = ntohl(x);
826
827 if (a->dict[d].kcount > 0)
828 {
829 a->dict[d].key = (const char **)calloc(a->dict[d].kcount, sizeof(const char *));
830 if (a->dict[d].key == NULL)
831 {
832 kvarray_free(a);
833 return NULL;
834 }
835
836 a->dict[d].vcount = (uint32_t *)calloc(a->dict[d].kcount, sizeof(uint32_t));
837 if (a->dict[d].vcount == NULL)
838 {
839 kvarray_free(a);
840 return NULL;
841 }
842
843 a->dict[d].val = (const char ***)calloc(a->dict[d].kcount, sizeof(char **));
844 if (a->dict[d].val == NULL)
845 {
846 kvarray_free(a);
847 return NULL;
848 }
849 }
850
851 for (k = 0; k < a->dict[d].kcount; k++)
852 {
853 /* get key */
854 if (kv->_size < sizeof(uint32_t))
855 {
856 kvarray_free(a);
857 return NULL;
858 }
859
860 /* key length */
861 x = 0;
862 memcpy(&x, p, sizeof(uint32_t));
863 p += sizeof(uint32_t);
864 kv->_size -= sizeof(uint32_t);
865 x = ntohl(x);
866
867 if (kv->_size < x)
868 {
869 kvarray_free(a);
870 return NULL;
871 }
872
873 /* key data */
874 a->dict[d].key[k] = p;
875
876 p += x;
877 kv->_size -= x;
878
879 if (kv->_size < sizeof(uint32_t))
880 {
881 kvarray_free(a);
882 return NULL;
883 }
884
885 /* val count */
886 x = 0;
887 memcpy(&x, p, sizeof(uint32_t));
888 p += sizeof(uint32_t);
889 kv->_size -= sizeof(uint32_t);
890 a->dict[d].vcount[k] = ntohl(x);
891
892 if (a->dict[d].vcount[k] > 0)
893 {
894 /* N.B. we add a NULL pointer at the end of the list */
895 a->dict[d].val[k] = (const char **)calloc(a->dict[d].vcount[k] + 1, sizeof(const char *));
896 if (a->dict[d].val[k] == NULL)
897 {
898 kvarray_free(a);
899 return NULL;
900 }
901 }
902
903 for (v = 0; v < a->dict[d].vcount[k]; v++)
904 {
905 /* get val */
906 if (kv->_size < sizeof(uint32_t))
907 {
908 kvarray_free(a);
909 return NULL;
910 }
911
912 /* val length */
913 x = 0;
914 memcpy(&x, p, sizeof(uint32_t));
915 p += sizeof(uint32_t);
916 kv->_size -= sizeof(uint32_t);
917 x = ntohl(x);
918
919 if (kv->_size < x)
920 {
921 kvarray_free(a);
922 return NULL;
923 }
924
925 /* val data */
926 a->dict[d].val[k][v] = p;
927
928 p += x;
929 kv->_size -= x;
930 }
931 }
932 }
933
934 a->kv = kv;
935 return a;
936 }
937
938 void
939 kvarray_free(kvarray_t *a)
940 {
941 uint32_t d, k;
942
943 if (a == NULL) return;
944
945 for (d = 0; d < a->count; d++)
946 {
947 for (k = 0; k < a->dict[d].kcount; k++)
948 {
949 if (a->dict[d].val == NULL) continue;
950 if (a->dict[d].val[k] != NULL) free(a->dict[d].val[k]);
951 }
952
953 if (a->dict[d].key != NULL) free(a->dict[d].key);
954 if (a->dict[d].vcount != NULL) free(a->dict[d].vcount);
955 if (a->dict[d].val != NULL) free(a->dict[d].val);
956 }
957
958 a->count = 0;
959
960 if (a->dict != NULL) free(a->dict);
961 a->dict = NULL;
962
963 if (a->kv != NULL) kvbuf_free(a->kv);
964 a->kv = NULL;
965
966 free(a);
967 }
968