#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;}
#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;
}