411 lines · 6.2 KB · C
RawDownload
#include <u.h>#include <libc.h>#include "amf0.h"#include "util.h" enum {	Anum,	Abool,	Astr,	Aobj,	Anull = 5,	Aarr = 8,	Aend,	Alstr = 12,}; #define atleast(what, x) do{ \	if(p == nil) \		return nil; \	if(e-p < x){ \		werrstr(what ": buffer short: expected %d, have %d", x, (int)(e-p)); \		return nil; \	} \}while(0) u8int *a₀null(u8int *p, u8int *e){	return a₀byte(p, e, Anull);} u8int *a₀bool(u8int *p, u8int *e, int v){	atleast("bool", 2);	*p++ = Abool;	*p++ = !!v;	return p;} u8int *a₀byte(u8int *p, u8int *e, u8int byte){	atleast("byte", 1);	*p++ = byte;	return p;} u8int *a₀i16(u8int *p, u8int *e, s16int i){	atleast("i16", 2);	*p++ = i >> 8;	*p++ = i;	return p;} u8int *a₀i24(u8int *p, u8int *e, s32int i){	atleast("i24", 3);	*p++ = i >> 16;	*p++ = i >> 8;	*p++ = i;	return p;} u8int *a₀i32(u8int *p, u8int *e, s32int i){	atleast("i32", 4);	*p++ = i >> 24;	*p++ = i >> 16;	*p++ = i >> 8;	*p++ = i;	return p;} u8int *a₀i32le(u8int *p, u8int *e, s32int i){	atleast("i32le", 4);	*p++ = i;	*p++ = i >> 8;	*p++ = i >> 16;	*p++ = i >> 24;	return p;} u8int *a₀num(u8int *p, u8int *e, double v){	union {		double v;		u64int u;	}x; 	atleast("num", 1+8);	*p++ = Anum;	x.v = v;	*p++ = x.u >> 56;	*p++ = x.u >> 48;	*p++ = x.u >> 40;	*p++ = x.u >> 32;	*p++ = x.u >> 24;	*p++ = x.u >> 16;	*p++ = x.u >> 8;	*p++ = x.u; 	return p;} u8int *a₀str(u8int *p, u8int *e, char *s){	int n; 	n = strlen(s);	if(n <= 0xffff){		atleast("str", 1+2+n);		*p++ = Astr;		return (u8int*)memmove(a₀i16(p, e, n), s, n) + n;	} 	atleast("lstr", 1+4+n);	*p++ = Alstr;	return (u8int*)memmove(a₀i32(p, e, n), s, n) + n;} u8int *a₀arr(u8int *p, u8int *e){	return a₀byte(p, e, Aarr);} u8int *a₀obj(u8int *p, u8int *e){	return a₀byte(p, e, Aobj);} u8int *a₀end(u8int *p, u8int *e){	return a₀i24(p, e, Aend);} static u8int *a₀kv(u8int *p, u8int *e, char *name){	int n; 	if((n = strlen(name)) > 0xffff){		werrstr("string too long");		return nil;	}	atleast("kv", 2+n);	p = a₀i16(p, e, n); 	return (u8int*)memmove(p, name, n) + n;} u8int *a₀kvbool(u8int *p, u8int *e, char *name, int v){	return a₀bool(a₀kv(p, e, name), e, v);} u8int *a₀kvnum(u8int *p, u8int *e, char *name, double v){	return a₀num(a₀kv(p, e, name), e, v);} u8int *a₀kvstr(u8int *p, u8int *e, char *name, char *v){	return a₀str(a₀kv(p, e, name), e, v);} u8int *a₀data(u8int *p, u8int *e, u8int *d, int sz){	atleast("data", sz); 	return (u8int*)memmove(p, d, sz) + sz;} u8int *a₀byteget(u8int *p, u8int *e, u8int *byte){	atleast("byte", 1);	*byte = *p;	return p+1;} u8int *a₀i16get(u8int *p, u8int *e, s16int *i){	atleast("i16", 2);	*i = p[0]<<8 | p[1];	return p+2;} u8int *a₀i24get(u8int *p, u8int *e, s32int *i){	atleast("i24", 3);	*i = p[0]<<16 | p[1]<<8 | p[2];	return p+3;} u8int *a₀i32get(u8int *p, u8int *e, s32int *i){	atleast("i32", 4);	*i = p[0]<<24 | p[1]<<16 | p[2]<<8 | p[3];	return p+4;} u8int *a₀i32leget(u8int *p, u8int *e, s32int *i){	atleast("i32le", 4);	*i = p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;	return p+4;} voida₀free(A₀ *a){	int i; 	if(a == nil)		return; 	switch(a->type){	case Tstr:		free(a->str);		break;	case Tobj:		for(i = 0; i < a->obj.n; i++){			free(a->obj.k[i]);			a₀free(a->obj.v[i]);		}		free(a->obj.k);		free(a->obj.v);		break;	case Tarr:		for(i = 0; i < a->arr.n; i++)			a₀free(a->arr.v[i]);		free(a->arr.v);	case Tnull:	case Tnum:	case Tbool:		break;	default:		sysfatal("unknown a₀ type %d", a->type);	} 	free(a);} u8int *a₀parse(A₀ **a₀, u8int *p, u8int *e){	s16int s16;	union {		double v;		u64int u;	}x;	int n;	A₀ *a; 	*a₀ = nil;	atleast("type", 1);	a = ecalloc(1, sizeof(*a));	a->type = -1; 	switch(*p++){	case Anull:		a->type = Tnull;		break;	case Anum:		atleast("num", 8);		for(n = 0, x.u = 0; n < 8; n++)			x.u = x.u<<8 | *p++;		a->num = x.v;		a->type = Tnum;		break;	case Abool:		atleast("bool", 1);		a->bool = *p++;		a->type = Tbool;		break;	case Alstr:		if((p = a₀i32get(p, e, &n)) == nil)			return nil;		if(0){	case Astr:			if((p = a₀i16get(p, e, &s16)) == nil)				return nil;			n = s16;		}		atleast("str", n);		a->str = estrndup(p, n);		p += n;		a->type = Tstr;		break;	case Aobj:		atleast("obj", 3); /* Aend should be there anyway */		for(a->obj.n = 0;;){			if((p = a₀i16get(p, e, &s16)) == nil)				break;			if(s16 == 0){				atleast("obj end?", 1);				if(*p != Aend){					werrstr("object doesn't end well");					p = nil;					break;				}				p++;				break;			}			n = s16;			atleast("obj key", n);			a->obj.n++;			a->obj.k = erealloc(a->obj.k, sizeof(*a->obj.k)*a->obj.n);			a->obj.v = erealloc(a->obj.v, sizeof(*a->obj.v)*a->obj.n);			a->obj.k[a->obj.n-1] = estrndup(p, n);			p += n;			if((p = a₀parse(&a->obj.v[a->obj.n-1], p, e)) == nil){				werrstr("obj val: %r");				break;			}		}		a->type = Tobj;		break;	case Aarr:		if((p = a₀i32get(p, e, &a->arr.n)) == nil)			break;		a->arr.v = emalloc(sizeof(*a->arr.v)*a->arr.n);		for(n = 0; n < a->arr.n; n++){			if((p = a₀parse(&a->arr.v[n], p, e)) == nil){				werrstr("arr el: %r");				break;			}		}		if((p = a₀i24get(p, e, &n)) == nil || n != Aend){			p = nil;			werrstr("array doesn't end with Aend");		}		a->type = Tarr;		break;	case Aend:		werrstr("unexpected Aend");		p = nil;		break;	default:		werrstr("unexpected type %d", p[-1]);		p = nil;		break;	} 	if(p == nil)		a₀free(a);	else		*a₀ = a; 	return p;} inta₀fmt(Fmt *f){	A₀ *a;	int i; 	a = va_arg(f->args, A₀*); 	switch(a->type){	case Tstr:		fmtprint(f, "%#q", a->str);		break;	case Tobj:		fmtprint(f, "{");		for(i = 0; i < a->obj.n; i++)			fmtprint(f, "%s%q:%A", i > 0 ? ", " : "", a->obj.k[i], a->obj.v[i]);		fmtprint(f, "}");		break;	case Tarr:		fmtprint(f, "[");		for(i = 0; i < a->arr.n; i++)			fmtprint(f, "%s%A", i > 0 ? ", " : "", a->arr.v[i]);		fmtprint(f, "]");		break;	case Tnum:		fmtprint(f, "%g", a->num);		break;	case Tbool:		fmtprint(f, a->bool ? "true" : "false");		break;	case Tnull:		fmtprint(f, "null");		break;	default:		sysfatal("unknown a₀ type %d", a->type);	} 	return 0;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t