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