int lua_amf_decode(lua_State *L) { int ver; int top; size_t pos; size_t buf_size; const char *buf; amf_cursor *cur; ver = luaL_checkint(L, 1); check_amf_ver(ver, 1); buf = luaL_checklstring(L, 2, &buf_size); pos = luaL_optint(L, 3, 0); luaL_argcheck(L, pos >= 0, 3, "input offset may not be negative"); buf_size = min(luaL_optint(L, 4, buf_size), (int)buf_size); luaL_argcheck(L, buf_size >= pos, 4, "input buf overflow"); top = lua_gettop(L); cur = amf_cursor_new(buf, buf_size); if (ver == AMF_VER0) { lua_newtable(L); amf0_decode(L, cur, top+1); } else { lua_newtable(L); lua_newtable(L); lua_newtable(L); amf3_decode(L, cur, top + 1, top + 2, top + 3); } if (cur->err) { lua_pushnil(L); lua_pushstring(L, cur->err_msg); } else { //obj is at top of the stack lua_pushnil(L); } lua_pushinteger(L, buf_size - cur->left); amf_cursor_free(cur); return 3; }
void amf0_decode(lua_State *L, amf_cursor *c, int ridx) { amf_cursor_need(c, 1); switch (c->p[0]) { case AMF0_BOOLEAN: amf_cursor_need(c, 2); lua_pushboolean(L, c->p[1] == 0x01 ? 1 : 0); amf_cursor_consume(c, 2); break; case AMF0_NULL: case AMF0_UNDEFINED: lua_pushnil(L); amf_cursor_consume(c, 1); break; case AMF0_NUMBER: amf_cursor_need(c, 9); assert(sizeof(double) == 8); double d; memcpy(&d, c->p + 1, 8); reverse_if_little_endian(&d, 8); lua_pushnumber(L, d); amf_cursor_consume(c, 9); break; case AMF0_STRING: amf_cursor_consume(c, 1); amf0_decode_string(L, c, 16); break; case AMF0_L_STRING: amf_cursor_consume(c, 1); amf0_decode_string(L, c, 32); break; case AMF0_OBJECT: amf_cursor_consume(c, 1); amf0_decode_to_lua_table(L, c, ridx); break; case AMF0_ECMA_ARRAY: /* the property count, basicly 0 */ amf_cursor_skip(c, 5); amf0_decode_to_lua_table(L, c, ridx); break; case AMF0_STRICT_ARRAY: amf_cursor_need(c, 5); uint32_t count = c->p[1] << 24 | c->p[2] << 16 | c->p[3] << 8 | c->p[4]; amf_cursor_consume(c, 5); assert(count <= INT_MAX); if (count > INT_MAX) { c->err = AMF_CUR_ERR_BADFMT; c->err_msg = "strict array elements count overflow"; return; } lua_createtable(L, (int)count, 0); amf0_decode_remember_ref(L, -1, ridx); for (int i = 1; i <= (int)count; i++) { amf0_decode(L, c, ridx); amf_cursor_checkerr(c); lua_rawseti(L, -2, i); } break; case AMF0_TYPED_OBJECT: amf_cursor_consume(c, 1); amf0_decode_string(L, c, 16); amf0_decode_to_lua_table(L, c, ridx); /* push alias name */ lua_pushstring(L, "__amf_alias__"); lua_pushvalue(L, -3); lua_rawset(L, -3); /* remove alias from stack */ lua_remove(L, -2); break; case AMF0_REFERENCE: amf_cursor_need(c, 3); uint16_t ref = c->p[1] << 8 | c->p[2]; amf_cursor_consume(c, 3); lua_rawgeti(L, ridx, ref + 1); if (lua_isnil(L, -1)) { c->err = AMF_CUR_ERR_BADFMT; c->err_msg = "reference not found"; return; } break; case AMF0_AVMPLUS: { lua_newtable(L); lua_newtable(L); int sidx = lua_gettop(L); amf3_decode(L, c, sidx, ridx, sidx - 1); break; } default: c->err = AMF_CUR_ERR_BADFMT; } }