ref: 8fb3df30a16cc34dcb10c3c068ddca913fb71047
dir: /amf.c/
#include <u.h> #include <libc.h> #include "amf.h" enum { Anum, Abool, Astr, Aobj, Aarr = 8, Aend, Alstr = 12, }; #define atleast(x) do{ \ if(p == nil) \ return nil; \ if(e-p < x){ \ werrstr("buffer short"); \ return nil; \ } \ }while(0) u8int * amfbool(u8int *p, u8int *e, int v) { atleast(2); *p++ = Abool; *p++ = !!v; return p; } u8int * amfbyte(u8int *p, u8int *e, u8int byte) { atleast(1); *p++ = byte; return p; } u8int * amfi16(u8int *p, u8int *e, s16int i) { atleast(2); *p++ = i >> 8; *p++ = i; return p; } u8int * amfi24(u8int *p, u8int *e, s32int i) { atleast(3); *p++ = i >> 16; *p++ = i >> 8; *p++ = i; return p; } u8int * amfi32(u8int *p, u8int *e, s32int i) { atleast(4); *p++ = i >> 24; *p++ = i >> 16; *p++ = i >> 8; *p++ = i; return p; } u8int * amfnum(u8int *p, u8int *e, double v) { union { double v; u64int u; }x; atleast(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 * amfstr(u8int *p, u8int *e, char *s) { int n; n = strlen(s); if(n <= 0xffff){ atleast(1+2+n); *p++ = Astr; return (u8int*)memmove(amfi16(p, e, n), s, n) + n; } atleast(1+4+n); *p++ = Alstr; return (u8int*)memmove(amfi32(p, e, n), s, n) + n; } u8int * amfarr(u8int *p, u8int *e) { return amfbyte(p, e, Aarr); } u8int * amfobj(u8int *p, u8int *e) { return amfbyte(p, e, Aobj); } u8int * amfend(u8int *p, u8int *e) { return amfi24(p, e, Aend); } static u8int * amfkv(u8int *p, u8int *e, char *name) { int n; if((n = strlen(name)) > 0xffff){ werrstr("string too long"); return nil; } atleast(2+n); p = amfi16(p, e, n); return (u8int*)memmove(p, name, n) + n; } u8int * amfkvbool(u8int *p, u8int *e, char *name, int v) { return amfbool(amfkv(p, e, name), e, v); } u8int * amfkvnum(u8int *p, u8int *e, char *name, double v) { return amfnum(amfkv(p, e, name), e, v); } u8int * amfkvstr(u8int *p, u8int *e, char *name, char *v) { return amfstr(amfkv(p, e, name), e, v); } u8int * amfbyteget(u8int *p, u8int *e, u8int *byte) { atleast(1); *byte = *p; return p+1; } u8int * amfi16get(u8int *p, u8int *e, s16int *i) { atleast(2); *i = p[0]<<8 | p[1]; return p+2; } u8int * amfi24get(u8int *p, u8int *e, s32int *i) { atleast(3); *i = p[0]<<16 | p[1]<<8 | p[2]; return p+3; } u8int * amfi32get(u8int *p, u8int *e, s32int *i) { atleast(4); *i = p[0]<<16 | p[1]<<16 | p[2]<<8 | p[3]; return p+4; } u8int * amffmt(Fmt *f, u8int *p, u8int *e, int one) { union { double v; u64int u; }x; s16int s16; int n; for(; p != e;){ atleast(1); switch(*p++){ case Anum: atleast(8); x.u = (uvlong)p[0]<<56 | (uvlong)p[1]<<48 | (uvlong)p[2]<<40 | (uvlong)p[3]<<32; x.u |= p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7]; fmtprint(f, "%g", x.v); p += 8; break; case Abool: atleast(1); fmtprint(f, *p ? "true" : "false"); p++; break; case Astr: if((p = amfi16get(p, e, &s16)) == nil) return nil; n = s16; String: atleast(n); /* FIXME this isn't correct - UTF-8 */ fmtprint(f, "%.*#q", n, (char*)p); p += n; break; case Aobj: fmtprint(f, "O{"); for(;;){ if((p = amfi16get(p, e, &s16)) == nil) return nil; if(s16 == 0){ atleast(1); if(*p != Aend){ werrstr("object doesn't end well"); return nil; } p++; fmtprint(f, "}"); break; } n = s16; atleast(n); fmtprint(f, "%.*s=", n, (char*)p); p += n; p = amffmt(f, p, e, 1); fmtprint(f, " "); } break; case Aarr: fmtprint(f, "A{"); atleast(4); p += 4; break; case Aend: fmtprint(f, "}"); break; case Alstr: if((p = amfi32get(p, e, &n)) == nil) return nil; goto String; default: fmtprint(f, "?%d?", p[-1]); break; } if(one) break; if(p != e) fmtprint(f, " "); } return p; }