webmcp
changeset 154:c8669dde9ce2
Added JSON export function
author | jbe |
---|---|
date | Thu Jul 31 03:01:53 2014 +0200 (2014-07-31) |
parents | c8c91216255f |
children | 185e944182cb |
files | libraries/json/json.c |
line diff
1.1 --- a/libraries/json/json.c Thu Jul 31 01:21:33 2014 +0200 1.2 +++ b/libraries/json/json.c Thu Jul 31 03:01:53 2014 +0200 1.3 @@ -2,6 +2,7 @@ 1.4 #include <lauxlib.h> 1.5 #include <stdlib.h> 1.6 #include <string.h> 1.7 +#include <math.h> 1.8 1.9 // maximum number of nested JSON values (objects and arrays): 1.10 // NOTE: The Lua reference states that the stack may typically contain at least 1.11 @@ -17,6 +18,7 @@ 1.12 #define JSON_REGENT char 1.13 #define JSON_REGPOINTER void * 1.14 #define json_pushlightref(L, x) lua_pushlightuserdata((L), &json_reference.x) 1.15 +#define json_islightref(L, i, x) (lua_touserdata((L), (i)) == &json_reference.x) 1.16 #define json_regpointer(x) (&json_registry.x) 1.17 #define json_regfetchpointer(L, x) lua_rawgetp((L), LUA_REGISTRYINDEX, (x)) 1.18 #define json_regfetch(L, x) json_regfetchpointer(L, json_regpointer(x)) 1.19 @@ -27,7 +29,6 @@ 1.20 JSON_REGENT nullmark; // magic value to indicate JSON null value in shadow table 1.21 } json_reference; 1.22 1.23 - 1.24 // generate dummy memory addresses that represent Lua objects 1.25 // via lightuserdata keys and LUA_REGISTRYINDEX: 1.26 static struct { 1.27 @@ -751,11 +752,156 @@ 1.28 return 3; 1.29 } 1.30 1.31 +#define JSON_TABLETYPE_UNKNOWN 0 1.32 +#define JSON_TABLETYPE_OBJECT 1 1.33 +#define JSON_TABLETYPE_ARRAY 2 1.34 + 1.35 +static int json_export(lua_State *L) { 1.36 + lua_Number num; 1.37 + const char *str; 1.38 + unsigned char c; 1.39 + size_t strlen; 1.40 + size_t pos = 0; 1.41 + luaL_Buffer buf; 1.42 + char hexcode[7]; // backslash, character 'u', 4 hex digits, and terminating NULL byte 1.43 + int luatype; 1.44 + int tabletype = JSON_TABLETYPE_UNKNOWN; 1.45 + int needsep = 0; 1.46 + lua_Integer idx; 1.47 + lua_settop(L, 1); 1.48 + switch (lua_type(L, 1)) { 1.49 + case LUA_TNIL: 1.50 + lua_pushliteral(L, "null"); 1.51 + return 1; 1.52 + case LUA_TNUMBER: 1.53 + num = lua_tonumber(L, 1); 1.54 + if (isnan(num)) return luaL_error(L, "JSON export not possible for NaN value"); 1.55 + if (isinf(num)) return luaL_error(L, "JSON export not possible for infinite numbers"); 1.56 + lua_tostring(L, 1); 1.57 + return 1; 1.58 + case LUA_TBOOLEAN: 1.59 + if (lua_toboolean(L, 1)) lua_pushliteral(L, "true"); 1.60 + else lua_pushliteral(L, "false"); 1.61 + return 1; 1.62 + case LUA_TSTRING: 1.63 + str = lua_tolstring(L, 1, &strlen); 1.64 + luaL_buffinit(L, &buf); 1.65 + luaL_addchar(&buf, '"'); 1.66 + while (pos < strlen) { 1.67 + c = str[pos++]; 1.68 + if (c == '"') luaL_addstring(&buf, "\\\""); 1.69 + else if (c == '\\') luaL_addstring(&buf, "\\\\"); 1.70 + else if (c == 127) luaL_addstring(&buf, "\\u007F"); 1.71 + else if (c >= 32) luaL_addchar(&buf, c); 1.72 + else if (c == '\b') luaL_addstring(&buf, "\\b"); 1.73 + else if (c == '\f') luaL_addstring(&buf, "\\f"); 1.74 + else if (c == '\n') luaL_addstring(&buf, "\\n"); 1.75 + else if (c == '\r') luaL_addstring(&buf, "\\r"); 1.76 + else if (c == '\t') luaL_addstring(&buf, "\\t"); 1.77 + else if (c == '\v') luaL_addstring(&buf, "\\v"); 1.78 + else { 1.79 + sprintf(hexcode, "\\u%04X", c); 1.80 + luaL_addstring(&buf, hexcode); 1.81 + } 1.82 + } 1.83 + luaL_addchar(&buf, '"'); 1.84 + luaL_pushresult(&buf); 1.85 + return 1; 1.86 + case LUA_TTABLE: 1.87 + if (lua_getmetatable(L, 1)) { 1.88 + json_regfetch(L, objectmt); 1.89 + if (lua_rawequal(L, -2, -1)) { 1.90 + tabletype = JSON_TABLETYPE_OBJECT; 1.91 + } else { 1.92 + json_regfetch(L, arraymt); 1.93 + if (lua_rawequal(L, -3, -1)) tabletype = JSON_TABLETYPE_ARRAY; 1.94 + } 1.95 + } 1.96 + json_regfetch(L, shadowtbl); 1.97 + lua_pushvalue(L, 1); 1.98 + lua_rawget(L, -2); 1.99 + if (!lua_isnil(L, -1)) lua_replace(L, 1); 1.100 + lua_settop(L, 1); 1.101 + if (tabletype == JSON_TABLETYPE_UNKNOWN) { 1.102 + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { 1.103 + luatype = lua_type(L, -2); 1.104 + if (tabletype == JSON_TABLETYPE_UNKNOWN) { 1.105 + if (luatype == LUA_TSTRING) tabletype = JSON_TABLETYPE_OBJECT; 1.106 + else if (luatype == LUA_TNUMBER) tabletype = JSON_TABLETYPE_ARRAY; 1.107 + } else if ( 1.108 + (tabletype == JSON_TABLETYPE_OBJECT && luatype == LUA_TNUMBER) || 1.109 + (tabletype == JSON_TABLETYPE_ARRAY && luatype == LUA_TSTRING) 1.110 + ) { 1.111 + goto json_export_tabletype_error; 1.112 + } 1.113 + } 1.114 + } 1.115 + switch (tabletype) { 1.116 + case JSON_TABLETYPE_OBJECT: 1.117 + lua_settop(L, 3); 1.118 + luaL_buffinit(L, &buf); 1.119 + luaL_addchar(&buf, '{'); 1.120 + for (lua_pushnil(L); lua_next(L, 1); ) { 1.121 + if (lua_type(L, -2) == LUA_TSTRING) { 1.122 + lua_replace(L, 3); 1.123 + lua_replace(L, 2); 1.124 + if (needsep) luaL_addchar(&buf, ','); 1.125 + else needsep = 1; 1.126 + lua_pushcfunction(L, json_export); 1.127 + lua_pushvalue(L, 2); 1.128 + lua_call(L, 1, 1); 1.129 + luaL_addvalue(&buf); 1.130 + luaL_addchar(&buf, ':'); 1.131 + if (json_islightref(L, 3, nullmark)) { 1.132 + luaL_addstring(&buf, "null"); 1.133 + } else { 1.134 + lua_pushcfunction(L, json_export); 1.135 + lua_pushvalue(L, 3); 1.136 + lua_call(L, 1, 1); 1.137 + luaL_addvalue(&buf); 1.138 + } 1.139 + lua_pushvalue(L, 2); 1.140 + } else { 1.141 + lua_pop(L, 1); 1.142 + } 1.143 + } 1.144 + luaL_addchar(&buf, '}'); 1.145 + luaL_pushresult(&buf); 1.146 + return 1; 1.147 + case JSON_TABLETYPE_ARRAY: 1.148 + lua_settop(L, 2); 1.149 + luaL_buffinit(L, &buf); 1.150 + luaL_addchar(&buf, '['); 1.151 + for (idx = 1; ; idx++) { 1.152 + lua_rawgeti(L, 1, idx); 1.153 + if (lua_isnil(L, -1)) { 1.154 + lua_pop(L, 1); 1.155 + break; 1.156 + } 1.157 + lua_replace(L, 2); 1.158 + if (needsep) luaL_addchar(&buf, ','); 1.159 + else needsep = 1; 1.160 + lua_pushcfunction(L, json_export); 1.161 + lua_pushvalue(L, 2); 1.162 + lua_call(L, 1, 1); 1.163 + luaL_addvalue(&buf); 1.164 + } 1.165 + luaL_addchar(&buf, ']'); 1.166 + luaL_pushresult(&buf); 1.167 + return 1; 1.168 + } 1.169 + json_export_tabletype_error: 1.170 + return luaL_error(L, "JSON export not possible for ambiguous table (cannot decide whether it is an object or array)"); 1.171 + } 1.172 + return luaL_error(L, "JSON export not possible for values of type \"%s\"", lua_typename(L, lua_type(L, 1))); 1.173 +} 1.174 + 1.175 // functions in library module: 1.176 static const struct luaL_Reg json_module_functions[] = { 1.177 {"object", json_object}, 1.178 {"array", json_array}, 1.179 {"import", json_import}, 1.180 + {"export", json_export}, 1.181 {"get", json_get}, 1.182 {"type", json_type}, 1.183 {"isnull", json_isnull},