#include "lua_common.h" #include #include #include int libretrodb_lua_to_rmsgpack_value(lua_State *L, int index, struct rmsgpack_dom_value * out) { size_t tmp_len; lua_Number tmp_num; struct rmsgpack_dom_value * tmp_value; int i, rv = -1; const char * tmp_string = NULL; char * tmp_buff = NULL; const int key_idx = -2; const int value_idx = -1; const int MAX_FIELDS = 100; out->type = RDT_MAP; out->val.map.len = 0; out->val.map.items = calloc(MAX_FIELDS, sizeof(struct rmsgpack_dom_pair)); lua_pushnil(L); while (lua_next(L, index - 1) != 0) { if (out->val.map.len > MAX_FIELDS) printf("skipping due to too many keys\n"); else if (!lua_isstring(L, key_idx)) printf("skipping non string key\n"); else if (lua_isnil(L, value_idx)) { /* Skipping nil value fields to save disk space */ } else { i = out->val.map.len; tmp_buff = strdup(lua_tostring(L, key_idx)); out->val.map.items[i].key.type = RDT_STRING; out->val.map.items[i].key.val.string.len = strlen(tmp_buff); out->val.map.items[i].key.val.string.buff = tmp_buff; tmp_value = &out->val.map.items[i].value; switch (lua_type(L, value_idx)) { case LUA_TNUMBER: tmp_num = lua_tonumber(L, value_idx); tmp_value->type = RDT_INT; tmp_value->val.int_ = tmp_num; break; case LUA_TBOOLEAN: tmp_value->type = RDT_BOOL; tmp_value->val.bool_ = lua_toboolean(L, value_idx); break; case LUA_TSTRING: tmp_buff = strdup(lua_tostring(L, value_idx)); tmp_value->type = RDT_STRING; tmp_value->val.string.len = strlen(tmp_buff); tmp_value->val.string.buff = tmp_buff; break; case LUA_TTABLE: lua_getfield(L, value_idx, "binary"); if (!lua_isstring(L, -1)) { lua_pop(L, 1); lua_getfield(L, value_idx, "uint"); if (!lua_isnumber(L, -1)) { lua_pop(L, 1); goto set_nil; } else { tmp_num = lua_tonumber(L, -1); tmp_value->type = RDT_UINT; tmp_value->val.uint_ = tmp_num; lua_pop(L, 1); } } else { tmp_string = lua_tolstring(L, -1, &tmp_len); tmp_buff = malloc(tmp_len); memcpy(tmp_buff, tmp_string, tmp_len); tmp_value->type = RDT_BINARY; tmp_value->val.binary.len = tmp_len; tmp_value->val.binary.buff = tmp_buff; lua_pop(L, 1); } break; default: set_nil: tmp_value->type = RDT_NULL; } out->val.map.len++; } lua_pop(L, 1); } #if 1 /* re-order to avoid random output each run */ struct rmsgpack_dom_pair* ordered_pairs = calloc(out->val.map.len, sizeof(struct rmsgpack_dom_pair)); struct rmsgpack_dom_pair* ordered_pairs_outp = ordered_pairs; const char* ordered_keys[] = { "name", "description", "rom_name", "size", "users", "releasemonth", "releaseyear", "rumble", "analog", "famitsu_rating", "edge_rating", "edge_issue", "edge_review", "enhancement_hw", "barcode", "esrb_rating", "elspa_rating", "pegi_rating", "cero_rating", "franchise", "developer", "publisher", "origin", "crc", "md5", "sha1", "serial" }; for (i = 0; i < (sizeof(ordered_keys)/sizeof(char*)); i++) { int j; for (j = 0; j < out->val.map.len; j++) { if(string_is_equal(ordered_keys[i], out->val.map.items[j].key.val.string.buff)) { *ordered_pairs_outp++ = out->val.map.items[j]; break; } } } free(out->val.map.items); out->val.map.items = ordered_pairs; out->val.map.len = ordered_pairs_outp - ordered_pairs; #endif rv = 0; return rv; }