mischiefinitial commitbd439e57 years agoHistory
212 lines · 3.0 KB · C
RawDownload
#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;}