aboutsummaryrefslogtreecommitdiff
path: root/lua_cjson.c
diff options
context:
space:
mode:
authorMark Pulford <mark@kyne.com.au>2011-05-03 00:58:57 +0930
committerMark Pulford <mark@kyne.com.au>2011-05-03 00:58:57 +0930
commitec18dfc358cc4391eec3a37bdb81fe8d5a8b3d69 (patch)
tree455261ec3b9bbebab54d2c6a27b40ea544c92389 /lua_cjson.c
parenta9bb5006d228539a1ec5028df7f660f862b0f2cc (diff)
downloadlua-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.c141
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
86typedef struct { 86typedef 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 ===== */ 118static 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
116static int json_config_key; 157static int json_config_key;
117 158
159/* ===== CONFIGURATION ===== */
160
118static json_config_t *json_fetch_config(lua_State *l) 161static 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 */
263static 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 */
293static void json_append_string(lua_State *l, strbuf_t *json, int lindex) 340static 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
626static void json_next_string_token(json_parse_t *json, json_token_t *token) 673static 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;