diff options
author | Mark Pulford <mark@kyne.com.au> | 2011-05-01 04:16:24 +0930 |
---|---|---|
committer | Mark Pulford <mark@kyne.com.au> | 2011-05-01 04:16:24 +0930 |
commit | 2fc7477b155cdecfee3b0a47203c0706c27db73e (patch) | |
tree | 840705c2246f4f88fff11f23310648112cf9f77f /lua_cjson.c | |
parent | af1fe38223e23b2bb90f65bc6dd1b7e0dd5cb5cd (diff) | |
download | lua-cjson-2fc7477b155cdecfee3b0a47203c0706c27db73e.tar.gz lua-cjson-2fc7477b155cdecfee3b0a47203c0706c27db73e.tar.bz2 lua-cjson-2fc7477b155cdecfee3b0a47203c0706c27db73e.zip |
Move static configuration into runtime userdata
Allow maximum nesting depth and sparse array ratio to be configured at
runtime via the sparse_ratio() and max_depth() functions.
Throw exceptions when encoding excessively nested structures.
Diffstat (limited to 'lua_cjson.c')
-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 | } |