ref: b5c87f9d2711099c002406442c4839acd11f01a6
dir: /amf0.c/
#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; } void a₀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; } int a₀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; }