/* TODO: typed object support */ static void amf0_encode_table_as_object(amf_buf *buf, lua_State *L, int idx, int ridx) { size_t key_len; const char *key; amf_buf_append_char(buf, AMF0_OBJECT); for (lua_pushnil(L); lua_next(L, idx); lua_pop(L, 1)) { switch (lua_type(L, -2)) { case LUA_TNUMBER: lua_pushvalue(L, -2); key = lua_tolstring(L, -1, &key_len); amf_buf_append_u16(buf, (uint16_t)key_len); amf_buf_append(buf, key, key_len); lua_pop(L, 1); break; case LUA_TSTRING: key = lua_tolstring(L, -2, &key_len); amf_buf_append_u16(buf, (uint16_t)key_len); amf_buf_append(buf, key, key_len); break; default: continue; } amf0_encode(L, buf, 0, -1, ridx); } amf_buf_append_u16(buf, (uint16_t)0); amf_buf_append_char(buf, AMF0_END_OF_OBJECT); }
void amf_encode_msg(lua_State *L, amf_buf *buf) { luaL_checktype(L, -1, LUA_TTABLE); int i = 0, ver; while(i++ < 3) { lua_rawgeti(L, -1, i); switch (i) { case 1: { ver = lua_tonumber(L, -1); amf_buf_append_u16(buf, ver); break; } case 2: { /* headers */ if (lua_isnil(L, -1)) { amf_buf_append_u16(buf, 0); } else if (lua_istable(L, -1)) { int hc = lua_objlen(L, -1); amf_buf_append_u16(buf, hc); int j; for (j = 1; j <= hc; j++) { lua_rawgeti(L, -1, j); encode_hdr(L, buf, ver); lua_pop(L, 1); } } else { luaL_error(L, "invalid amf msg header container structure, must be a table or nil"); } break; } case 3: { if (lua_isnil(L, -1)) { amf_buf_append_u16(buf, 0); } else if (lua_istable(L, -1)) { int bc = lua_objlen(L, -1); amf_buf_append_u16(buf, bc); int j; for (j = 1; j <= bc; j++) { lua_rawgeti(L, -1, j); encode_body(L, buf, ver); lua_pop(L, 1); } } else { luaL_error(L, "invalid amf msg body container structure, must be a table or nil"); } break; } } lua_pop(L, 1); } }
static int amf0_encode_ref(amf_buf *buf, lua_State *L, int idx, int ridx) { int ref; /* lookup in the ref table */ lua_pushvalue(L, idx); lua_rawget(L, ridx); ref = (lua_isnumber(L, -1) ? lua_tonumber(L, -1) : -1); lua_pop(L, 1); if (ref >= 0) { amf_buf_append_char(buf, AMF0_REFERENCE); if (ref > UINT16_MAX) { luaL_error(L, "amf0 reference overflow"); } amf_buf_append_u16(buf, ref); } else { save_ref(L, idx, ridx); } return ref; }
static void encode_hdr(lua_State *L, amf_buf *buf, int ver) { if(!lua_istable(L, -1)) { luaL_error(L, "invalid header structure, must be a dense table"); } /* name */ lua_rawgeti(L, -1, 1); size_t len; const char *name = lua_tolstring(L, -1, &len); amf_buf_append_u16(buf, (uint16_t)len); if (len > 0) amf_buf_append(buf, name, (uint16_t)len); lua_pop(L, 1); /* must understand */ lua_rawgeti(L, -1, 2); int mu = lua_toboolean(L, -1); amf_buf_append_char(buf, (char)mu); lua_pop(L, 1); /* content length */ amf_buf_append_u32(buf, (uint32_t)0); lua_rawgeti(L, -1, 3); lua_newtable(L); amf0_encode(L, buf, (ver == 3), -2, lua_gettop(L)); lua_pop(L, 2); /* pops the obj and ref table */ }
static int lua_amf_buffer_write_ushort(lua_State *L) { amf_buf *b = luaL_checkudata(L, 1, "amf_buffer"); unsigned short s = (unsigned short)luaL_checkint(L, 2); amf_buf_append_u16(b, s); return 0; }
static int lua_amf_buffer_write_str(lua_State *L) { amf_buf *b = luaL_checkudata(L, 1, "amf_buffer"); size_t len; const char *str = luaL_checklstring(L, 2, &len); printf("string len: %d\n", (uint16_t)len); amf_buf_append_u16(b, (uint16_t)len); amf_buf_append(b, str, len); return 0; }
static void encode_body(lua_State *L, amf_buf *buf, int ver) { if(!lua_istable(L, -1)) { luaL_error(L, "invalid body structure, must be a dense table"); } size_t len; const char *uri; /* target uri */ lua_rawgeti(L, -1, 1); uri = lua_tolstring(L, -1, &len); amf_buf_append_u16(buf, (uint16_t)len); if (len > 0) { amf_buf_append(buf, uri, (uint16_t)len); printf("target: %s\n", uri); } lua_pop(L, 1); /* response uri */ lua_rawgeti(L, -1, 2); uri = lua_tolstring(L, -1, &len); amf_buf_append_u16(buf, (uint16_t)len); if (len > 0) { amf_buf_append(buf, uri, (uint16_t)len); printf("response: %s\n", uri); } lua_pop(L, 1); /* content length */ amf_buf_append_u32(buf, (uint32_t)0); lua_rawgeti(L, -1, 3); lua_newtable(L); amf0_encode(L, buf, (ver == 3), -2, lua_gettop(L)); lua_pop(L, 2); /* pops the obj and ref table */ }
static void amf0_encode_string(amf_buf *b, const char *s, size_t len) { uint16_t u16; uint32_t u32; if (len < UINT16_MAX) { u16 = (uint16_t)len; amf_buf_append_char(b, AMF0_STRING); amf_buf_append_u16(b, u16); amf_buf_append(b, s, u16); } else { // long string if (len > UINT32_MAX) { len = UINT32_MAX; } u32 = (uint32_t)len; amf_buf_append_char(b, AMF0_L_STRING); amf_buf_append_u32(b, u32); amf_buf_append(b, s, u32); } }