]>
git.saurik.com Git - apple/libinfo.git/blob - lookup.subproj/kvbuf.c
2 * Copyright (c) 2009 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@
30 #define KVBUF_CHUNK 256
33 * kvbuf_t is a list of key/value dictionaries.
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
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.
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.
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.
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.
60 * The cache_entry_list_to_kvbuf() routine contains the only
61 * code that builds an array.
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.
73 kvbuf_query(char *fmt
, ...)
76 char *arg
, *f
, str
[32];
81 if (fmt
== NULL
) return NULL
;
84 if (kv
== NULL
) return NULL
;
89 for (f
= fmt
; (*f
) != '\0'; f
++)
93 arg
= va_arg(ap
, char *);
94 kvbuf_add_key(kv
, arg
);
98 arg
= va_arg(ap
, char *);
99 kvbuf_add_val(kv
, arg
);
103 iarg
= va_arg(ap
, int32_t);
104 snprintf(str
, sizeof(str
), "%d", iarg
);
105 kvbuf_add_val(kv
, str
);
109 uarg
= va_arg(ap
,uint32_t);
110 snprintf(str
, sizeof(str
), "%u", uarg
);
111 kvbuf_add_val(kv
, str
);
120 kvbuf_query_key_val(const char *key
, const char *val
)
123 uint32_t x
, kl
, vl
, vc
;
126 if (key
== NULL
) return NULL
;
128 kl
= strlen(key
) + 1;
135 vl
= strlen(val
) + 1;
139 kv
= (kvbuf_t
*)calloc(1, sizeof(kvbuf_t
));
140 if (kv
== NULL
) return NULL
;
142 kv
->_size
= (5 * sizeof(uint32_t)) + kl
+ vl
;
143 kv
->datalen
= kv
->_size
;
145 kv
->databuf
= calloc(1, kv
->_size
);
146 if (kv
->databuf
== NULL
)
156 memcpy(p
, &x
, sizeof(uint32_t));
157 p
+= sizeof(uint32_t);
160 memcpy(p
, &x
, sizeof(uint32_t));
161 p
+= sizeof(uint32_t);
165 memcpy(p
, &x
, sizeof(uint32_t));
166 p
+= sizeof(uint32_t);
172 /* number of values */
174 memcpy(p
, &x
, sizeof(uint32_t));
175 p
+= sizeof(uint32_t);
181 memcpy(p
, &x
, sizeof(uint32_t));
182 p
+= sizeof(uint32_t);
192 kvbuf_query_key_int(const char *key
, int32_t i
)
196 snprintf(str
, sizeof(str
), "%d", i
);
197 return kvbuf_query_key_val(key
, str
);
201 kvbuf_query_key_uint(const char *key
, uint32_t u
)
205 snprintf(str
, sizeof(str
), "%u", u
);
206 return kvbuf_query_key_val(key
, str
);
210 kvbuf_new_zone(malloc_zone_t
*zone
)
214 if (zone
== NULL
) return NULL
;
216 kv
= (kvbuf_t
*)malloc_zone_calloc(zone
, 1, sizeof(kvbuf_t
));
217 if (kv
== NULL
) return NULL
;
219 kv
->_size
= KVBUF_START_SIZE
;
220 kv
->databuf
= malloc_zone_calloc(zone
, 1, kv
->_size
);
221 if (kv
->databuf
== NULL
)
227 kv
->datalen
= sizeof(uint32_t);
228 kv
->_dict
= kv
->datalen
;
236 return kvbuf_new_zone(malloc_default_zone());
240 kvbuf_init_zone(malloc_zone_t
*zone
, char *buffer
, uint32_t length
)
244 if (zone
== NULL
) return NULL
;
246 kv
= (kvbuf_t
*)malloc_zone_calloc(zone
, 1, sizeof(kvbuf_t
));
247 if (kv
== NULL
) return NULL
;
250 kv
->datalen
= length
;
253 kv
->databuf
= malloc_zone_calloc(zone
, 1, length
);
254 if (kv
->databuf
== NULL
)
261 memcpy(kv
->databuf
, buffer
, length
);
269 kvbuf_init(char *buffer
, uint32_t length
)
271 return kvbuf_init_zone(malloc_default_zone(), buffer
, length
);
275 kvbuf_grow(kvbuf_t
*kv
, uint32_t delta
)
281 if (kv
== NULL
) return;
282 if (delta
== 0) return;
284 if (kv
->databuf
== NULL
) delta
+= sizeof(uint32_t);
286 newlen
= kv
->datalen
+ delta
;
287 if (newlen
<= kv
->_size
) return;
289 kv
->_size
= ((newlen
+ KVBUF_CHUNK
- 1) / KVBUF_CHUNK
) * KVBUF_CHUNK
;
291 zone
= malloc_zone_from_ptr(kv
);
292 if (kv
->databuf
== NULL
)
294 kv
->databuf
= malloc_zone_calloc(zone
, 1, kv
->_size
);
295 if (kv
->databuf
== NULL
)
297 memset(kv
, 0, sizeof(kvbuf_t
));
301 kv
->datalen
= sizeof(uint32_t);
302 kv
->_dict
= sizeof(uint32_t);
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
)
311 memset(kv
, 0, sizeof(kvbuf_t
));
315 p
= kv
->databuf
+ kv
->datalen
;
316 memset(p
, 0, kv
->_size
- kv
->datalen
);
321 kvbuf_add_dict(kvbuf_t
*kv
)
324 uint32_t x
, dict_count
;
326 if (kv
== NULL
) return;
328 /* Add a key count */
329 kvbuf_grow(kv
, sizeof(uint32_t));
330 if (kv
->databuf
== NULL
) return;
332 kv
->_dict
= kv
->datalen
;
333 kv
->datalen
+= sizeof(uint32_t);
335 kv
->_key
= kv
->datalen
;
339 /* increment and rewrite the dict count */
343 memcpy(&x
, p
, sizeof(uint32_t));
344 dict_count
= ntohl(x
);
347 x
= htonl(dict_count
);
348 memcpy(p
, &x
, sizeof(uint32_t));
352 kvbuf_add_key(kvbuf_t
*kv
, const char *key
)
354 uint32_t kl
, x
, key_count
, delta
;
357 if (kv
== NULL
) return;
358 if (key
== NULL
) return;
360 kl
= strlen(key
) + 1;
362 /* Grow to hold key len, key, and value list count. */
363 delta
= (2 * sizeof(uint32_t)) + kl
;
364 kvbuf_grow(kv
, delta
);
366 if (kv
->databuf
== NULL
) return;
368 /* increment and rewrite the key count for the current dictionary */
369 p
= kv
->databuf
+ kv
->_dict
;
372 memcpy(&x
, p
, sizeof(uint32_t));
373 key_count
= ntohl(x
);
375 if (key_count
== 0) kv
->_key
= kv
->_dict
+ sizeof(uint32_t);
376 else kv
->_key
= kv
->datalen
;
379 x
= htonl(key_count
);
380 memcpy(p
, &x
, sizeof(uint32_t));
382 /* append key to data buffer */
383 p
= kv
->databuf
+ kv
->datalen
;
386 memcpy(p
, &x
, sizeof(uint32_t));
387 p
+= sizeof(uint32_t);
391 kv
->_vlist
= kv
->datalen
+ sizeof(uint32_t) + kl
;
394 memcpy(p
, &x
, sizeof(uint32_t));
396 kv
->datalen
+= delta
;
397 kv
->_val
= kv
->datalen
;
401 kvbuf_add_val_len(kvbuf_t
*kv
, const char *val
, uint32_t len
)
403 uint32_t x
, val_count
, delta
;
406 if (kv
== NULL
) return;
407 if (val
== NULL
) return;
408 if (len
== 0) return;
410 /* Grow to hold val len and value. */
411 delta
= sizeof(uint32_t) + len
;
412 kvbuf_grow(kv
, delta
);
414 if (kv
->databuf
== NULL
) return;
416 /* increment and rewrite the value count for the value_list dictionary */
417 p
= kv
->databuf
+ kv
->_vlist
;
420 memcpy(&x
, p
, sizeof(uint32_t));
421 val_count
= ntohl(x
);
423 x
= htonl(val_count
);
424 memcpy(p
, &x
, sizeof(uint32_t));
426 /* append val to data buffer */
427 p
= kv
->databuf
+ kv
->_val
;
430 memcpy(p
, &x
, sizeof(uint32_t));
431 p
+= sizeof(uint32_t);
435 kv
->datalen
+= delta
;
436 kv
->_val
= kv
->datalen
;
440 * WARNING! Kludge Alert!
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.
447 kvbuf_get_len(const char *p
)
452 memcpy(&x
, p
- sizeof(uint32_t), sizeof(uint32_t));
457 kvbuf_add_val(kvbuf_t
*kv
, const char *val
)
459 if (kv
== NULL
) return;
460 if (val
== NULL
) return;
462 kvbuf_add_val_len(kv
, val
, strlen(val
) + 1);
466 kvbuf_make_purgeable(kvbuf_t
*kv
)
468 if (kv
== NULL
) return;
470 if (kv
->databuf
!= NULL
) malloc_make_purgeable(kv
->databuf
);
474 kvbuf_make_nonpurgeable(kvbuf_t
*kv
)
476 if (kv
== NULL
) return 0;
479 * malloc_make_nonpurgeable returns 0 even if memory was not
480 * allocated from the purgeable zone, so this is safe to call.
482 if ((kv
->databuf
== NULL
) || (malloc_make_nonpurgeable(kv
->databuf
) == 0)) return 0;
484 /* return non-zero since something failed */
489 kvbuf_free(kvbuf_t
*kv
)
491 if (kv
== NULL
) return;
493 if (kv
->databuf
!= NULL
) free(kv
->databuf
);
494 memset(kv
, 0, sizeof(kvbuf_t
));
498 /* appends a kvbuf to an existing kvbuf */
500 kvbuf_append_kvbuf(kvbuf_t
*kv
, const kvbuf_t
*kv2
)
502 uint32_t curr_count
, new_count
, temp
;
504 if (kv
== NULL
) return;
505 if (kv2
== NULL
) return;
510 memcpy(&temp
, kv
->databuf
, sizeof(uint32_t));
511 curr_count
= ntohl(temp
);
513 memcpy(&temp
, kv2
->databuf
, sizeof(uint32_t));
514 new_count
= ntohl(temp
);
517 if (new_count
== 0) return;
519 /* add the dictionary count to the current dictionary counts */
520 curr_count
+= new_count
;
522 temp
= htonl(curr_count
);
523 memcpy(kv
->databuf
, &temp
, sizeof(uint32_t));
525 /* grow the current buffer so we can append the new buffer */
526 temp
= kv2
->datalen
- sizeof(uint32_t);
528 kvbuf_grow(kv
, temp
);
530 memcpy(kv
->databuf
+ kv
->datalen
, kv2
->databuf
+ sizeof(uint32_t), temp
);
534 /* returns number of dictionaries */
536 kvbuf_reset(kvbuf_t
*kv
)
540 if (kv
== NULL
) return 0;
541 if (kv
->databuf
== NULL
) return 0;
548 if (kv
->datalen
< sizeof(uint32_t)) return 0;
551 memcpy(&x
, kv
->databuf
, sizeof(uint32_t));
555 /* advance to next dictionary, returns key count */
557 kvbuf_next_dict(kvbuf_t
*kv
)
559 uint32_t x
, k
, v
, kcount
, vcount
, kl
, vl
;
562 if (kv
== NULL
) return 0;
563 if (kv
->databuf
== NULL
) return 0;
572 if (kv
->datalen
< sizeof(uint32_t)) return 0;
573 kv
->_dict
= sizeof(uint32_t);
575 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return 0;
577 p
= kv
->databuf
+ kv
->_dict
;
579 memcpy(&x
, p
, sizeof(uint32_t));
585 p
= kv
->databuf
+ kv
->_dict
;
588 memcpy(&x
, p
, sizeof(uint32_t));
589 p
+= sizeof(uint32_t);
590 kv
->_dict
+= sizeof(uint32_t);
593 for (k
= 0; k
< kcount
; k
++)
596 memcpy(&x
, p
, sizeof(uint32_t));
597 p
+= sizeof(uint32_t);
598 kv
->_dict
+= sizeof(uint32_t);
604 memcpy(&x
, p
, sizeof(uint32_t));
605 p
+= sizeof(uint32_t);
606 kv
->_dict
+= sizeof(uint32_t);
609 for (v
= 0; v
< vcount
; v
++)
612 memcpy(&x
, p
, sizeof(uint32_t));
613 p
+= sizeof(uint32_t);
614 kv
->_dict
+= sizeof(uint32_t);
621 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return 0;
623 p
= kv
->databuf
+ kv
->_dict
;
625 memcpy(&x
, p
, sizeof(uint32_t));
631 /* advance to next key, returns key and sets val_count */
633 kvbuf_next_key(kvbuf_t
*kv
, uint32_t *val_count
)
635 uint32_t x
, kl
, v
, vl
, vc
;
638 if (kv
== NULL
) return NULL
;
639 if (val_count
== NULL
) return NULL
;
643 if (kv
->databuf
== NULL
) return NULL
;
644 if (kv
->_dict
== 0) return NULL
;
652 if (kv
->datalen
< (kv
->_dict
+ sizeof(uint32_t))) return NULL
;
653 kv
->_key
= kv
->_dict
+ sizeof(uint32_t);
657 p
= kv
->databuf
+ kv
->_key
;
660 memcpy(&x
, p
, sizeof(uint32_t));
663 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t) + kl
)) return NULL
;
665 p
+= (sizeof(uint32_t) + kl
);
666 kv
->_key
+= (sizeof(uint32_t) + kl
);
668 /* skip over values */
669 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
672 memcpy(&x
, p
, sizeof(uint32_t));
675 p
+= sizeof(uint32_t);
676 kv
->_key
+= sizeof(uint32_t);
678 for (v
= 0; v
< vc
; v
++)
680 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
683 memcpy(&x
, p
, sizeof(uint32_t));
686 if (kv
->datalen
< (kv
->_key
+ kl
)) return NULL
;
688 p
+= (sizeof(uint32_t) + vl
);
689 kv
->_key
+= (sizeof(uint32_t) + vl
);
693 if (kv
->datalen
< (kv
->_key
+ sizeof(uint32_t))) return NULL
;
695 p
= kv
->databuf
+ kv
->_key
;
697 memcpy(&x
, p
, sizeof(uint32_t));
700 p
+= sizeof(uint32_t);
703 kv
->_vlist
= kv
->_key
+ sizeof(uint32_t) + kl
;
704 if (kv
->datalen
< (kv
->_vlist
+ sizeof(uint32_t)))
710 p
= kv
->databuf
+ kv
->_vlist
;
712 memcpy(&x
, p
, sizeof(uint32_t));
713 *val_count
= ntohl(x
);
719 kvbuf_next_val(kvbuf_t
*kv
)
721 return kvbuf_next_val_len(kv
, NULL
);
725 kvbuf_next_val_len(kvbuf_t
*kv
, uint32_t *len
)
731 if (kv
== NULL
) return NULL
;
732 if (kv
->databuf
== NULL
) return NULL
;
733 if (kv
->_vlist
== 0) return NULL
;
738 if (kv
->datalen
< (kv
->_vlist
+ sizeof(uint32_t))) return NULL
;
739 kv
->_val
= kv
->_vlist
+ sizeof(uint32_t);
741 p
= kv
->databuf
+ kv
->_val
;
743 memcpy(&x
, p
, sizeof(uint32_t));
748 p
= kv
->databuf
+ kv
->_val
;
750 memcpy(&x
, p
, sizeof(uint32_t));
753 if (kv
->datalen
< (kv
->_val
+ sizeof(uint32_t) + vltemp
)) return NULL
;
755 p
+= (sizeof(uint32_t) + vltemp
);
756 kv
->_val
+= (sizeof(uint32_t) + vltemp
);
759 if (kv
->datalen
< (kv
->_val
+ sizeof(uint32_t))) return NULL
;
761 if (len
!= NULL
) (*len
) = vltemp
;
762 p
= kv
->databuf
+ kv
->_val
+ sizeof(uint32_t);
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.
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().
778 kvbuf_decode(kvbuf_t
*kv
)
784 if (kv
== NULL
) return NULL
;
785 if (kv
->databuf
== NULL
) return NULL
;
787 if (kv
->datalen
< sizeof(uint32_t)) return NULL
;
790 kv
->_size
= kv
->datalen
;
794 memcpy(&x
, p
, sizeof(uint32_t));
795 p
+= sizeof(uint32_t);
796 kv
->_size
-= sizeof(uint32_t);
799 if (x
== 0) return NULL
;
801 a
= (kvarray_t
*)calloc(1, sizeof(kvarray_t
));
802 if (a
== NULL
) return NULL
;
805 a
->dict
= (kvdict_t
*)calloc(a
->count
, sizeof(kvdict_t
));
812 for (d
= 0; d
< a
->count
; d
++)
814 if (kv
->_size
< sizeof(uint32_t))
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
);
827 if (a
->dict
[d
].kcount
> 0)
829 a
->dict
[d
].key
= (const char **)calloc(a
->dict
[d
].kcount
, sizeof(const char *));
830 if (a
->dict
[d
].key
== NULL
)
836 a
->dict
[d
].vcount
= (uint32_t *)calloc(a
->dict
[d
].kcount
, sizeof(uint32_t));
837 if (a
->dict
[d
].vcount
== NULL
)
843 a
->dict
[d
].val
= (const char ***)calloc(a
->dict
[d
].kcount
, sizeof(char **));
844 if (a
->dict
[d
].val
== NULL
)
851 for (k
= 0; k
< a
->dict
[d
].kcount
; k
++)
854 if (kv
->_size
< sizeof(uint32_t))
862 memcpy(&x
, p
, sizeof(uint32_t));
863 p
+= sizeof(uint32_t);
864 kv
->_size
-= sizeof(uint32_t);
874 a
->dict
[d
].key
[k
] = p
;
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);
890 a
->dict
[d
].vcount
[k
] = ntohl(x
);
892 if (a
->dict
[d
].vcount
[k
] > 0)
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
)
903 for (v
= 0; v
< a
->dict
[d
].vcount
[k
]; v
++)
906 if (kv
->_size
< sizeof(uint32_t))
914 memcpy(&x
, p
, sizeof(uint32_t));
915 p
+= sizeof(uint32_t);
916 kv
->_size
-= sizeof(uint32_t);
926 a
->dict
[d
].val
[k
][v
] = p
;
939 kvarray_free(kvarray_t
*a
)
943 if (a
== NULL
) return;
945 for (d
= 0; d
< a
->count
; d
++)
947 for (k
= 0; k
< a
->dict
[d
].kcount
; k
++)
949 if (a
->dict
[d
].val
== NULL
) continue;
950 if (a
->dict
[d
].val
[k
] != NULL
) free(a
->dict
[d
].val
[k
]);
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
);
960 if (a
->dict
!= NULL
) free(a
->dict
);
963 if (a
->kv
!= NULL
) kvbuf_free(a
->kv
);