shithub: rtmp

Download patch

ref: 02a850608753ed9c743dfd6992ad56e4c4ea3d53
parent: 5a2a972aa72c4b827ea784d91c15fd02adee3f71
author: Sigrid Solveig Haflínudóttir <[email protected]>
date: Thu Jul 29 05:00:29 EDT 2021

add amf0 stuff

--- /dev/null
+++ b/amf0.c
@@ -1,0 +1,374 @@
+#include <u.h>
+#include <libc.h>
+#include "amf0.h"
+#include "util.h"
+
+enum {
+	Anum,
+	Abool,
+	Astr,
+	Aobj,
+	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 *
+amf0bool(u8int *p, u8int *e, int v)
+{
+	atleast("bool", 2);
+	*p++ = Abool;
+	*p++ = !!v;
+	return p;
+}
+
+u8int *
+amf0byte(u8int *p, u8int *e, u8int byte)
+{
+	atleast("byte", 1);
+	*p++ = byte;
+	return p;
+}
+
+u8int *
+amf0i16(u8int *p, u8int *e, s16int i)
+{
+	atleast("i16", 2);
+	*p++ = i >> 8;
+	*p++ = i;
+	return p;
+}
+
+u8int *
+amf0i24(u8int *p, u8int *e, s32int i)
+{
+	atleast("i24", 3);
+	*p++ = i >> 16;
+	*p++ = i >> 8;
+	*p++ = i;
+	return p;
+}
+
+u8int *
+amf0i32(u8int *p, u8int *e, s32int i)
+{
+	atleast("i32", 4);
+	*p++ = i >> 24;
+	*p++ = i >> 16;
+	*p++ = i >> 8;
+	*p++ = i;
+	return p;
+}
+
+u8int *
+amf0num(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 *
+amf0str(u8int *p, u8int *e, char *s)
+{
+	int n;
+
+	n = strlen(s);
+	if(n <= 0xffff){
+		atleast("str", 1+2+n);
+		*p++ = Astr;
+		return (u8int*)memmove(amf0i16(p, e, n), s, n) + n;
+	}
+
+	atleast("lstr", 1+4+n);
+	*p++ = Alstr;
+	return (u8int*)memmove(amf0i32(p, e, n), s, n) + n;
+}
+
+u8int *
+amf0arr(u8int *p, u8int *e)
+{
+	return amf0byte(p, e, Aarr);
+}
+
+u8int *
+amf0obj(u8int *p, u8int *e)
+{
+	return amf0byte(p, e, Aobj);
+}
+
+u8int *
+amf0end(u8int *p, u8int *e)
+{
+	return amf0i24(p, e, Aend);
+}
+
+static u8int *
+amf0kv(u8int *p, u8int *e, char *name)
+{
+	int n;
+
+	if((n = strlen(name)) > 0xffff){
+		werrstr("string too long");
+		return nil;
+	}
+	atleast("kv", 2+n);
+	p = amf0i16(p, e, n);
+
+	return (u8int*)memmove(p, name, n) + n;
+}
+
+u8int *
+amf0kvbool(u8int *p, u8int *e, char *name, int v)
+{
+	return amf0bool(amf0kv(p, e, name), e, v);
+}
+
+u8int *
+amf0kvnum(u8int *p, u8int *e, char *name, double v)
+{
+	return amf0num(amf0kv(p, e, name), e, v);
+}
+
+u8int *
+amf0kvstr(u8int *p, u8int *e, char *name, char *v)
+{
+	return amf0str(amf0kv(p, e, name), e, v);
+}
+
+u8int *
+amf0byteget(u8int *p, u8int *e, u8int *byte)
+{
+	atleast("byte", 1);
+	*byte = *p;
+	return p+1;
+}
+
+u8int *
+amf0i16get(u8int *p, u8int *e, s16int *i)
+{
+	atleast("i16", 2);
+	*i = p[0]<<8 | p[1];
+	return p+2;
+}
+
+u8int *
+amf0i24get(u8int *p, u8int *e, s32int *i)
+{
+	atleast("i24", 3);
+	*i = p[0]<<16 | p[1]<<8 | p[2];
+	return p+3;
+}
+
+u8int *
+amf0i32get(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 *
+amf0i32leget(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
+amf0free(Amf0 *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]);
+			amf0free(a->obj.v[i]);
+		}
+		break;
+	case Tarr:
+		for(i = 0; i < a->arr.n; i++)
+			amf0free(a->arr.v[i]);
+	case Tnum:
+	case Tbool:
+		break;
+	default:
+		sysfatal("unknown amf0 type %d", a->type);
+	}
+
+	free(a);
+}
+
+u8int *
+amf0parse(Amf0 **amf0, u8int *p, u8int *e)
+{
+	s16int s16;
+	union {
+		double v;
+		u64int u;
+	}x;
+	int n;
+	Amf0 *a;
+
+	atleast("type", 1);
+
+	a = ecalloc(1, sizeof(Amf0));
+	*amf0 = nil;
+
+	switch(*p++){
+	case Anum:
+		atleast("num", 8);
+		for(n = 0, x.u = 0; n < 8; n++)
+			x.u = x.u<<8 | *p++;
+		a->type = Tnum;
+		a->num = x.v;
+		break;
+	case Abool:
+		atleast("bool", 1);
+		a->type = Tbool;
+		a->bool = *p++;
+		break;
+	case Alstr:
+		if((p = amf0i32get(p, e, &n)) == nil)
+			return nil;
+		if(0){
+	case Astr:
+			if((p = amf0i16get(p, e, &s16)) == nil)
+				return nil;
+			n = s16;
+		}
+		atleast("str", n);
+		a->str = estrndup(p, n);
+		p += n;
+		break;
+	case Aobj:
+		atleast("obj", 3); /* Aend should be there anyway */
+		a->type = Tobj;
+		for(a->obj.n = 0;;){
+			if((p = amf0i16get(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 = amf0parse(&a->obj.v[a->obj.n-1], p, e)) == nil){
+				werrstr("obj val: %r");
+				break;
+			}
+		}
+		break;
+	case Aarr:
+		a->type = Tarr;
+		if((p = amf0i32get(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 = amf0parse(&a->arr.v[n], p, e)) == nil){
+				werrstr("arr el: %r");
+				break;
+			}
+		}
+		if((p = amf0i24get(p, e, &n)) == nil || n != Aend){
+			p = nil;
+			werrstr("array doesn't end with Aend");
+		}
+		break;
+	case Aend:
+		p = nil;
+		werrstr("unexpected Aend");
+		break;
+	default:
+		werrstr("unexpected type %d", p[-1]);
+		p = nil;
+		break;
+	}
+
+	if(p == nil)
+		amf0free(a);
+	else
+		*amf0 = a;
+
+	return p;
+}
+
+int
+amf0fmt(Fmt *f)
+{
+	Amf0 *a;
+	int i;
+
+	a = va_arg(f->args, Amf0*);
+
+	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;
+	default:
+		sysfatal("unknown amf0 type %d", a->type);
+	}
+
+	return 0;
+}
--- /dev/null
+++ b/amf0.h
@@ -1,0 +1,53 @@
+enum {
+	Tstr,
+	Tnum,
+	Tbool,
+	Tarr,
+	Tobj,
+};
+
+typedef struct Amf0 Amf0;
+
+struct Amf0 {
+	int type;
+	union {
+		char *str;
+		double num;
+		u8int bool;
+		struct {
+			Amf0 **v;
+			int n;
+		}arr;
+		struct {
+			char **k;
+			Amf0 **v;
+			int n;
+		}obj;
+	};
+};
+
+u8int *amf0i16(u8int *p, u8int *e, s16int i);
+u8int *amf0bool(u8int *p, u8int *e, int v);
+u8int *amf0byte(u8int *p, u8int *e, u8int byte);
+u8int *amf0i24(u8int *p, u8int *e, s32int i);
+u8int *amf0i32(u8int *p, u8int *e, s32int i);
+u8int *amf0num(u8int *p, u8int *e, double v);
+u8int *amf0str(u8int *p, u8int *e, char *s);
+u8int *amf0arr(u8int *p, u8int *e);
+u8int *amf0obj(u8int *p, u8int *e);
+u8int *amf0end(u8int *p, u8int *e);
+u8int *amf0kvnum(u8int *p, u8int *e, char *name, double v);
+u8int *amf0kvstr(u8int *p, u8int *e, char *name, char *v);
+u8int *amf0kvbool(u8int *p, u8int *e, char *name, int v);
+
+u8int *amf0byteget(u8int *p, u8int *e, u8int *byte);
+u8int *amf0i16get(u8int *p, u8int *e, s16int *i);
+u8int *amf0i24get(u8int *p, u8int *e, s32int *i);
+u8int *amf0i32get(u8int *p, u8int *e, s32int *i);
+u8int *amf0i32leget(u8int *p, u8int *e, s32int *i);
+
+u8int *amf0parse(Amf0 **a, u8int *p, u8int *e);
+void amf0free(Amf0 *a);
+
+#pragma varargck type "A" Amf0*
+int amf0fmt(Fmt *f);