diff options
Diffstat (limited to '')
| -rw-r--r-- | lua_cjson.c | 367 |
1 files changed, 230 insertions, 137 deletions
diff --git a/lua_cjson.c b/lua_cjson.c index b87aebf..b2869c1 100644 --- a/lua_cjson.c +++ b/lua_cjson.c | |||
| @@ -20,31 +20,197 @@ | |||
| 20 | 20 | ||
| 21 | /* FIXME: | 21 | /* FIXME: |
| 22 | * - Option to encode non-printable characters? Only \" \\ are required | 22 | * - Option to encode non-printable characters? Only \" \\ are required |
| 23 | * - Protect against cycles when encoding JSON from a data structure | ||
| 24 | * - Max depth? Notice cycles? | ||
| 25 | */ | 23 | */ |
| 26 | 24 | ||
| 27 | #include <assert.h> | 25 | #include <assert.h> |
| 28 | #include <string.h> | 26 | #include <string.h> |
| 29 | #include <math.h> | 27 | #include <math.h> |
| 30 | |||
| 31 | #include <pthread.h> | ||
| 32 | |||
| 33 | #include <lua.h> | 28 | #include <lua.h> |
| 34 | #include <lauxlib.h> | 29 | #include <lauxlib.h> |
| 35 | 30 | ||
| 36 | #include "strbuf.h" | 31 | #include "strbuf.h" |
| 37 | 32 | ||
| 38 | /* Encode very sparse arrays as objects */ | 33 | |
| 39 | #ifndef VERY_SPARSE_ARRAY_RATIO | 34 | #define CJSON_CONFIG_KEY "cjson_configdata" |
| 40 | #define VERY_SPARSE_ARRAY_RATIO 2 | 35 | #define DEFAULT_SPARSE_RATIO 2 |
| 41 | #endif | 36 | #define DEFAULT_MAX_DEPTH 20 |
| 37 | |||
| 38 | typedef enum { | ||
| 39 | T_OBJ_BEGIN, | ||
| 40 | T_OBJ_END, | ||
| 41 | T_ARR_BEGIN, | ||
| 42 | T_ARR_END, | ||
| 43 | T_STRING, | ||
| 44 | T_NUMBER, | ||
| 45 | T_BOOLEAN, | ||
| 46 | T_NULL, | ||
| 47 | T_COLON, | ||
| 48 | T_COMMA, | ||
| 49 | T_END, | ||
| 50 | T_WHITESPACE, | ||
| 51 | T_ERROR, | ||
| 52 | T_UNKNOWN | ||
| 53 | } json_token_type_t; | ||
| 54 | |||
| 55 | static const char *json_token_type_name[] = { | ||
| 56 | "T_OBJ_BEGIN", | ||
| 57 | "T_OBJ_END", | ||
| 58 | "T_ARR_BEGIN", | ||
| 59 | "T_ARR_END", | ||
| 60 | "T_STRING", | ||
| 61 | "T_NUMBER", | ||
| 62 | "T_BOOLEAN", | ||
| 63 | "T_NULL", | ||
| 64 | "T_COLON", | ||
| 65 | "T_COMMA", | ||
| 66 | "T_END", | ||
| 67 | "T_WHITESPACE", | ||
| 68 | "T_ERROR", | ||
| 69 | "T_UNKNOWN", | ||
| 70 | NULL | ||
| 71 | }; | ||
| 72 | |||
| 73 | typedef struct { | ||
| 74 | json_token_type_t ch2token[256]; | ||
| 75 | char ch2escape[256]; | ||
| 76 | int sparse_ratio; | ||
| 77 | int max_depth; | ||
| 78 | int current_depth; | ||
| 79 | } json_config_t; | ||
| 80 | |||
| 81 | typedef struct { | ||
| 82 | const char *data; | ||
| 83 | int index; | ||
| 84 | strbuf_t *tmp; /* Temporary storage for strings */ | ||
| 85 | json_config_t *cfg; | ||
| 86 | } json_parse_t; | ||
| 87 | |||
| 88 | typedef struct { | ||
| 89 | json_token_type_t type; | ||
| 90 | int index; | ||
| 91 | union { | ||
| 92 | char *string; | ||
| 93 | double number; | ||
| 94 | int boolean; | ||
| 95 | } value; | ||
| 96 | int length; /* FIXME: Merge into union? Won't save memory, but more logical */ | ||
| 97 | } json_token_t; | ||
| 98 | |||
| 99 | /* ===== CONFIGURATION ===== */ | ||
| 100 | |||
| 101 | static json_config_t *json_fetch_config(lua_State *l) | ||
| 102 | { | ||
| 103 | json_config_t *cfg; | ||
| 104 | |||
| 105 | lua_getfield(l, LUA_REGISTRYINDEX, CJSON_CONFIG_KEY); | ||
| 106 | cfg = lua_touserdata(l, -1); | ||
| 107 | if (!cfg) | ||
| 108 | luaL_error(l, "BUG: Unable to fetch cjson configuration"); | ||
| 109 | |||
| 110 | lua_pop(l, 1); | ||
| 111 | |||
| 112 | return cfg; | ||
| 113 | } | ||
| 114 | |||
| 115 | static int json_sparse_ratio(lua_State *l) | ||
| 116 | { | ||
| 117 | json_config_t *cfg; | ||
| 118 | int sparse_ratio; | ||
| 119 | int args; | ||
| 120 | |||
| 121 | args = lua_gettop(l); | ||
| 122 | luaL_argcheck(l, args <= 1, 2, "found too many arguments"); | ||
| 123 | |||
| 124 | cfg = json_fetch_config(l); | ||
| 125 | |||
| 126 | if (args == 1) { | ||
| 127 | sparse_ratio = luaL_checkinteger(l, 1); | ||
| 128 | luaL_argcheck(l, sparse_ratio >= 0, 1, | ||
| 129 | "expected zero or positive integer"); | ||
| 130 | cfg->sparse_ratio = sparse_ratio; | ||
| 131 | } | ||
| 132 | |||
| 133 | lua_pushinteger(l, cfg->sparse_ratio); | ||
| 134 | |||
| 135 | return 1; | ||
| 136 | } | ||
| 137 | |||
| 138 | static int json_max_depth(lua_State *l) | ||
| 139 | { | ||
| 140 | json_config_t *cfg; | ||
| 141 | int max_depth; | ||
| 142 | int args; | ||
| 143 | |||
| 144 | args = lua_gettop(l); | ||
| 145 | luaL_argcheck(l, args <= 1, 2, "found too many arguments"); | ||
| 146 | |||
| 147 | cfg = json_fetch_config(l); | ||
| 148 | |||
| 149 | if (args == 1) { | ||
| 150 | max_depth = luaL_checkinteger(l, 1); | ||
| 151 | luaL_argcheck(l, max_depth > 0, 1, "expected positive integer"); | ||
| 152 | cfg->max_depth = max_depth; | ||
| 153 | } | ||
| 154 | |||
| 155 | lua_pushinteger(l, cfg->max_depth); | ||
| 156 | |||
| 157 | return 1; | ||
| 158 | } | ||
| 159 | |||
| 160 | static void json_create_config(lua_State *l) | ||
| 161 | { | ||
| 162 | json_config_t *cfg; | ||
| 163 | int i; | ||
| 164 | |||
| 165 | cfg = lua_newuserdata(l, sizeof(*cfg)); | ||
| 166 | |||
| 167 | /* Tag all characters as an error */ | ||
| 168 | for (i = 0; i < 256; i++) | ||
| 169 | cfg->ch2token[i] = T_ERROR; | ||
| 170 | |||
| 171 | /* Set tokens that require no further processing */ | ||
| 172 | cfg->ch2token['{'] = T_OBJ_BEGIN; | ||
| 173 | cfg->ch2token['}'] = T_OBJ_END; | ||
| 174 | cfg->ch2token['['] = T_ARR_BEGIN; | ||
| 175 | cfg->ch2token[']'] = T_ARR_END; | ||
| 176 | cfg->ch2token[','] = T_COMMA; | ||
| 177 | cfg->ch2token[':'] = T_COLON; | ||
| 178 | cfg->ch2token['\0'] = T_END; | ||
| 179 | cfg->ch2token[' '] = T_WHITESPACE; | ||
| 180 | cfg->ch2token['\t'] = T_WHITESPACE; | ||
| 181 | cfg->ch2token['\n'] = T_WHITESPACE; | ||
| 182 | cfg->ch2token['\r'] = T_WHITESPACE; | ||
| 183 | |||
| 184 | /* Update characters that require further processing */ | ||
| 185 | cfg->ch2token['n'] = T_UNKNOWN; | ||
| 186 | cfg->ch2token['t'] = T_UNKNOWN; | ||
| 187 | cfg->ch2token['f'] = T_UNKNOWN; | ||
| 188 | cfg->ch2token['"'] = T_UNKNOWN; | ||
| 189 | cfg->ch2token['-'] = T_UNKNOWN; | ||
| 190 | for (i = 0; i < 10; i++) | ||
| 191 | cfg->ch2token['0' + i] = T_UNKNOWN; | ||
| 192 | |||
| 193 | for (i = 0; i < 256; i++) | ||
| 194 | cfg->ch2escape[i] = 0; /* String error */ | ||
| 195 | |||
| 196 | cfg->ch2escape['"'] = '"'; | ||
| 197 | cfg->ch2escape['\\'] = '\\'; | ||
| 198 | cfg->ch2escape['/'] = '/'; | ||
| 199 | cfg->ch2escape['b'] = '\b'; | ||
| 200 | cfg->ch2escape['t'] = '\t'; | ||
| 201 | cfg->ch2escape['n'] = '\n'; | ||
| 202 | cfg->ch2escape['f'] = '\f'; | ||
| 203 | cfg->ch2escape['r'] = '\r'; | ||
| 204 | cfg->ch2escape['u'] = 'u'; /* This needs to be parsed as unicode */ | ||
| 205 | |||
| 206 | cfg->sparse_ratio = DEFAULT_SPARSE_RATIO; | ||
| 207 | cfg->max_depth = DEFAULT_MAX_DEPTH; | ||
| 208 | } | ||
| 42 | 209 | ||
| 43 | /* ===== ENCODING ===== */ | 210 | /* ===== ENCODING ===== */ |
| 44 | 211 | ||
| 45 | static void json_encode_exception(lua_State *l, strbuf_t *json, | 212 | static void json_encode_type_exception(lua_State *l, strbuf_t *json, |
| 46 | char *location, int lindex) | 213 | char *location, int lindex) |
| 47 | |||
| 48 | { | 214 | { |
| 49 | strbuf_free(json); | 215 | strbuf_free(json); |
| 50 | 216 | ||
| @@ -113,7 +279,7 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex) | |||
| 113 | * -1 object (not a pure array) | 279 | * -1 object (not a pure array) |
| 114 | * >=0 elements in array | 280 | * >=0 elements in array |
| 115 | */ | 281 | */ |
| 116 | static int lua_array_length(lua_State *l) | 282 | static int lua_array_length(lua_State *l, int sparse_ratio) |
| 117 | { | 283 | { |
| 118 | double k; | 284 | double k; |
| 119 | int max; | 285 | int max; |
| @@ -143,25 +309,38 @@ static int lua_array_length(lua_State *l) | |||
| 143 | return -1; | 309 | return -1; |
| 144 | } | 310 | } |
| 145 | 311 | ||
| 146 | #ifdef VERY_SPARSE_ARRAY_RATIO | 312 | /* Encode very sparse arrays as objects (if enabled) */ |
| 147 | /* Encode very sparse arrays as objects */ | 313 | if (sparse_ratio > 0 && max > items * sparse_ratio) |
| 148 | if (max > items * VERY_SPARSE_ARRAY_RATIO) | ||
| 149 | return -1; | 314 | return -1; |
| 150 | #endif | ||
| 151 | 315 | ||
| 152 | return max; | 316 | return max; |
| 153 | } | 317 | } |
| 154 | 318 | ||
| 155 | static void json_append_data(lua_State *l, strbuf_t *json); | 319 | static void json_encode_descend(lua_State *l, json_config_t *cfg, |
| 320 | strbuf_t *json) | ||
| 321 | { | ||
| 322 | cfg->current_depth++; | ||
| 323 | |||
| 324 | if (cfg->current_depth > cfg->max_depth) { | ||
| 325 | strbuf_free(json); | ||
| 326 | luaL_error(l, "Cannot serialise, excessive nesting (%d)", | ||
| 327 | cfg->current_depth); | ||
| 328 | } | ||
| 329 | } | ||
| 330 | |||
| 331 | static void json_append_data(lua_State *l, json_config_t *cfg, strbuf_t *json); | ||
| 156 | 332 | ||
| 157 | /* json_append_array args: | 333 | /* json_append_array args: |
| 158 | * - lua_State | 334 | * - lua_State |
| 159 | * - JSON strbuf | 335 | * - JSON strbuf |
| 160 | * - Size of passwd Lua array (top of stack) */ | 336 | * - Size of passwd Lua array (top of stack) */ |
| 161 | static void json_append_array(lua_State *l, strbuf_t *json, int array_length) | 337 | static void json_append_array(lua_State *l, json_config_t *cfg, strbuf_t *json, |
| 338 | int array_length) | ||
| 162 | { | 339 | { |
| 163 | int comma, i; | 340 | int comma, i; |
| 164 | 341 | ||
| 342 | json_encode_descend(l, cfg, json); | ||
| 343 | |||
| 165 | strbuf_append_string(json, "[ "); | 344 | strbuf_append_string(json, "[ "); |
| 166 | 345 | ||
| 167 | comma = 0; | 346 | comma = 0; |
| @@ -172,17 +351,22 @@ static void json_append_array(lua_State *l, strbuf_t *json, int array_length) | |||
| 172 | comma = 1; | 351 | comma = 1; |
| 173 | 352 | ||
| 174 | lua_rawgeti(l, -1, i); | 353 | lua_rawgeti(l, -1, i); |
| 175 | json_append_data(l, json); | 354 | json_append_data(l, cfg, json); |
| 176 | lua_pop(l, 1); | 355 | lua_pop(l, 1); |
| 177 | } | 356 | } |
| 178 | 357 | ||
| 179 | strbuf_append_string(json, " ]"); | 358 | strbuf_append_string(json, " ]"); |
| 359 | |||
| 360 | cfg->current_depth--; | ||
| 180 | } | 361 | } |
| 181 | 362 | ||
| 182 | static void json_append_object(lua_State *l, strbuf_t *json) | 363 | static void json_append_object(lua_State *l, json_config_t *cfg, |
| 364 | strbuf_t *json) | ||
| 183 | { | 365 | { |
| 184 | int comma, keytype; | 366 | int comma, keytype; |
| 185 | 367 | ||
| 368 | json_encode_descend(l, cfg, json); | ||
| 369 | |||
| 186 | /* Object */ | 370 | /* Object */ |
| 187 | strbuf_append_string(json, "{ "); | 371 | strbuf_append_string(json, "{ "); |
| 188 | 372 | ||
| @@ -204,21 +388,23 @@ static void json_append_object(lua_State *l, strbuf_t *json) | |||
| 204 | json_append_string(l, json, -2); | 388 | json_append_string(l, json, -2); |
| 205 | strbuf_append_string(json, ": "); | 389 | strbuf_append_string(json, ": "); |
| 206 | } else { | 390 | } else { |
| 207 | json_encode_exception(l, json, "table key", -2); | 391 | json_encode_type_exception(l, json, "table key", -2); |
| 208 | /* never returns */ | 392 | /* never returns */ |
| 209 | } | 393 | } |
| 210 | 394 | ||
| 211 | /* table, key, value */ | 395 | /* table, key, value */ |
| 212 | json_append_data(l, json); | 396 | json_append_data(l, cfg, json); |
| 213 | lua_pop(l, 1); | 397 | lua_pop(l, 1); |
| 214 | /* table, key */ | 398 | /* table, key */ |
| 215 | } | 399 | } |
| 216 | 400 | ||
| 217 | strbuf_append_string(json, " }"); | 401 | strbuf_append_string(json, " }"); |
| 402 | |||
| 403 | cfg->current_depth--; | ||
| 218 | } | 404 | } |
| 219 | 405 | ||
| 220 | /* Serialise Lua data into JSON string. */ | 406 | /* Serialise Lua data into JSON string. */ |
| 221 | static void json_append_data(lua_State *l, strbuf_t *json) | 407 | static void json_append_data(lua_State *l, json_config_t *cfg, strbuf_t *json) |
| 222 | { | 408 | { |
| 223 | int len; | 409 | int len; |
| 224 | 410 | ||
| @@ -236,11 +422,11 @@ static void json_append_data(lua_State *l, strbuf_t *json) | |||
| 236 | strbuf_append_string(json, "false"); | 422 | strbuf_append_string(json, "false"); |
| 237 | break; | 423 | break; |
| 238 | case LUA_TTABLE: | 424 | case LUA_TTABLE: |
| 239 | len = lua_array_length(l); | 425 | len = lua_array_length(l, cfg->sparse_ratio); |
| 240 | if (len > 0) | 426 | if (len > 0) |
| 241 | json_append_array(l, json, len); | 427 | json_append_array(l, cfg, json, len); |
| 242 | else | 428 | else |
| 243 | json_append_object(l, json); | 429 | json_append_object(l, cfg, json); |
| 244 | break; | 430 | break; |
| 245 | case LUA_TNIL: | 431 | case LUA_TNIL: |
| 246 | strbuf_append_string(json, "null"); | 432 | strbuf_append_string(json, "null"); |
| @@ -253,21 +439,25 @@ static void json_append_data(lua_State *l, strbuf_t *json) | |||
| 253 | default: | 439 | default: |
| 254 | /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, | 440 | /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, |
| 255 | * and LUA_TLIGHTUSERDATA) cannot be serialised */ | 441 | * and LUA_TLIGHTUSERDATA) cannot be serialised */ |
| 256 | json_encode_exception(l, json, "value", -1); | 442 | json_encode_type_exception(l, json, "value", -1); |
| 257 | /* never returns */ | 443 | /* never returns */ |
| 258 | } | 444 | } |
| 259 | } | 445 | } |
| 260 | 446 | ||
| 261 | static int json_encode(lua_State *l) | 447 | static int json_encode(lua_State *l) |
| 262 | { | 448 | { |
| 449 | json_config_t *cfg; | ||
| 263 | strbuf_t buf; | 450 | strbuf_t buf; |
| 264 | char *json; | 451 | char *json; |
| 265 | int len; | 452 | int len; |
| 266 | 453 | ||
| 267 | luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); | 454 | luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); |
| 268 | 455 | ||
| 456 | cfg = json_fetch_config(l); | ||
| 457 | cfg->current_depth = 0; | ||
| 458 | |||
| 269 | strbuf_init(&buf, 0); | 459 | strbuf_init(&buf, 0); |
| 270 | json_append_data(l, &buf); | 460 | json_append_data(l, cfg, &buf); |
| 271 | json = strbuf_free_to_string(&buf, &len); | 461 | json = strbuf_free_to_string(&buf, &len); |
| 272 | 462 | ||
| 273 | lua_pushlstring(l, json, len); | 463 | lua_pushlstring(l, json, len); |
| @@ -278,107 +468,8 @@ static int json_encode(lua_State *l) | |||
| 278 | 468 | ||
| 279 | /* ===== DECODING ===== */ | 469 | /* ===== DECODING ===== */ |
| 280 | 470 | ||
| 281 | typedef struct { | ||
| 282 | const char *data; | ||
| 283 | int index; | ||
| 284 | strbuf_t *tmp; /* Temporary storage for strings */ | ||
| 285 | } json_parse_t; | ||
| 286 | |||
| 287 | typedef enum { | ||
| 288 | T_OBJ_BEGIN, | ||
| 289 | T_OBJ_END, | ||
| 290 | T_ARR_BEGIN, | ||
| 291 | T_ARR_END, | ||
| 292 | T_STRING, | ||
| 293 | T_NUMBER, | ||
| 294 | T_BOOLEAN, | ||
| 295 | T_NULL, | ||
| 296 | T_COLON, | ||
| 297 | T_COMMA, | ||
| 298 | T_END, | ||
| 299 | T_WHITESPACE, | ||
| 300 | T_ERROR, | ||
| 301 | T_UNKNOWN | ||
| 302 | } json_token_type_t; | ||
| 303 | |||
| 304 | static const char *json_token_type_name[] = { | ||
| 305 | "T_OBJ_BEGIN", | ||
| 306 | "T_OBJ_END", | ||
| 307 | "T_ARR_BEGIN", | ||
| 308 | "T_ARR_END", | ||
| 309 | "T_STRING", | ||
| 310 | "T_NUMBER", | ||
| 311 | "T_BOOLEAN", | ||
| 312 | "T_NULL", | ||
| 313 | "T_COLON", | ||
| 314 | "T_COMMA", | ||
| 315 | "T_END", | ||
| 316 | "T_WHITESPACE", | ||
| 317 | "T_ERROR", | ||
| 318 | "T_UNKNOWN", | ||
| 319 | NULL | ||
| 320 | }; | ||
| 321 | |||
| 322 | typedef struct { | ||
| 323 | json_token_type_t type; | ||
| 324 | int index; | ||
| 325 | union { | ||
| 326 | char *string; | ||
| 327 | double number; | ||
| 328 | int boolean; | ||
| 329 | } value; | ||
| 330 | int length; /* FIXME: Merge into union? Won't save memory, but more logical */ | ||
| 331 | } json_token_t; | ||
| 332 | |||
| 333 | static void json_process_value(lua_State *l, json_parse_t *json, json_token_t *token); | 471 | static void json_process_value(lua_State *l, json_parse_t *json, json_token_t *token); |
| 334 | 472 | ||
| 335 | static json_token_type_t json_ch2token[256]; | ||
| 336 | static char json_ch2escape[256]; | ||
| 337 | |||
| 338 | static void json_global_init() | ||
| 339 | { | ||
| 340 | int i; | ||
| 341 | |||
| 342 | /* Tag all characters as an error */ | ||
| 343 | for (i = 0; i < 256; i++) | ||
| 344 | json_ch2token[i] = T_ERROR; | ||
| 345 | |||
| 346 | /* Set tokens that require no further processing */ | ||
| 347 | json_ch2token['{'] = T_OBJ_BEGIN; | ||
| 348 | json_ch2token['}'] = T_OBJ_END; | ||
| 349 | json_ch2token['['] = T_ARR_BEGIN; | ||
| 350 | json_ch2token[']'] = T_ARR_END; | ||
| 351 | json_ch2token[','] = T_COMMA; | ||
| 352 | json_ch2token[':'] = T_COLON; | ||
| 353 | json_ch2token['\0'] = T_END; | ||
| 354 | json_ch2token[' '] = T_WHITESPACE; | ||
| 355 | json_ch2token['\t'] = T_WHITESPACE; | ||
| 356 | json_ch2token['\n'] = T_WHITESPACE; | ||
| 357 | json_ch2token['\r'] = T_WHITESPACE; | ||
| 358 | |||
| 359 | /* Update characters that require further processing */ | ||
| 360 | json_ch2token['n'] = T_UNKNOWN; | ||
| 361 | json_ch2token['t'] = T_UNKNOWN; | ||
| 362 | json_ch2token['f'] = T_UNKNOWN; | ||
| 363 | json_ch2token['"'] = T_UNKNOWN; | ||
| 364 | json_ch2token['-'] = T_UNKNOWN; | ||
| 365 | for (i = 0; i < 10; i++) | ||
| 366 | json_ch2token['0' + i] = T_UNKNOWN; | ||
| 367 | |||
| 368 | for (i = 0; i < 256; i++) | ||
| 369 | json_ch2escape[i] = 0; /* String error */ | ||
| 370 | |||
| 371 | json_ch2escape['"'] = '"'; | ||
| 372 | json_ch2escape['\\'] = '\\'; | ||
| 373 | json_ch2escape['/'] = '/'; | ||
| 374 | json_ch2escape['b'] = '\b'; | ||
| 375 | json_ch2escape['t'] = '\t'; | ||
| 376 | json_ch2escape['n'] = '\n'; | ||
| 377 | json_ch2escape['f'] = '\f'; | ||
| 378 | json_ch2escape['r'] = '\r'; | ||
| 379 | json_ch2escape['u'] = 'u'; /* This needs to be parsed as unicode */ | ||
| 380 | } | ||
| 381 | |||
| 382 | static inline int hexdigit2int(char hex) | 473 | static inline int hexdigit2int(char hex) |
| 383 | { | 474 | { |
| 384 | if ('0' <= hex && hex <= '9') | 475 | if ('0' <= hex && hex <= '9') |
| @@ -473,6 +564,7 @@ static int json_append_unicode_escape(json_parse_t *json) | |||
| 473 | 564 | ||
| 474 | static void json_next_string_token(json_parse_t *json, json_token_t *token) | 565 | static void json_next_string_token(json_parse_t *json, json_token_t *token) |
| 475 | { | 566 | { |
| 567 | char *ch2escape = json->cfg->ch2escape; | ||
| 476 | char ch; | 568 | char ch; |
| 477 | 569 | ||
| 478 | /* Caller must ensure a string is next */ | 570 | /* Caller must ensure a string is next */ |
| @@ -498,7 +590,7 @@ static void json_next_string_token(json_parse_t *json, json_token_t *token) | |||
| 498 | ch = json->data[json->index]; | 590 | ch = json->data[json->index]; |
| 499 | 591 | ||
| 500 | /* Translate escape code and append to tmp string */ | 592 | /* Translate escape code and append to tmp string */ |
| 501 | ch = json_ch2escape[(unsigned char)ch]; | 593 | ch = ch2escape[(unsigned char)ch]; |
| 502 | if (ch == 'u') { | 594 | if (ch == 'u') { |
| 503 | if (json_append_unicode_escape(json) < 0) | 595 | if (json_append_unicode_escape(json) < 0) |
| 504 | continue; | 596 | continue; |
| @@ -561,12 +653,13 @@ static void json_next_number_token(json_parse_t *json, json_token_t *token) | |||
| 561 | */ | 653 | */ |
| 562 | static void json_next_token(json_parse_t *json, json_token_t *token) | 654 | static void json_next_token(json_parse_t *json, json_token_t *token) |
| 563 | { | 655 | { |
| 656 | json_token_type_t *ch2token = json->cfg->ch2token; | ||
| 564 | int ch; | 657 | int ch; |
| 565 | 658 | ||
| 566 | /* Eat whitespace. FIXME: UGLY */ | 659 | /* Eat whitespace. FIXME: UGLY */ |
| 567 | token->type = json_ch2token[(unsigned char)json->data[json->index]]; | 660 | token->type = ch2token[(unsigned char)json->data[json->index]]; |
| 568 | while (token->type == T_WHITESPACE) | 661 | while (token->type == T_WHITESPACE) |
| 569 | token->type = json_ch2token[(unsigned char)json->data[++json->index]]; | 662 | token->type = ch2token[(unsigned char)json->data[++json->index]]; |
| 570 | 663 | ||
| 571 | token->index = json->index; | 664 | token->index = json->index; |
| 572 | 665 | ||
| @@ -735,6 +828,7 @@ static void lua_json_decode(lua_State *l, const char *json_text) | |||
| 735 | json_parse_t json; | 828 | json_parse_t json; |
| 736 | json_token_t token; | 829 | json_token_t token; |
| 737 | 830 | ||
| 831 | json.cfg = json_fetch_config(l); | ||
| 738 | json.data = json_text; | 832 | json.data = json_text; |
| 739 | json.index = 0; | 833 | json.index = 0; |
| 740 | json.tmp = strbuf_new(0); | 834 | json.tmp = strbuf_new(0); |
| @@ -765,26 +859,25 @@ static int json_decode(lua_State *l) | |||
| 765 | 859 | ||
| 766 | /* ===== INITIALISATION ===== */ | 860 | /* ===== INITIALISATION ===== */ |
| 767 | 861 | ||
| 768 | /* FIXME: Rewrite to keep lookup tables within Lua (userdata?) | ||
| 769 | * Remove pthread dependency */ | ||
| 770 | static pthread_once_t json_global_init_once = PTHREAD_ONCE_INIT; | ||
| 771 | |||
| 772 | int luaopen_cjson(lua_State *l) | 862 | int luaopen_cjson(lua_State *l) |
| 773 | { | 863 | { |
| 774 | luaL_Reg reg[] = { | 864 | luaL_Reg reg[] = { |
| 775 | { "encode", json_encode }, | 865 | { "encode", json_encode }, |
| 776 | { "decode", json_decode }, | 866 | { "decode", json_decode }, |
| 867 | { "sparse_ratio", json_sparse_ratio }, | ||
| 868 | { "max_depth", json_max_depth }, | ||
| 777 | { NULL, NULL } | 869 | { NULL, NULL } |
| 778 | }; | 870 | }; |
| 779 | 871 | ||
| 872 | json_create_config(l); | ||
| 873 | lua_setfield(l, LUA_REGISTRYINDEX, CJSON_CONFIG_KEY); | ||
| 874 | |||
| 780 | luaL_register(l, "cjson", reg); | 875 | luaL_register(l, "cjson", reg); |
| 781 | 876 | ||
| 782 | /* Set cjson.null */ | 877 | /* Set cjson.null */ |
| 783 | lua_pushlightuserdata(l, NULL); | 878 | lua_pushlightuserdata(l, NULL); |
| 784 | lua_setfield(l, -2, "null"); | 879 | lua_setfield(l, -2, "null"); |
| 785 | 880 | ||
| 786 | pthread_once(&json_global_init_once, json_global_init); | ||
| 787 | |||
| 788 | /* Return cjson table */ | 881 | /* Return cjson table */ |
| 789 | return 1; | 882 | return 1; |
| 790 | } | 883 | } |
