diff options
author | Mark Pulford <mark@kyne.com.au> | 2011-05-03 00:58:57 +0930 |
---|---|---|
committer | Mark Pulford <mark@kyne.com.au> | 2011-05-03 00:58:57 +0930 |
commit | ec18dfc358cc4391eec3a37bdb81fe8d5a8b3d69 (patch) | |
tree | 455261ec3b9bbebab54d2c6a27b40ea544c92389 /lua_cjson.c | |
parent | a9bb5006d228539a1ec5028df7f660f862b0f2cc (diff) | |
download | lua-cjson-ec18dfc358cc4391eec3a37bdb81fe8d5a8b3d69.tar.gz lua-cjson-ec18dfc358cc4391eec3a37bdb81fe8d5a8b3d69.tar.bz2 lua-cjson-ec18dfc358cc4391eec3a37bdb81fe8d5a8b3d69.zip |
Escape all unprintable ASCII when encoding
Replace json_escape_char() with a static char2escape[] lookup table.
Escape all unprintable ASCII (0-31, 127) and JSON special characters
(double quote, backslash).
Dynamic creation of the char2escape table has been left commented out
due to an apparent performance hit. The performance loss may be due to
memory/page alignment (unknown).
Rename parsing lookup table from ch2escape to escape2char for consistency.
Diffstat (limited to 'lua_cjson.c')
-rw-r--r-- | lua_cjson.c | 141 |
1 files changed, 94 insertions, 47 deletions
diff --git a/lua_cjson.c b/lua_cjson.c index cab1922..df3b71c 100644 --- a/lua_cjson.c +++ b/lua_cjson.c | |||
@@ -85,7 +85,11 @@ static const char *json_token_type_name[] = { | |||
85 | 85 | ||
86 | typedef struct { | 86 | typedef struct { |
87 | json_token_type_t ch2token[256]; | 87 | json_token_type_t ch2token[256]; |
88 | char ch2escape[256]; | 88 | char escape2char[256]; /* Decoding */ |
89 | #if 0 | ||
90 | char escapes[35][8]; /* Pre-generated escape string buffer */ | ||
91 | char *char2escape[256]; /* Encoding */ | ||
92 | #endif | ||
89 | strbuf_t encode_buf; | 93 | strbuf_t encode_buf; |
90 | int sparse_ratio; | 94 | int sparse_ratio; |
91 | int max_depth; | 95 | int max_depth; |
@@ -111,10 +115,49 @@ typedef struct { | |||
111 | int string_len; | 115 | int string_len; |
112 | } json_token_t; | 116 | } json_token_t; |
113 | 117 | ||
114 | /* ===== CONFIGURATION ===== */ | 118 | static const char *char2escape[256] = { |
119 | "\\u0000", "\\u0001", "\\u0002", "\\u0003", | ||
120 | "\\u0004", "\\u0005", "\\u0006", "\\u0007", | ||
121 | "\\b", "\\t", "\\n", "\\u000b", | ||
122 | "\\f", "\\r", "\\u000e", "\\u000f", | ||
123 | "\\u0010", "\\u0011", "\\u0012", "\\u0013", | ||
124 | "\\u0014", "\\u0015", "\\u0016", "\\u0017", | ||
125 | "\\u0018", "\\u0019", "\\u001a", "\\u001b", | ||
126 | "\\u001c", "\\u001d", "\\u001e", "\\u001f", | ||
127 | NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL, | ||
128 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
129 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
130 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
131 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
132 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
133 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
134 | NULL, NULL, NULL, NULL, "\\\\", NULL, NULL, NULL, | ||
135 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
136 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
137 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
138 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\u007f", | ||
139 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
140 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
141 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
142 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
143 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
144 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
145 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
146 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
147 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
148 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
149 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
150 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
151 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
152 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
153 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
154 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, | ||
155 | }; | ||
115 | 156 | ||
116 | static int json_config_key; | 157 | static int json_config_key; |
117 | 158 | ||
159 | /* ===== CONFIGURATION ===== */ | ||
160 | |||
118 | static json_config_t *json_fetch_config(lua_State *l) | 161 | static json_config_t *json_fetch_config(lua_State *l) |
119 | { | 162 | { |
120 | json_config_t *cfg; | 163 | json_config_t *cfg; |
@@ -201,6 +244,12 @@ static void json_create_config(lua_State *l) | |||
201 | 244 | ||
202 | cfg = lua_newuserdata(l, sizeof(*cfg)); | 245 | cfg = lua_newuserdata(l, sizeof(*cfg)); |
203 | 246 | ||
247 | cfg->sparse_ratio = DEFAULT_SPARSE_RATIO; | ||
248 | cfg->max_depth = DEFAULT_MAX_DEPTH; | ||
249 | cfg->strict_numbers = 1; | ||
250 | |||
251 | /* Decoding init */ | ||
252 | |||
204 | /* Tag all characters as an error */ | 253 | /* Tag all characters as an error */ |
205 | for (i = 0; i < 256; i++) | 254 | for (i = 0; i < 256; i++) |
206 | cfg->ch2token[i] = T_ERROR; | 255 | cfg->ch2token[i] = T_ERROR; |
@@ -233,22 +282,45 @@ static void json_create_config(lua_State *l) | |||
233 | 282 | ||
234 | /* Lookup table for parsing escape characters */ | 283 | /* Lookup table for parsing escape characters */ |
235 | for (i = 0; i < 256; i++) | 284 | for (i = 0; i < 256; i++) |
236 | cfg->ch2escape[i] = 0; /* String error */ | 285 | cfg->escape2char[i] = 0; /* String error */ |
237 | cfg->ch2escape['"'] = '"'; | 286 | cfg->escape2char['"'] = '"'; |
238 | cfg->ch2escape['\\'] = '\\'; | 287 | cfg->escape2char['\\'] = '\\'; |
239 | cfg->ch2escape['/'] = '/'; | 288 | cfg->escape2char['/'] = '/'; |
240 | cfg->ch2escape['b'] = '\b'; | 289 | cfg->escape2char['b'] = '\b'; |
241 | cfg->ch2escape['t'] = '\t'; | 290 | cfg->escape2char['t'] = '\t'; |
242 | cfg->ch2escape['n'] = '\n'; | 291 | cfg->escape2char['n'] = '\n'; |
243 | cfg->ch2escape['f'] = '\f'; | 292 | cfg->escape2char['f'] = '\f'; |
244 | cfg->ch2escape['r'] = '\r'; | 293 | cfg->escape2char['r'] = '\r'; |
245 | cfg->ch2escape['u'] = 'u'; /* Unicode parsing required */ | 294 | cfg->escape2char['u'] = 'u'; /* Unicode parsing required */ |
246 | 295 | ||
247 | cfg->sparse_ratio = DEFAULT_SPARSE_RATIO; | 296 | /* Encoding init */ |
248 | cfg->max_depth = DEFAULT_MAX_DEPTH; | ||
249 | cfg->strict_numbers = 1; | ||
250 | 297 | ||
251 | strbuf_init(&cfg->encode_buf, 0); | 298 | strbuf_init(&cfg->encode_buf, 0); |
299 | |||
300 | #if 0 | ||
301 | /* Initialise separate storage for pre-generated escape codes. | ||
302 | * Escapes 0-31 map directly, 34, 92, 127 follow afterwards to | ||
303 | * save memory. */ | ||
304 | for (i = 0 ; i < 32; i++) | ||
305 | sprintf(cfg->escapes[i], "\\u%04x", i); | ||
306 | strcpy(cfg->escapes[8], "\b"); /* Override simpler escapes */ | ||
307 | strcpy(cfg->escapes[9], "\t"); | ||
308 | strcpy(cfg->escapes[10], "\n"); | ||
309 | strcpy(cfg->escapes[12], "\f"); | ||
310 | strcpy(cfg->escapes[13], "\r"); | ||
311 | strcpy(cfg->escapes[32], "\\\""); /* chr(34) */ | ||
312 | strcpy(cfg->escapes[33], "\\\\"); /* chr(92) */ | ||
313 | sprintf(cfg->escapes[34], "\\u%04x", 127); /* char(127) */ | ||
314 | |||
315 | /* Initialise encoding escape lookup table */ | ||
316 | for (i = 0; i < 32; i++) | ||
317 | cfg->char2escape[i] = cfg->escapes[i]; | ||
318 | for (i = 32; i < 256; i++) | ||
319 | cfg->char2escape[i] = NULL; | ||
320 | cfg->char2escape[34] = cfg->escapes[32]; | ||
321 | cfg->char2escape[92] = cfg->escapes[33]; | ||
322 | cfg->char2escape[127] = cfg->escapes[34]; | ||
323 | #endif | ||
252 | } | 324 | } |
253 | 325 | ||
254 | /* ===== ENCODING ===== */ | 326 | /* ===== ENCODING ===== */ |
@@ -259,31 +331,6 @@ static void json_encode_exception(lua_State *l, int lindex, const char *reason) | |||
259 | lua_typename(l, lua_type(l, lindex)), reason); | 331 | lua_typename(l, lua_type(l, lindex)), reason); |
260 | } | 332 | } |
261 | 333 | ||
262 | /* JSON escape a character if required, or return NULL */ | ||
263 | static inline char *json_escape_char(int c) | ||
264 | { | ||
265 | switch(c) { | ||
266 | case 0: | ||
267 | return "\\u0000"; | ||
268 | case '\\': | ||
269 | return "\\\\"; | ||
270 | case '"': | ||
271 | return "\\\""; | ||
272 | case '\b': | ||
273 | return "\\b"; | ||
274 | case '\t': | ||
275 | return "\\t"; | ||
276 | case '\n': | ||
277 | return "\\n"; | ||
278 | case '\f': | ||
279 | return "\\f"; | ||
280 | case '\r': | ||
281 | return "\\r"; | ||
282 | } | ||
283 | |||
284 | return NULL; | ||
285 | } | ||
286 | |||
287 | /* json_append_string args: | 334 | /* json_append_string args: |
288 | * - lua_State | 335 | * - lua_State |
289 | * - JSON strbuf | 336 | * - JSON strbuf |
@@ -292,7 +339,7 @@ static inline char *json_escape_char(int c) | |||
292 | * Returns nothing. Doesn't remove string from Lua stack */ | 339 | * Returns nothing. Doesn't remove string from Lua stack */ |
293 | static void json_append_string(lua_State *l, strbuf_t *json, int lindex) | 340 | static void json_append_string(lua_State *l, strbuf_t *json, int lindex) |
294 | { | 341 | { |
295 | const char *p; | 342 | const char *escstr; |
296 | int i; | 343 | int i; |
297 | const char *str; | 344 | const char *str; |
298 | size_t len; | 345 | size_t len; |
@@ -307,9 +354,9 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex) | |||
307 | 354 | ||
308 | strbuf_append_char_unsafe(json, '\"'); | 355 | strbuf_append_char_unsafe(json, '\"'); |
309 | for (i = 0; i < len; i++) { | 356 | for (i = 0; i < len; i++) { |
310 | p = json_escape_char(str[i]); | 357 | escstr = char2escape[(unsigned char)str[i]]; |
311 | if (p) | 358 | if (escstr) |
312 | strbuf_append_string(json, p); | 359 | strbuf_append_string(json, escstr); |
313 | else | 360 | else |
314 | strbuf_append_char_unsafe(json, str[i]); | 361 | strbuf_append_char_unsafe(json, str[i]); |
315 | } | 362 | } |
@@ -625,7 +672,7 @@ static void json_set_token_error(json_token_t *token, json_parse_t *json, | |||
625 | 672 | ||
626 | static void json_next_string_token(json_parse_t *json, json_token_t *token) | 673 | static void json_next_string_token(json_parse_t *json, json_token_t *token) |
627 | { | 674 | { |
628 | char *ch2escape = json->cfg->ch2escape; | 675 | char *escape2char = json->cfg->escape2char; |
629 | char ch; | 676 | char ch; |
630 | 677 | ||
631 | /* Caller must ensure a string is next */ | 678 | /* Caller must ensure a string is next */ |
@@ -650,7 +697,7 @@ static void json_next_string_token(json_parse_t *json, json_token_t *token) | |||
650 | ch = json->data[json->index + 1]; | 697 | ch = json->data[json->index + 1]; |
651 | 698 | ||
652 | /* Translate escape code and append to tmp string */ | 699 | /* Translate escape code and append to tmp string */ |
653 | ch = ch2escape[(unsigned char)ch]; | 700 | ch = escape2char[(unsigned char)ch]; |
654 | if (ch == 'u') { | 701 | if (ch == 'u') { |
655 | if (json_append_unicode_escape(json) == 0) | 702 | if (json_append_unicode_escape(json) == 0) |
656 | continue; | 703 | continue; |