]>
git.saurik.com Git - apple/libinfo.git/blob - lookup.subproj/kvbuf.c
2 * Copyright (c) 2009-2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "libinfo_common.h"
32 #define KVBUF_CHUNK 256
35 * kvbuf_t is a list of key/value dictionaries.
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
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.
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.
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.
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.
62 * The cache_entry_list_to_kvbuf() routine contains the only
63 * code that builds an array.
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.
76 kvbuf_query(char *fmt
, ...)
79 char *arg
, *f
, str
[32];
84 if (fmt
== NULL
) return NULL
;
87 if (kv
== NULL
) return NULL
;
92 for (f
= fmt
; (*f
) != '\0'; f
++)
96 arg
= va_arg(ap
, char *);
97 kvbuf_add_key(kv
, arg
);
101 arg
= va_arg(ap
, char *);
102 kvbuf_add_val(kv
, arg
);
106 iarg
= va_arg(ap
, int32_t);
107 snprintf(str
, sizeof(str
), "%d", iarg
);
108 kvbuf_add_val(kv
, str
);
112 uarg
= va_arg(ap
,uint32_t);
113 snprintf(str
, sizeof(str
), "%u", uarg
);
114 kvbuf_add_val(kv
, str
);
124 kvbuf_query_key_val(const char *key
, const char *val
)
127 uint32_t x
, kl
, vl
, vc
;
130 if (key
== NULL
) return NULL
;
132 kl
= strlen(key
) + 1;
139 vl
= strlen(val
) + 1;
143 kv
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
144 if (kv
== NULL
) return NULL
;
146 kv
->_size
= (5 * sizeof(uint32_t)) + kl
+ vl
;
147 kv
->datalen
= kv
->_size
;
149 kv
->databuf
= calloc(1, kv
->_size
);
150 if (kv
->databuf
== NULL
)
160 memcpy(p
, &x
, sizeof(uint32_t));
161 p
+= sizeof(uint32_t);
164 memcpy(p
, &x
, sizeof(uint32_t));
165 p
+= sizeof(uint32_t);
169 memcpy(p
, &x
, sizeof(uint32_t));
170 p
+= sizeof(uint32_t);
176 /* number of values */
178 memcpy(p
, &x
, sizeof(uint32_t));
179 p
+= sizeof(uint32_t);
185 memcpy(p
, &x
, sizeof(uint32_t));
186 p
+= sizeof(uint32_t);
197 kvbuf_query_key_int(const char *key
, int32_t i
)
201 snprintf(str
, sizeof(str
), "%d", i
);
202 return kvbuf_query_key_val(key
, str
);
207 kvbuf_query_key_uint(const char *key
, uint32_t u
)
211 snprintf(str
, sizeof(str
), "%u", u
);
212 return kvbuf_query_key_val(key
, str
);
217 kvbuf_new_zone(malloc_zone_t
*zone
)
221 if (zone
== NULL
) return NULL
;
223 kv
= (kvbuf_t
*)malloc_zone_calloc(zone
, 1, sizeof(kvbuf_t
));
224 if (kv
== NULL
) return NULL
;
226 kv
->_size
= KVBUF_START_SIZE
;
227 kv
->databuf
= malloc_zone_calloc(zone
, 1, kv
->_size
);
228 if (kv
->databuf
== NULL
)
234 kv
->datalen
= sizeof(uint32_t);
235 kv
->_dict
= kv
->datalen
;
244 return kvbuf_new_zone(malloc_default_zone());
249 kvbuf_init_zone(malloc_zone_t
*zone
, char *buffer
, uint32_t length
)
253 if (zone
== NULL
) return NULL
;
255 kv
= (kvbuf_t
*)malloc_zone_calloc(zone
, 1, sizeof(kvbuf_t
));
256 if (kv
== NULL
) return NULL
;
259 kv
->datalen
= length
;
262 kv
->databuf
= malloc_zone_calloc(zone
, 1, length
);
263 if (kv
->databuf
== NULL
)
270 memcpy(kv
->databuf
, buffer
, length
);
279 kvbuf_init(char *buffer
, uint32_t length
)
281 return kvbuf_init_zone(malloc_default_zone(), buffer
, length
);
285 kvbuf_grow(kvbuf_t
*kv
, uint32_t delta
)
291 if (kv
== NULL
) return;
292 if (delta
== 0) return;
294 if (kv
->databuf
== NULL
) delta
+= sizeof(uint32_t);
296 newlen
= kv
->datalen
+ delta
;
297 if (newlen
<= kv
->_size
) return;
299 kv
->_size
= ((newlen
+ KVBUF_CHUNK
- 1) / KVBUF_CHUNK
) * KVBUF_CHUNK
;
301 zone
= malloc_zone_from_ptr(kv
);
302 if (kv
->databuf
== NULL
)
304 kv
->databuf
= malloc_zone_calloc(zone
, 1, kv
->_size
);
305 if (kv
->databuf
== NULL
)
307 memset(kv
, 0, sizeof(kvbuf_t
));
311 kv
->datalen
= sizeof(uint32_t);
312 kv
->_dict
= sizeof(uint32_t);
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
)
321 memset(kv
, 0, sizeof(kvbuf_t
));
325 p
= kv
->databuf
+ kv
->datalen
;
326 memset(p
, 0, kv
->_size
- kv
->datalen
);
332 kvbuf_add_dict(kvbuf_t
*kv
)
335 uint32_t x
, dict_count
;
337 if (kv
== NULL
) return;
339 /* Add a key count */
340 kvbuf_grow(kv
, sizeof(uint32_t));
341 if (kv
->databuf
== NULL
) return;
343 kv
->_dict
= kv
->datalen
;
344 kv
->datalen
+= sizeof(uint32_t);
346 kv
->_key
= kv
->datalen
;
350 /* increment and rewrite the dict count */
354 memcpy(&x
, p
, sizeof(uint32_t));
355 dict_count
= ntohl(x
);
358 x
= htonl(dict_count
);
359 memcpy(p
, &x
, sizeof(uint32_t));
364 kvbuf_add_key(kvbuf_t
*kv
, const char *key
)
366 uint32_t kl
, x
, key_count
, delta
;
369 if (kv
== NULL
) return;
370 if (key
== NULL
) return;
372 kl
= strlen(key
) + 1;
374 /* Grow to hold key len, key, and value list count. */
375 delta
= (2 * sizeof(uint32_t)) + kl
;
376 kvbuf_grow(kv
, delta
);
378 if (kv
->databuf
== NULL
) return;
380 /* increment and rewrite the key count for the current dictionary */
381 p
= kv
->databuf
+ kv
->_dict
;
384 memcpy(&x
, p
, sizeof(uint32_t));
385 key_count
= ntohl(x
);
387 if (key_count
== 0) kv
->_key
= kv
->_dict
+ sizeof(uint32_t);
388 else kv
->_key
= kv
->datalen
;
391 x
= htonl(key_count
);
392 memcpy(p
, &x
, sizeof(uint32_t));
394 /* append key to data buffer */
395 p
= kv
->databuf
+ kv
->datalen
;
398 memcpy(p
, &x
, sizeof(uint32_t));
399 p
+= sizeof(uint32_t);
403 kv
->_vlist
= kv
->datalen
+ sizeof(uint32_t) + kl
;
406 memcpy(p
, &x
, sizeof(uint32_t));
408 kv
->datalen
+= delta
;
409 kv
->_val
= kv
->datalen
;
414 kvbuf_add_val_len(kvbuf_t
*kv
, const char *val
, uint32_t len
)
416 uint32_t x
, val_count
, delta
;
419 if (kv
== NULL
) return;
420 if (val
== NULL
) return;
421 if (len
== 0) return;
423 /* Grow to hold val len and value. */
424 delta
= sizeof(uint32_t) + len
;
425 kvbuf_grow(kv
, delta
);
427 if (kv
->databuf
== NULL
) return;
429 /* increment and rewrite the value count for the value_list dictionary */
430 p
= kv
->databuf
+ kv
->_vlist
;
433 memcpy(&x
, p
, sizeof(uint32_t));
434 val_count
= ntohl(x
);
436 x
= htonl(val_count
);
437 memcpy(p
, &x
, sizeof(uint32_t));
439 /* append val to data buffer */
440 p
= kv
->databuf
+ kv
->_val
;
443 memcpy(p
, &x
, sizeof(uint32_t));
444 p
+= sizeof(uint32_t);
448 kv
->datalen
+= delta
;
449 kv
->_val
= kv
->datalen
;
453 * WARNING! Kludge Alert!
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.
461 kvbuf_get_len(const char *p
)
466 memcpy(&x
, p
- sizeof(uint32_t), sizeof(uint32_t));
472 kvbuf_add_val(kvbuf_t
*kv
, const char *val
)
474 if (kv
== NULL
) return;
475 if (val
== NULL
) return;
477 kvbuf_add_val_len(kv
, val
, strlen(val
) + 1);
482 kvbuf_make_purgeable(kvbuf_t
*kv
)
484 if (kv
== NULL
) return;
486 if (kv
->databuf
!= NULL
) malloc_make_purgeable(kv
->databuf
);
491 kvbuf_make_nonpurgeable(kvbuf_t
*kv
)
493 if (kv
== NULL
) return 0;
496 * malloc_make_nonpurgeable returns 0 even if memory was not
497 * allocated from the purgeable zone, so this is safe to call.
499 if ((kv
->databuf
== NULL
) || (malloc_make_nonpurgeable(kv
->databuf
) == 0)) return 0;
501 /* return non-zero since something failed */
507 kvbuf_free(kvbuf_t
*kv
)
509 if (kv
== NULL
) return;
511 if (kv
->databuf
!= NULL
) free(kv
->databuf
);
512 memset(kv
, 0, sizeof(kvbuf_t
));
516 /* appends a kvbuf to an existing kvbuf */
519 kvbuf_append_kvbuf(kvbuf_t
*kv
, const kvbuf_t
*kv2
)
521 uint32_t curr_count
, new_count
, temp
;
523 if (kv
== NULL
) return;
524 if (kv2
== NULL
) return;
529 memcpy(&temp
, kv
->databuf
, sizeof(uint32_t));
530 curr_count
= ntohl(temp
);
532 memcpy(&temp
, kv2
->databuf
, sizeof(uint32_t));
533 new_count
= ntohl(temp
);
536 if (new_count
== 0) return;
538 /* add the dictionary count to the current dictionary counts */
539 curr_count
+= new_count
;
541 temp
= htonl(curr_count
);
542 memcpy(kv
->databuf
, &temp
, sizeof(uint32_t));
544 /* grow the current buffer so we can append the new buffer */
545 temp
= kv2
->datalen
- sizeof(uint32_t);
547 kvbuf_grow(kv
, temp
);
549 memcpy(kv
->databuf
+ kv
->datalen
, kv2
->databuf
+ sizeof(uint32_t), temp
);
553 /* returns number of dictionaries */
556 kvbuf_reset(kvbuf_t
*kv
)
560 if (kv
== NULL
) return 0;
561 if (kv
->databuf
== NULL
) return 0;
568 if (kv
->datalen
< sizeof(uint32_t)) return 0;
571 memcpy(&x
, kv
->databuf
, sizeof(uint32_t));
575 /* advance to next dictionary, returns key count */
578 kvbuf_next_dict(kvbuf_t
*kv
)
580 uint32_t x
, k
, v
, kcount
, vcount
, kl
, vl
;
583 if (kv
== NULL
) return 0;
584 if (kv
->databuf
== NULL
) return 0;
593 if (kv
->datalen
< sizeof(uint32_t)) return 0;
594 kv
->_dict
= sizeof(uint32_t);
596 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return 0;
598 p
= kv
->databuf
+ kv
->_dict
;
600 memcpy(&x
, p
, sizeof(uint32_t));
606 p
= kv
->databuf
+ kv
->_dict
;
609 memcpy(&x
, p
, sizeof(uint32_t));
610 p
+= sizeof(uint32_t);
611 kv
->_dict
+= sizeof(uint32_t);
614 for (k
= 0; k
< kcount
; k
++)
617 memcpy(&x
, p
, sizeof(uint32_t));
618 p
+= sizeof(uint32_t);
619 kv
->_dict
+= sizeof(uint32_t);
625 memcpy(&x
, p
, sizeof(uint32_t));
626 p
+= sizeof(uint32_t);
627 kv
->_dict
+= sizeof(uint32_t);
630 for (v
= 0; v
< vcount
; v
++)
633 memcpy(&x
, p
, sizeof(uint32_t));
634 p
+= sizeof(uint32_t);
635 kv
->_dict
+= sizeof(uint32_t);
642 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return 0;
644 p
= kv
->databuf
+ kv
->_dict
;
646 memcpy(&x
, p
, sizeof(uint32_t));
652 /* advance to next key, returns key and sets val_count */
655 kvbuf_next_key(kvbuf_t
*kv
, uint32_t *val_count
)
657 uint32_t x
, kl
, v
, vl
, vc
;
660 if (kv
== NULL
) return NULL
;
661 if (val_count
== NULL
) return NULL
;
665 if (kv
->databuf
== NULL
) return NULL
;
666 if (kv
->_dict
== 0) return NULL
;
674 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return NULL
;
675 kv
->_key
= kv
->_dict
+ sizeof(uint32_t);
679 p
= kv
->databuf
+ kv
->_key
;
682 memcpy(&x
, p
, sizeof(uint32_t));
685 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t) + kl
)) return NULL
;
687 p
+= (sizeof(uint32_t) + kl
);
688 kv
->_key
+= (sizeof(uint32_t) + kl
);
690 /* skip over values */
691 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
694 memcpy(&x
, p
, sizeof(uint32_t));
697 p
+= sizeof(uint32_t);
698 kv
->_key
+= sizeof(uint32_t);
700 for (v
= 0; v
< vc
; v
++)
702 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
705 memcpy(&x
, p
, sizeof(uint32_t));
708 if (kv
->datalen
< (kv
->_key
+ kl
)) return NULL
;
710 p
+= (sizeof(uint32_t) + vl
);
711 kv
->_key
+= (sizeof(uint32_t) + vl
);
715 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
717 p
= kv
->databuf
+ kv
->_key
;
719 memcpy(&x
, p
, sizeof(uint32_t));
722 p
+= sizeof(uint32_t);
725 kv
->_vlist
= kv
->_key
+ sizeof(uint32_t) + kl
;
726 if (kv
->datalen
< (kv
->_vlist
+ sizeof(uint32_t)))
732 p
= kv
->databuf
+ kv
->_vlist
;
734 memcpy(&x
, p
, sizeof(uint32_t));
735 *val_count
= ntohl(x
);
742 kvbuf_next_val(kvbuf_t
*kv
)
744 return kvbuf_next_val_len(kv
, NULL
);
749 kvbuf_next_val_len(kvbuf_t
*kv
, uint32_t *len
)
755 if (kv
== NULL
) return NULL
;
756 if (kv
->databuf
== NULL
) return NULL
;
757 if (kv
->_vlist
== 0) return NULL
;
762 if (kv
->datalen
< (kv
->_vlist
+ sizeof(uint32_t))) return NULL
;
763 kv
->_val
= kv
->_vlist
+ sizeof(uint32_t);
765 p
= kv
->databuf
+ kv
->_val
;
767 memcpy(&x
, p
, sizeof(uint32_t));
772 p
= kv
->databuf
+ kv
->_val
;
774 memcpy(&x
, p
, sizeof(uint32_t));
777 if (kv
->datalen
< (kv
->_val
+ sizeof(uint32_t) + vltemp
)) return NULL
;
779 p
+= (sizeof(uint32_t) + vltemp
);
780 kv
->_val
+= (sizeof(uint32_t) + vltemp
);
783 if (kv
->datalen
< (kv
->_val
+ sizeof(uint32_t))) return NULL
;
785 if (len
!= NULL
) (*len
) = vltemp
;
786 p
= kv
->databuf
+ kv
->_val
+ sizeof(uint32_t);
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.
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().
803 kvbuf_decode(kvbuf_t
*kv
)
809 if (kv
== NULL
) return NULL
;
810 if (kv
->databuf
== NULL
) return NULL
;
812 if (kv
->datalen
< sizeof(uint32_t)) return NULL
;
815 kv
->_size
= kv
->datalen
;
819 memcpy(&x
, p
, sizeof(uint32_t));
820 p
+= sizeof(uint32_t);
821 kv
->_size
-= sizeof(uint32_t);
824 if (x
== 0) return NULL
;
826 a
= (kvarray_t
*)calloc(1, sizeof(kvarray_t
));
827 if (a
== NULL
) return NULL
;
830 a
->dict
= (kvdict_t
*)calloc(a
->count
, sizeof(kvdict_t
));
837 for (d
= 0; d
< a
->count
; d
++)
839 if (kv
->_size
< sizeof(uint32_t))
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
);
852 if (a
->dict
[d
].kcount
> 0)
854 a
->dict
[d
].key
= (const char **)calloc(a
->dict
[d
].kcount
, sizeof(const char *));
855 if (a
->dict
[d
].key
== NULL
)
861 a
->dict
[d
].vcount
= (uint32_t *)calloc(a
->dict
[d
].kcount
, sizeof(uint32_t));
862 if (a
->dict
[d
].vcount
== NULL
)
868 a
->dict
[d
].val
= (const char ***)calloc(a
->dict
[d
].kcount
, sizeof(char **));
869 if (a
->dict
[d
].val
== NULL
)
876 for (k
= 0; k
< a
->dict
[d
].kcount
; k
++)
879 if (kv
->_size
< sizeof(uint32_t))
887 memcpy(&x
, p
, sizeof(uint32_t));
888 p
+= sizeof(uint32_t);
889 kv
->_size
-= sizeof(uint32_t);
899 a
->dict
[d
].key
[k
] = p
;
904 if (kv
->_size
< sizeof(uint32_t))
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
);
917 if (a
->dict
[d
].vcount
[k
] > 0)
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
)
928 for (v
= 0; v
< a
->dict
[d
].vcount
[k
]; v
++)
931 if (kv
->_size
< sizeof(uint32_t))
939 memcpy(&x
, p
, sizeof(uint32_t));
940 p
+= sizeof(uint32_t);
941 kv
->_size
-= sizeof(uint32_t);
951 a
->dict
[d
].val
[k
][v
] = p
;
965 kvarray_free(kvarray_t
*a
)
969 if (a
== NULL
) return;
971 for (d
= 0; d
< a
->count
; d
++)
973 for (k
= 0; k
< a
->dict
[d
].kcount
; k
++)
975 if (a
->dict
[d
].val
== NULL
) continue;
976 if (a
->dict
[d
].val
[k
] != NULL
) free(a
->dict
[d
].val
[k
]);
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
);
986 if (a
->dict
!= NULL
) free(a
->dict
);
989 if (a
->kv
!= NULL
) kvbuf_free(a
->kv
);