#include <u.h>#include <libc.h> #include "cbor.h" #define MIN(x, y) ((x) < (y) ? (x): (y)) static int cbor_vunpack(cbor_allocator *a, cbor *c, char **fmt, va_list *va); static intcbor_vunpack_array(cbor_allocator *a, cbor *array, char **fmt, va_list *va){ char c; int i; cbor *e; assert(array->type == CBOR_ARRAY); for(i = 0; i < array->len; i++){ e = array->array[i]; c = **fmt; switch(**fmt){ case '\0': /* expected ']' */ abort(); goto err; case ']': return 0; } if(cbor_vunpack(a, e, fmt, va) < 0) goto err; } if(**fmt == ']') return 0; err: return -1;} static cbor*map_find(cbor *map, char *key){ int i, klen, min; cbor *e; assert(map->type == CBOR_MAP); klen = strlen(key); for(i = 0; i < map->len; i++){ e = map->array[i]; assert(e->type == CBOR_MAP_ELEMENT); if(e->key->type != CBOR_STRING) continue; min = MIN(klen, e->key->len); if(strncmp(e->key->string, key, min) != 0) continue; return e->value; } return nil;} static intcbor_vunpack_map(cbor_allocator *a, cbor *map, char **fmt, va_list *va){ char *key; cbor *v; assert(map->type == CBOR_MAP); for(;;){ switch(*(*fmt)++){ default: case '\0': /* expected '}' */ abort(); goto err; case '}': return 0; case 'S': key = va_arg(*va, char*); v = map_find(map, key); break; } if(cbor_vunpack(a, v, fmt, va) < 0) goto err; } err: return -1;} static intcbor_vunpack(cbor_allocator *a, cbor *c, char **fmt, va_list *va){ u64int *up; s64int *sp; int *lenp; uchar *uch, **uchp; char *sch, **schp; cbor **cp; assert(c != nil); switch(*(*fmt)++){ default: break; case 'u': if(c->type != CBOR_UINT) break; up = va_arg(*va, u64int*); *up = c->uint; return 0; case 'i': if(c->type != CBOR_SINT) break; sp = va_arg(*va, s64int*); *sp = c->sint; return 0; case 'b': if(c->type != CBOR_BYTE) break; lenp = va_arg(*va, int*); uchp = va_arg(*va, uchar**); uch = a->alloc(a->context, c->len); if(uch == nil) break; memcpy(uch, c->byte, c->len); *lenp = c->len; *uchp = uch; return 0; case 's': if(c->type != CBOR_STRING) break; lenp = va_arg(*va, int*); schp = va_arg(*va, char**); sch = a->alloc(a->context, c->len+1); if(sch == nil) break; memcpy(sch, c->string, c->len); sch[c->len] = '\0'; *lenp = c->len; *schp = sch; return 0; case '{': if(c->type != CBOR_MAP) break; return cbor_vunpack_map(a, c, fmt, va); case '[': if(c->type != CBOR_ARRAY) break; return cbor_vunpack_array(a, c, fmt, va); case 't': if(c->type != CBOR_TAG) break; up = va_arg(*va, u64int*); *up = c->tag; return cbor_vunpack(a, c->item, fmt, va); case 'c': cp = va_arg(*va, cbor**); /* TODO: copy value? */ *cp = c; return 0; } return -1;} intcbor_unpack(cbor_allocator *a, cbor *c, char *fmt, ...){ int rv; va_list va; va_start(va, fmt); rv = cbor_vunpack(a, c, &fmt, &va); va_end(va); return rv;}
#include <u.h>
#include <libc.h>
#include "cbor.h"
#define MIN(x, y) ((x) < (y) ? (x): (y))
static int cbor_vunpack(cbor_allocator *a, cbor *c, char **fmt, va_list *va);
static int
cbor_vunpack_array(cbor_allocator *a, cbor *array, char **fmt, va_list *va)
{
char c;
int i;
cbor *e;
assert(array->type == CBOR_ARRAY);
for(i = 0; i < array->len; i++){
e = array->array[i];
c = **fmt;
switch(**fmt){
case '\0':
/* expected ']' */
abort();
goto err;
case ']':
return 0;
}
if(cbor_vunpack(a, e, fmt, va) < 0)
goto err;
}
if(**fmt == ']')
return 0;
err:
return -1;
}
static cbor*
map_find(cbor *map, char *key)
{
int i, klen, min;
cbor *e;
assert(map->type == CBOR_MAP);
klen = strlen(key);
for(i = 0; i < map->len; i++){
e = map->array[i];
assert(e->type == CBOR_MAP_ELEMENT);
if(e->key->type != CBOR_STRING)
continue;
min = MIN(klen, e->key->len);
if(strncmp(e->key->string, key, min) != 0)
continue;
return e->value;
}
return nil;
}
static int
cbor_vunpack_map(cbor_allocator *a, cbor *map, char **fmt, va_list *va)
{
char *key;
cbor *v;
assert(map->type == CBOR_MAP);
for(;;){
switch(*(*fmt)++){
default:
case '\0':
/* expected '}' */
abort();
goto err;
case '}':
return 0;
case 'S':
key = va_arg(*va, char*);
v = map_find(map, key);
break;
}
if(cbor_vunpack(a, v, fmt, va) < 0)
goto err;
}
err:
return -1;
}
static int
cbor_vunpack(cbor_allocator *a, cbor *c, char **fmt, va_list *va)
{
u64int *up;
s64int *sp;
int *lenp;
uchar *uch, **uchp;
char *sch, **schp;
cbor **cp;
assert(c != nil);
switch(*(*fmt)++){
default:
break;
case 'u':
if(c->type != CBOR_UINT)
break;
up = va_arg(*va, u64int*);
*up = c->uint;
return 0;
case 'i':
if(c->type != CBOR_SINT)
break;
sp = va_arg(*va, s64int*);
*sp = c->sint;
return 0;
case 'b':
if(c->type != CBOR_BYTE)
break;
lenp = va_arg(*va, int*);
uchp = va_arg(*va, uchar**);
uch = a->alloc(a->context, c->len);
if(uch == nil)
break;
memcpy(uch, c->byte, c->len);
*lenp = c->len;
*uchp = uch;
return 0;
case 's':
if(c->type != CBOR_STRING)
break;
lenp = va_arg(*va, int*);
schp = va_arg(*va, char**);
sch = a->alloc(a->context, c->len+1);
if(sch == nil)
break;
memcpy(sch, c->string, c->len);
sch[c->len] = '\0';
*lenp = c->len;
*schp = sch;
return 0;
case '{':
if(c->type != CBOR_MAP)
break;
return cbor_vunpack_map(a, c, fmt, va);
case '[':
if(c->type != CBOR_ARRAY)
break;
return cbor_vunpack_array(a, c, fmt, va);
case 't':
if(c->type != CBOR_TAG)
break;
up = va_arg(*va, u64int*);
*up = c->tag;
return cbor_vunpack(a, c->item, fmt, va);
case 'c':
cp = va_arg(*va, cbor**);
/* TODO: copy value? */
*cp = c;
return 0;
}
return -1;
}
int
cbor_unpack(cbor_allocator *a, cbor *c, char *fmt, ...)
{
int rv;
va_list va;
va_start(va, fmt);
rv = cbor_vunpack(a, c, &fmt, &va);
va_end(va);
return rv;
}