#include "libinfo_common.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <kvbuf.h>
#define KVBUF_CHUNK 256
LIBINFO_EXPORT
kvbuf_t *
kvbuf_query(char *fmt, ...)
{
va_list ap;
char *arg, *f, str[32];
int32_t iarg;
uint32_t uarg;
kvbuf_t *kv;
if (fmt == NULL) return NULL;
kv = kvbuf_new();
if (kv == NULL) return NULL;
kvbuf_add_dict(kv);
va_start(ap, fmt);
for (f = fmt; (*f) != '\0'; f++)
{
if (*f == 'k')
{
arg = va_arg(ap, char *);
kvbuf_add_key(kv, arg);
}
else if (*f == 's')
{
arg = va_arg(ap, char *);
kvbuf_add_val(kv, arg);
}
else if (*f == 'i')
{
iarg = va_arg(ap, int32_t);
snprintf(str, sizeof(str), "%d", iarg);
kvbuf_add_val(kv, str);
}
else if (*f == 'u')
{
uarg = va_arg(ap,uint32_t);
snprintf(str, sizeof(str), "%u", uarg);
kvbuf_add_val(kv, str);
}
}
va_end(ap);
return kv;
}
LIBINFO_EXPORT
kvbuf_t *
kvbuf_query_key_val(const char *key, const char *val)
{
kvbuf_t *kv;
uint32_t x, kl, vl, vc;
char *p;
if (key == NULL) return NULL;
kl = strlen(key) + 1;
vl = 0;
vc = 0;
if (val != NULL)
{
vl = strlen(val) + 1;
vc = 1;
}
kv = (kvbuf_t *)calloc(1, sizeof(kvbuf_t));
if (kv == NULL) return NULL;
kv->_size = (5 * sizeof(uint32_t)) + kl + vl;
kv->datalen = kv->_size;
kv->databuf = calloc(1, kv->_size);
if (kv->databuf == NULL)
{
free(kv);
return NULL;
}
p = kv->databuf;
x = htonl(1);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
x = htonl(kl);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, key, kl);
p += kl;
x = htonl(vc);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
if (vc > 0)
{
x = htonl(vl);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, val, vl);
}
return kv;
}
LIBINFO_EXPORT
kvbuf_t *
kvbuf_query_key_int(const char *key, int32_t i)
{
char str[32];
snprintf(str, sizeof(str), "%d", i);
return kvbuf_query_key_val(key, str);
}
LIBINFO_EXPORT
kvbuf_t *
kvbuf_query_key_uint(const char *key, uint32_t u)
{
char str[32];
snprintf(str, sizeof(str), "%u", u);
return kvbuf_query_key_val(key, str);
}
LIBINFO_EXPORT
kvbuf_t *
kvbuf_new_zone(malloc_zone_t *zone)
{
kvbuf_t *kv;
if (zone == NULL) return NULL;
kv = (kvbuf_t *)malloc_zone_calloc(zone, 1, sizeof(kvbuf_t));
if (kv == NULL) return NULL;
kv->_size = KVBUF_START_SIZE;
kv->databuf = malloc_zone_calloc(zone, 1, kv->_size);
if (kv->databuf == NULL)
{
free(kv);
return NULL;
}
kv->datalen = sizeof(uint32_t);
kv->_dict = kv->datalen;
return kv;
}
LIBINFO_EXPORT
kvbuf_t *
kvbuf_new(void)
{
return kvbuf_new_zone(malloc_default_zone());
}
LIBINFO_EXPORT
kvbuf_t *
kvbuf_init_zone(malloc_zone_t *zone, char *buffer, uint32_t length)
{
kvbuf_t *kv;
if (zone == NULL) return NULL;
kv = (kvbuf_t *)malloc_zone_calloc(zone, 1, sizeof(kvbuf_t));
if (kv == NULL) return NULL;
kv->_size = length;
kv->datalen = length;
if (length > 0)
{
kv->databuf = malloc_zone_calloc(zone, 1, length);
if (kv->databuf == NULL)
{
free(kv);
kv = NULL;
}
else
{
memcpy(kv->databuf, buffer, length);
}
}
return kv;
}
LIBINFO_EXPORT
kvbuf_t *
kvbuf_init(char *buffer, uint32_t length)
{
return kvbuf_init_zone(malloc_default_zone(), buffer, length);
}
static void
kvbuf_grow(kvbuf_t *kv, uint32_t delta)
{
uint32_t newlen;
char *p, *newbuf;
malloc_zone_t *zone;
if (kv == NULL) return;
if (delta == 0) return;
if (kv->databuf == NULL) delta += sizeof(uint32_t);
newlen = kv->datalen + delta;
if (newlen <= kv->_size) return;
kv->_size = ((newlen + KVBUF_CHUNK - 1) / KVBUF_CHUNK) * KVBUF_CHUNK;
zone = malloc_zone_from_ptr(kv);
if (kv->databuf == NULL)
{
kv->databuf = malloc_zone_calloc(zone, 1, kv->_size);
if (kv->databuf == NULL)
{
memset(kv, 0, sizeof(kvbuf_t));
return;
}
kv->datalen = sizeof(uint32_t);
kv->_dict = sizeof(uint32_t);
}
else
{
newbuf = malloc_zone_realloc(zone, kv->databuf, kv->_size);
if (newbuf == NULL) free(kv->databuf);
kv->databuf = newbuf;
if (kv->databuf == NULL)
{
memset(kv, 0, sizeof(kvbuf_t));
return;
}
p = kv->databuf + kv->datalen;
memset(p, 0, kv->_size - kv->datalen);
}
}
LIBINFO_EXPORT
void
kvbuf_add_dict(kvbuf_t *kv)
{
char *p;
uint32_t x, dict_count;
if (kv == NULL) return;
kvbuf_grow(kv, sizeof(uint32_t));
if (kv->databuf == NULL) return;
kv->_dict = kv->datalen;
kv->datalen += sizeof(uint32_t);
kv->_key = kv->datalen;
kv->_vlist = 0;
kv->_val = 0;
p = kv->databuf;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
dict_count = ntohl(x);
dict_count++;
x = htonl(dict_count);
memcpy(p, &x, sizeof(uint32_t));
}
LIBINFO_EXPORT
void
kvbuf_add_key(kvbuf_t *kv, const char *key)
{
uint32_t kl, x, key_count, delta;
char *p;
if (kv == NULL) return;
if (key == NULL) return;
kl = strlen(key) + 1;
delta = (2 * sizeof(uint32_t)) + kl;
kvbuf_grow(kv, delta);
if (kv->databuf == NULL) return;
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
key_count = ntohl(x);
if (key_count == 0) kv->_key = kv->_dict + sizeof(uint32_t);
else kv->_key = kv->datalen;
key_count++;
x = htonl(key_count);
memcpy(p, &x, sizeof(uint32_t));
p = kv->databuf + kv->datalen;
x = htonl(kl);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, key, kl);
p += kl;
kv->_vlist = kv->datalen + sizeof(uint32_t) + kl;
x = 0;
memcpy(p, &x, sizeof(uint32_t));
kv->datalen += delta;
kv->_val = kv->datalen;
}
LIBINFO_EXPORT
void
kvbuf_add_val_len(kvbuf_t *kv, const char *val, uint32_t len)
{
uint32_t x, val_count, delta;
char *p;
if (kv == NULL) return;
if (val == NULL) return;
if (len == 0) return;
delta = sizeof(uint32_t) + len;
kvbuf_grow(kv, delta);
if (kv->databuf == NULL) return;
p = kv->databuf + kv->_vlist;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
val_count = ntohl(x);
val_count++;
x = htonl(val_count);
memcpy(p, &x, sizeof(uint32_t));
p = kv->databuf + kv->_val;
x = htonl(len);
memcpy(p, &x, sizeof(uint32_t));
p += sizeof(uint32_t);
memcpy(p, val, len);
p += len;
kv->datalen += delta;
kv->_val = kv->datalen;
}
LIBINFO_EXPORT
uint32_t
kvbuf_get_len(const char *p)
{
uint32_t x;
x = 0;
memcpy(&x, p - sizeof(uint32_t), sizeof(uint32_t));
return ntohl(x);
}
LIBINFO_EXPORT
void
kvbuf_add_val(kvbuf_t *kv, const char *val)
{
if (kv == NULL) return;
if (val == NULL) return;
kvbuf_add_val_len(kv, val, strlen(val) + 1);
}
LIBINFO_EXPORT
void
kvbuf_make_purgeable(kvbuf_t *kv)
{
if (kv == NULL) return;
if (kv->databuf != NULL) malloc_make_purgeable(kv->databuf);
}
LIBINFO_EXPORT
int
kvbuf_make_nonpurgeable(kvbuf_t *kv)
{
if (kv == NULL) return 0;
if ((kv->databuf == NULL) || (malloc_make_nonpurgeable(kv->databuf) == 0)) return 0;
return 1;
}
LIBINFO_EXPORT
void
kvbuf_free(kvbuf_t *kv)
{
if (kv == NULL) return;
if (kv->databuf != NULL) free(kv->databuf);
memset(kv, 0, sizeof(kvbuf_t));
free(kv);
}
LIBINFO_EXPORT
void
kvbuf_append_kvbuf(kvbuf_t *kv, const kvbuf_t *kv2)
{
uint32_t curr_count, new_count, temp;
if (kv == NULL) return;
if (kv2 == NULL) return;
curr_count = 0;
new_count = 0;
memcpy(&temp, kv->databuf, sizeof(uint32_t));
curr_count = ntohl(temp);
memcpy(&temp, kv2->databuf, sizeof(uint32_t));
new_count = ntohl(temp);
if (new_count == 0) return;
curr_count += new_count;
temp = htonl(curr_count);
memcpy(kv->databuf, &temp, sizeof(uint32_t));
temp = kv2->datalen - sizeof(uint32_t);
kvbuf_grow(kv, temp);
memcpy(kv->databuf + kv->datalen, kv2->databuf + sizeof(uint32_t), temp);
kv->datalen += temp;
}
LIBINFO_EXPORT
uint32_t
kvbuf_reset(kvbuf_t *kv)
{
uint32_t x;
if (kv == NULL) return 0;
if (kv->databuf == NULL) return 0;
kv->_dict = 0;
kv->_key = 0;
kv->_vlist = 0;
kv->_val = 0;
if (kv->datalen < sizeof(uint32_t)) return 0;
x = 0;
memcpy(&x, kv->databuf, sizeof(uint32_t));
return ntohl(x);
}
LIBINFO_EXPORT
uint32_t
kvbuf_next_dict(kvbuf_t *kv)
{
uint32_t x, k, v, kcount, vcount, kl, vl;
char *p;
if (kv == NULL) return 0;
if (kv->databuf == NULL) return 0;
kv->_key = 0;
kv->_vlist = 0;
kv->_val = 0;
if (kv->_dict == 0)
{
if (kv->datalen < sizeof(uint32_t)) return 0;
kv->_dict = sizeof(uint32_t);
if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kcount = ntohl(x);
return kcount;
}
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
kcount = ntohl(x);
for (k = 0; k < kcount; k++)
{
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
kl = ntohl(x);
p += kl;
kv->_dict += kl;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
vcount = ntohl(x);
for (v = 0; v < vcount; v++)
{
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_dict += sizeof(uint32_t);
vl = ntohl(x);
p += vl;
kv->_dict += vl;
}
}
if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return 0;
p = kv->databuf + kv->_dict;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kcount = ntohl(x);
return kcount;
}
LIBINFO_EXPORT
char *
kvbuf_next_key(kvbuf_t *kv, uint32_t *val_count)
{
uint32_t x, kl, v, vl, vc;
char *p, *out;
if (kv == NULL) return NULL;
if (val_count == NULL) return NULL;
*val_count = 0;
if (kv->databuf == NULL) return NULL;
if (kv->_dict == 0) return NULL;
kv->_vlist = 0;
kv->_val = 0;
if (kv->_key == 0)
{
if (kv->datalen < (kv->_dict + sizeof(uint32_t))) return NULL;
kv->_key = kv->_dict + sizeof(uint32_t);
}
else
{
p = kv->databuf + kv->_key;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kl = ntohl(x);
if (kv->datalen < (kv->_key + sizeof(uint32_t) + kl)) return NULL;
p += (sizeof(uint32_t) + kl);
kv->_key += (sizeof(uint32_t) + kl);
if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
vc = ntohl(x);
p += sizeof(uint32_t);
kv->_key += sizeof(uint32_t);
for (v = 0; v < vc; v++)
{
if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
vl = ntohl(x);
if (kv->datalen < (kv->_key + kl)) return NULL;
p += (sizeof(uint32_t) + vl);
kv->_key += (sizeof(uint32_t) + vl);
}
}
if (kv->datalen < (kv->_key + sizeof(uint32_t))) return NULL;
p = kv->databuf + kv->_key;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
kl = ntohl(x);
p += sizeof(uint32_t);
out = p;
kv->_vlist = kv->_key + sizeof(uint32_t) + kl;
if (kv->datalen < (kv->_vlist + sizeof(uint32_t)))
{
kv->_vlist = 0;
return NULL;
}
p = kv->databuf + kv->_vlist;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
*val_count = ntohl(x);
return out;
}
LIBINFO_EXPORT
char *
kvbuf_next_val(kvbuf_t *kv)
{
return kvbuf_next_val_len(kv, NULL);
}
LIBINFO_EXPORT
char *
kvbuf_next_val_len(kvbuf_t *kv, uint32_t *len)
{
uint32_t x = 0;
uint32_t vltemp = 0;
char *p;
if (kv == NULL) return NULL;
if (kv->databuf == NULL) return NULL;
if (kv->_vlist == 0) return NULL;
if (kv->_val == 0)
{
if (kv->datalen < (kv->_vlist + sizeof(uint32_t))) return NULL;
kv->_val = kv->_vlist + sizeof(uint32_t);
p = kv->databuf + kv->_val;
memcpy(&x, p, sizeof(uint32_t));
vltemp = ntohl(x);
}
else
{
p = kv->databuf + kv->_val;
memcpy(&x, p, sizeof(uint32_t));
vltemp = ntohl(x);
if (kv->datalen < (kv->_val + sizeof(uint32_t) + vltemp)) return NULL;
p += (sizeof(uint32_t) + vltemp);
kv->_val += (sizeof(uint32_t) + vltemp);
}
if (kv->datalen < (kv->_val + sizeof(uint32_t))) return NULL;
if (len != NULL) (*len) = vltemp;
p = kv->databuf + kv->_val + sizeof(uint32_t);
return p;
}
LIBINFO_EXPORT
kvarray_t *
kvbuf_decode(kvbuf_t *kv)
{
kvarray_t *a;
uint32_t x, d, k, v;
char *p;
if (kv == NULL) return NULL;
if (kv->databuf == NULL) return NULL;
if (kv->datalen < sizeof(uint32_t)) return NULL;
p = kv->databuf;
kv->_size = kv->datalen;
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
x = ntohl(x);
if (x == 0) return NULL;
a = (kvarray_t *)calloc(1, sizeof(kvarray_t));
if (a == NULL) return NULL;
a->count = x;
a->dict = (kvdict_t *)calloc(a->count, sizeof(kvdict_t));
if (a->dict == NULL)
{
free(a);
return NULL;
}
for (d = 0; d < a->count; d++)
{
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
a->dict[d].kcount = ntohl(x);
if (a->dict[d].kcount > 0)
{
a->dict[d].key = (const char **)calloc(a->dict[d].kcount, sizeof(const char *));
if (a->dict[d].key == NULL)
{
kvarray_free(a);
return NULL;
}
a->dict[d].vcount = (uint32_t *)calloc(a->dict[d].kcount, sizeof(uint32_t));
if (a->dict[d].vcount == NULL)
{
kvarray_free(a);
return NULL;
}
a->dict[d].val = (const char ***)calloc(a->dict[d].kcount, sizeof(char **));
if (a->dict[d].val == NULL)
{
kvarray_free(a);
return NULL;
}
}
for (k = 0; k < a->dict[d].kcount; k++)
{
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
x = ntohl(x);
if (kv->_size < x)
{
kvarray_free(a);
return NULL;
}
a->dict[d].key[k] = p;
p += x;
kv->_size -= x;
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
a->dict[d].vcount[k] = ntohl(x);
if (a->dict[d].vcount[k] > 0)
{
a->dict[d].val[k] = (const char **)calloc(a->dict[d].vcount[k] + 1, sizeof(const char *));
if (a->dict[d].val[k] == NULL)
{
kvarray_free(a);
return NULL;
}
}
for (v = 0; v < a->dict[d].vcount[k]; v++)
{
if (kv->_size < sizeof(uint32_t))
{
kvarray_free(a);
return NULL;
}
x = 0;
memcpy(&x, p, sizeof(uint32_t));
p += sizeof(uint32_t);
kv->_size -= sizeof(uint32_t);
x = ntohl(x);
if (kv->_size < x)
{
kvarray_free(a);
return NULL;
}
a->dict[d].val[k][v] = p;
p += x;
kv->_size -= x;
}
}
}
a->kv = kv;
return a;
}
LIBINFO_EXPORT
void
kvarray_free(kvarray_t *a)
{
uint32_t d, k;
if (a == NULL) return;
for (d = 0; d < a->count; d++)
{
for (k = 0; k < a->dict[d].kcount; k++)
{
if (a->dict[d].val == NULL) continue;
if (a->dict[d].val[k] != NULL) free(a->dict[d].val[k]);
}
if (a->dict[d].key != NULL) free(a->dict[d].key);
if (a->dict[d].vcount != NULL) free(a->dict[d].vcount);
if (a->dict[d].val != NULL) free(a->dict[d].val);
}
a->count = 0;
if (a->dict != NULL) free(a->dict);
a->dict = NULL;
if (a->kv != NULL) kvbuf_free(a->kv);
a->kv = NULL;
free(a);
}