aboutsummaryrefslogtreecommitdiff
path: root/src/3rdParty/colib/ljson.c
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-11-04 17:00:46 +0800
committerLi Jin <dragon-fly@qq.com>2025-11-04 17:00:46 +0800
commitccd9c7f216c341b50e0a0313ac2eef6a89cee5a4 (patch)
tree153ce8766144c7f4288772a1fe668590f60e42a5 /src/3rdParty/colib/ljson.c
parent03d4fad6ef79ce1788391648e535039a5f29aec3 (diff)
downloadyuescript-ccd9c7f216c341b50e0a0313ac2eef6a89cee5a4.tar.gz
yuescript-ccd9c7f216c341b50e0a0313ac2eef6a89cee5a4.tar.bz2
yuescript-ccd9c7f216c341b50e0a0313ac2eef6a89cee5a4.zip
Included a minimal json lib in yue compiler tool.
Diffstat (limited to 'src/3rdParty/colib/ljson.c')
-rwxr-xr-xsrc/3rdParty/colib/ljson.c900
1 files changed, 900 insertions, 0 deletions
diff --git a/src/3rdParty/colib/ljson.c b/src/3rdParty/colib/ljson.c
new file mode 100755
index 0000000..78f9070
--- /dev/null
+++ b/src/3rdParty/colib/ljson.c
@@ -0,0 +1,900 @@
1/**
2 * json解析器:只支持utf-8格式,Lua只支持64位的数字
3 */
4#define LUA_LIB
5#include <stdlib.h>
6#include <string.h>
7#include <stdint.h>
8#include <stdio.h>
9#include <ctype.h>
10#include <assert.h>
11#include <errno.h>
12#include <setjmp.h>
13#include <ctype.h>
14#include <limits.h>
15#include <float.h>
16#include <math.h>
17#include "lua.h"
18#include "lauxlib.h"
19
20// 内存分配函数,方便替换
21#define co_malloc malloc
22#define co_free free
23#define co_realloc realloc
24#define co_calloc calloc
25
26
27#if !defined(likely)
28#if defined(__GNUC__)
29#define likely(x) (__builtin_expect(((x) != 0), 1))
30#define unlikely(x) (__builtin_expect(((x) != 0), 0))
31#else
32#define likely(x) (x)
33#define unlikely(x) (x)
34#endif
35
36#endif
37
38//-----------------------------------------------------------------------------
39// membuffer
40
41#define STACK_BUFF_SIZE 512
42
43typedef struct membuffer {
44 char *b; // 内存buffer
45 size_t sz; // buffer已用长度
46 size_t cap; // buffer实际大小
47 char s[STACK_BUFF_SIZE];
48} membuffer_t;
49
50// 初始化buffer
51static inline void membuffer_init(membuffer_t *buff) {
52 buff->b = buff->s;
53 buff->cap = STACK_BUFF_SIZE;
54 buff->sz = 0;
55}
56
57static inline void membuffer_add_size(membuffer_t *buff, size_t sz) {
58 buff->sz += sz;
59}
60
61static inline void membuffer_reset(membuffer_t *buff) {
62 buff->sz = 0;
63}
64
65static inline void membuffer_free(membuffer_t *buff) {
66 if (buff->b && buff->b != buff->s) {
67 co_free(buff->b);
68 buff->b = NULL;
69 }
70}
71
72static inline void _membuffer_grow(membuffer_t *buff, size_t needsz) {
73 if (buff->cap < needsz) {
74 size_t newcap = buff->cap * 2;
75 if (newcap < needsz)
76 newcap = needsz;
77 if (buff->b == buff->s) {
78 buff->b = (char*)co_malloc(newcap);
79 memcpy(buff->b, buff->s, buff->sz);
80 } else {
81 buff->b = (char*)co_realloc(buff->b, newcap);
82 }
83 buff->cap = newcap;
84 }
85}
86
87// 确保缓存中还有sz的可用空间
88static inline void membuffer_ensure_space(membuffer_t *buff, size_t sz) {
89 if (buff->sz + sz > buff->cap) {
90 _membuffer_grow(buff, buff->sz+sz);
91 }
92}
93
94// 压入一个字符
95static inline void membuffer_putc(membuffer_t *buff, char c) {
96 membuffer_ensure_space(buff, 1);
97 buff->b[buff->sz++] = c;
98}
99
100// 写入一段内存
101static inline void membuffer_putb(membuffer_t *buff, const void *b, size_t sz) {
102 membuffer_ensure_space(buff, sz);
103 memcpy(buff->b + buff->sz, b, sz);
104 buff->sz += sz;
105}
106
107// 压入一个字符:不检查空间(不安全版本)
108static inline void membuffer_putc_unsafe(membuffer_t *buff, char c) {
109 buff->b[buff->sz++] = c;
110}
111
112// 写入一段内存:不检查空间(不安全版本)
113static inline void membuffer_putb_unsafe(membuffer_t *buff, const void *b, size_t sz) {
114 memcpy(buff->b + buff->sz, b, sz);
115 buff->sz += sz;
116}
117
118// 取当前的指针
119static inline char* membuffer_getp(membuffer_t *buff) {
120 return buff->b + buff->sz;
121}
122
123//-----------------------------------------------------------------------------
124// parser
125
126//-------------------------------------
127// 与Lua相关的代码
128
129static inline void l_add_object(lua_State *L) {
130 luaL_checkstack(L, 6, NULL);
131 lua_createtable(L, 0, 4);
132}
133static inline void l_begin_pair(lua_State *L, const char *k, size_t sz) {
134 lua_pushlstring(L, k, sz);
135}
136static inline void l_end_pair(lua_State *L) {
137 lua_rawset(L, -3);
138}
139static inline void l_add_array(lua_State *L) {
140 luaL_checkstack(L, 6, NULL);
141 lua_createtable(L, 4, 0);
142}
143static inline void l_add_index(lua_State *L, int i) {
144 lua_rawseti(L, -2, i+1);
145}
146static inline void l_add_string(lua_State *L, const char *s, size_t sz) {
147 lua_pushlstring(L, s, sz);
148}
149static inline void l_add_float(lua_State *L, double f) {
150 lua_pushnumber(L, (lua_Number)f);
151}
152static inline void l_add_integer(lua_State *L, int64_t i) {
153 lua_pushinteger(L, (lua_Integer)i);
154}
155static inline void l_add_boolean(lua_State *L, int b) {
156 lua_pushboolean(L, b);
157}
158static inline void l_add_null(lua_State *L) {
159 lua_pushlightuserdata(L, NULL);
160}
161static inline void l_error(lua_State *L, const char *msg) {
162 luaL_error(L, msg);
163}
164
165// 解析事件
166#define ON_ADD_OBJECT(ud) l_add_object((lua_State*)(ud))
167#define ON_BEGIN_PAIR(ud, k, sz) l_begin_pair((lua_State*)(ud), k, sz)
168#define ON_END_PAIR(ud) l_end_pair((lua_State*)(ud))
169#define ON_ADD_ARRAY(ud) l_add_array((lua_State*)(ud))
170#define ON_ADD_INDEX(ud, i) l_add_index((lua_State*)(ud), i)
171#define ON_ADD_STRING(ud, s, sz) l_add_string((lua_State*)(ud), s, sz)
172#define ON_ADD_FLOAT(ud, f) l_add_float((lua_State*)(ud), f)
173#define ON_ADD_INTEGER(ud, i) l_add_integer((lua_State*)(ud), i)
174#define ON_ADD_BOOLEAN(ud, b) l_add_boolean((lua_State*)(ud), b)
175#define ON_ADD_NULL(ud) l_add_null((lua_State*)(ud))
176#define ON_ERROR(ud, msg) l_error((lua_State*)(ud), msg)
177
178//-------------------------------------
179// 解析json,这部分代码与Lua无关,是通用的解析器;如果要移植这部分代码,需要把 //>>> 开头的注释去掉
180
181// 错误消息的大小
182#define ERRMSG_SIZE 256
183
184// json解析器
185typedef struct {
186 const char *str; // json字符串
187 const char *ptr; // json字符串解析指针
188 void *ud; // 解析事件的用户数据
189 membuffer_t buff; // 临时缓存
190 int curdepth; // 当前层次
191 int maxdepth; // 最大层次
192 int allowcomment; // 是否允许注释
193 char errmsg[ERRMSG_SIZE]; // 保存错误消息
194 //>>>jmp_buf jb; // 用于实现从解析中出错直接跳出
195} json_parser_t;
196
197static inline void parser_init(json_parser_t *parser, const char *str, size_t size, void *ud,
198 int maxdepth, int allowcomment) {
199 membuffer_init(&parser->buff);
200 membuffer_ensure_space(&parser->buff, size);
201 parser->str = str;
202 parser->ptr = str;
203 parser->ud = ud;
204 parser->maxdepth = maxdepth;
205 parser->curdepth = 0;
206 parser->allowcomment = allowcomment;
207}
208
209static inline void parser_free(json_parser_t *parser) {
210 membuffer_free(&parser->buff);
211}
212
213// 抛出错误
214static void parser_throw_error(json_parser_t *parser, const char *fmt, ...) {
215 membuffer_free(&parser->buff);
216 va_list arg;
217 va_start(arg, fmt);
218 vsnprintf(parser->errmsg, ERRMSG_SIZE, fmt, arg);
219 va_end(arg);
220 ON_ERROR(parser->ud, parser->errmsg);
221 // 直接跳出解析代码,由于Lua的lua_error也是用longjmp,所以下面的代码没有机会执行到。但其他语言就不一定。
222 //>>>longjmp(parser->jb, 1);
223}
224
225// 辅助宏
226#define peekchar(p) (*(p)->ptr)
227#define skipchar(p) (++(p)->ptr)
228#define get_and_next(p) (*(p)->ptr++)
229#define next_and_get(p) (*(++(p)->ptr))
230#define savechar(p, c) membuffer_putc_unsafe(&(p)->buff, (c))
231#define currpos(p) (size_t)((p)->ptr - (p)->str)
232
233// 取解析到的错误内容
234static const char* parser_error_content(json_parser_t *p) {
235 size_t n = currpos(p);
236 if (n > 50) n = 50; // 调整这个数获得更长的内容
237 membuffer_reset(&p->buff);
238 membuffer_putb(&p->buff, p->ptr - n, n);
239 membuffer_putc(&p->buff, '\0');
240 return p->buff.b;
241}
242
243// 增加深度
244static inline void parser_add_depth(json_parser_t *p) {
245 p->curdepth++;
246 if (p->curdepth >= p->maxdepth)
247 parser_throw_error(p, "Too many nested data, max depth is %d, at: %s[:%lu]", p->maxdepth,
248 parser_error_content(p), currpos(p));
249}
250
251static inline void parser_skip_whitespaces(json_parser_t *p) {
252 // colin: 要支持注释,请将下面注释去掉
253 // if (likely(!p->allowcomment)) {
254 char ch = peekchar(p);
255 while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
256 ch = next_and_get(p);
257 // } else {
258 // char ch = peekchar(p);
259 // for (;;) {
260 // while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
261 // ch = next_and_get(p);
262 // if (ch == '/') {
263 // ch = next_and_get(p);
264 // if (ch == '/') {
265 // ch = next_and_get(p);
266 // while (ch != '\n' && ch != '\r' && ch != '\0')
267 // ch = next_and_get(p);
268 // continue;
269 // } else {
270 // parser_throw_error(p, "Invalid comment, at: %s[:%lu]", parser_error_content(p), currpos(p));
271 // }
272 // }
273 // break;
274 // }
275 // }
276}
277
278static inline void parser_expect_char(json_parser_t *p, char c) {
279 if (likely(peekchar(p) == c))
280 skipchar(p);
281 else
282 parser_throw_error(p, "Expect '%c' at: %s[:%lu]", c, parser_error_content(p), currpos(p));
283}
284
285static inline void parser_process_false(json_parser_t *p) {
286 if (likely(p->ptr[0] == 'a' && p->ptr[1] == 'l' && p->ptr[2] == 's' && p->ptr[3] == 'e')) {
287 p->ptr += 4;
288 ON_ADD_BOOLEAN(p->ud, 0);
289 } else {
290 parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p));
291 }
292}
293
294static inline void parser_process_true(json_parser_t *p) {
295 if (likely(p->ptr[0] == 'r' && p->ptr[1] == 'u' && p->ptr[2] == 'e')) {
296 p->ptr += 3;
297 ON_ADD_BOOLEAN(p->ud, 1);
298 } else {
299 parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p));
300 }
301}
302
303static inline void parser_process_null(json_parser_t *p) {
304 if (likely(p->ptr[0] == 'u' && p->ptr[1] == 'l' && p->ptr[2] == 'l')) {
305 p->ptr += 3;
306 ON_ADD_NULL(p->ud);
307 } else {
308 parser_throw_error(p, "Invalid null, at: %s[:%lu]", parser_error_content(p), currpos(p));
309 }
310}
311
312static inline uint32_t parser_read_hex(json_parser_t *p) {
313 uint32_t cp = 0;
314 unsigned char ch;
315 int i = 4;
316 while (i--) {
317 ch = (unsigned char)get_and_next(p);
318 if ('0' <= ch && ch <= '9')
319 ch -= '0';
320 else if (ch >= 'a' && ch <= 'f')
321 ch = ch - 'a' + 10;
322 else if (ch >= 'A' && ch <= 'F')
323 ch = ch - 'A' + 10;
324 else {
325 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
326 return cp;
327 }
328 cp = (cp << 4) + ch;
329 }
330 return cp;
331}
332
333static inline void parser_process_utf8esc(json_parser_t *p) {
334 uint32_t cp = parser_read_hex(p);
335 // UTF-16 surrogate pairs, see https://unicodebook.readthedocs.io/unicode_encodings.html#utf-16-surrogate-pairs
336 if (cp >= 0xD800 && cp <= 0xDBFF) {
337 char p0 = p->ptr[0];
338 char p1 = p->ptr[1];
339 if (p0 != '\\' || p1 != 'u')
340 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
341 p->ptr += 2;
342 uint32_t cp2 = parser_read_hex(p);
343 if (cp2 < 0xDC00 || cp2 > 0xDFFF)
344 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
345 cp = 0x10000 + (((cp & 0x03FF) << 10) | (cp2 & 0x03FF));
346 }
347 if (cp < 0x80) {
348 membuffer_putc_unsafe(&p->buff, (char)cp);
349 } else if (cp < 0x800) {
350 membuffer_putc_unsafe(&p->buff, 0xC0 | (cp >> 6));
351 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
352 } else if (cp < 0x10000) {
353 membuffer_putc_unsafe(&p->buff, 0xE0 | (cp >> 12));
354 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F));
355 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
356 } else {
357 membuffer_putc_unsafe(&p->buff, 0xF0 | (cp >> 18));
358 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 12) & 0x3F));
359 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F));
360 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
361 }
362}
363
364static const char escape2char[256] = {
365 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0~19
366 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\"',0, 0, 0, 0, 0, // 20~39
367 0, 0, 0, 0, 0, 0, 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59
368 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79
369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\',0, 0, 0, 0, 0, '\b',0, // 80~99
370 0, 0, '\f',0, 0, 0, 0, 0, 0, 0, '\n',0, 0, 0, '\r',0, '\t',0, 0, 0, // 100~119
371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139
372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159
373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179
374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199
375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219
376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239
377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256
378};
379
380static inline void parser_process_string(json_parser_t *p) {
381 membuffer_reset(&p->buff);
382 char ch = get_and_next(p);
383 for (;;) {
384 if (ch == '\\') {
385 unsigned char nch = (unsigned char)peekchar(p);
386 if (likely(escape2char[nch])) {
387 savechar(p, escape2char[nch]);
388 skipchar(p);
389 } else if (nch == 'u') {
390 skipchar(p);
391 parser_process_utf8esc(p);
392 } else {
393 parser_throw_error(p, "Invalid escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
394 }
395 } else if (ch == '"') {
396 break;
397 } else if ((unsigned char)ch < 0x20) {
398 parser_throw_error(p, "Invalid string, at: %s[:%lu]", parser_error_content(p), currpos(p));
399 } else {
400 savechar(p, ch);
401 }
402 ch = get_and_next(p);
403 }
404}
405
406#define invalid_number(p) parser_throw_error(p, "Invalid value, at: %s[:%lu]", parser_error_content(p), currpos(p))
407#define MAXBY10 (int64_t)(922337203685477580)
408#define MAXLASTD (int)(7)
409static double powersOf10[] = {10., 100., 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256};
410static inline void parser_process_number(json_parser_t *p, char ch) {
411 double db; // 浮点数
412 int64_t in = 0; // 整型值
413 int isdouble = 0; // 是否是浮点数
414 int neg = 0; // 是否是负数
415 int exponent = 0; // 指数位数
416
417 if (ch == '-') { // 负值
418 neg = 1;
419 ch = get_and_next(p);
420 }
421 if (unlikely(ch == '0')) { // 0开头的后面只能是:.eE或\0
422 ch = peekchar(p);
423 } else if (likely(ch >= '1' && ch <= '9')) {
424 in = ch - '0';
425 ch = peekchar(p);
426 while (ch >= '0' && ch <= '9') {
427 if (unlikely(in >= MAXBY10 && (in > MAXBY10 || (ch - '0') > MAXLASTD + neg))) { // 更大的数字就用浮点数表示
428 isdouble = 1;
429 db = (double)in;
430 do {
431 db = db * 10.0 + (ch - '0');
432 ch = next_and_get(p);
433 } while (ch >= '0' && ch <= '9');
434 break;
435 }
436 in = in * 10 + (ch - '0');
437 ch = next_and_get(p);
438 }
439 } else {
440 invalid_number(p);
441 }
442
443 if (ch == '.') { // 小数点部分
444 if (likely(!isdouble)) {
445 isdouble = 1;
446 db = (double)in;
447 }
448 ch = next_and_get(p);
449 if (unlikely(!(ch >= '0' && ch <= '9')))
450 invalid_number(p); // .后面一定是数字
451 do {
452 db = db * 10. + (ch - '0');
453 exponent--;
454 ch = next_and_get(p);
455 } while (ch >= '0' && ch <= '9');
456 }
457
458 if (ch == 'e' || ch == 'E') { // 指数部分
459 if (!isdouble) { // 有e强制认为是浮点数
460 isdouble = 1;
461 db = (double)in;
462 }
463 ch = next_and_get(p);
464 int eneg = 0;
465 if (ch == '-') {
466 eneg = 1;
467 ch = next_and_get(p);
468 } else if (ch == '+') {
469 ch = next_and_get(p);
470 }
471 if (unlikely(!(ch >= '0' && ch <= '9')))
472 invalid_number(p); // 后面一定是数字
473 int exp = 0;
474 do {
475 exp = exp * 10. + (ch - '0');
476 ch = next_and_get(p);
477 } while (ch >= '0' && ch <= '9');
478 exponent += eneg ? (-exp) : (exp);
479 }
480
481 if (isdouble) {
482 int n = exponent < 0 ? -exponent : exponent;
483 if (unlikely(n>511))
484 n = 511; // inf
485 double p10 = 1.0;
486 double *d;
487 for (d = powersOf10; n != 0; n >>= 1, d += 1) {
488 if (n & 1) p10 *= *d;
489 }
490 if (exponent < 0)
491 db /= p10;
492 else
493 db *= p10;
494 if (neg) db = -db;
495 ON_ADD_FLOAT(p->ud, db);
496 } else {
497 if (neg) in = -in;
498 ON_ADD_INTEGER(p->ud, in);
499 }
500}
501
502static void parser_process_value(json_parser_t *p);
503
504static inline void parser_process_object(json_parser_t *p) {
505 parser_add_depth(p);
506 ON_ADD_OBJECT(p->ud);
507 parser_skip_whitespaces(p);
508 char ch = peekchar(p);
509 if (ch == '}') {
510 skipchar(p);
511 p->curdepth--;
512 return;
513 }
514 for (;;) {
515 parser_expect_char(p, '"');
516 parser_process_string(p); // key
517 ON_BEGIN_PAIR(p->ud, p->buff.b, p->buff.sz);
518
519 parser_skip_whitespaces(p);
520 parser_expect_char(p, ':');
521
522 parser_process_value(p); // value
523 ON_END_PAIR(p->ud);
524
525 parser_skip_whitespaces(p);
526 if (peekchar(p) == '}') {
527 skipchar(p);
528 p->curdepth--;
529 return;
530 }
531 else {
532 parser_expect_char(p, ',');
533 parser_skip_whitespaces(p);
534 }
535 }
536}
537
538static inline void parser_process_array(json_parser_t *p) {
539 parser_add_depth(p);
540 ON_ADD_ARRAY(p->ud);
541 parser_skip_whitespaces(p);
542 char ch = peekchar(p);
543 if (ch == ']') {
544 skipchar(p);
545 p->curdepth--;
546 return;
547 }
548 int i;
549 for (i = 0; ;++i) {
550 parser_process_value(p);
551 ON_ADD_INDEX(p->ud, i);
552
553 parser_skip_whitespaces(p);
554 if (peekchar(p) == ']') {
555 skipchar(p);
556 p->curdepth--;
557 return;
558 }
559 else {
560 parser_expect_char(p, ',');
561 }
562 }
563}
564
565static void parser_process_value(json_parser_t *p) {
566 parser_skip_whitespaces(p);
567 char ch = get_and_next(p);
568 switch (ch) {
569 case 'f':
570 parser_process_false(p);
571 break;
572 case 't':
573 parser_process_true(p);
574 break;
575 case 'n':
576 parser_process_null(p);
577 break;
578 case '"':
579 parser_process_string(p);
580 ON_ADD_STRING(p->ud, p->buff.b, p->buff.sz);
581 break;
582 case '{':
583 parser_process_object(p);
584 break;
585 case '[':
586 parser_process_array(p);
587 break;
588 default:
589 parser_process_number(p, ch);
590 break;
591 }
592}
593
594// 解析json文本
595static void parser_do_parse(const char *str, size_t size, void *ud, int maxdepth, int allowcomment) {
596 json_parser_t p;
597 parser_init(&p, str, size, ud, maxdepth, allowcomment);
598 //>>>if (setjmp(p.jb) == 0) {
599 parser_process_value(&p);
600 parser_skip_whitespaces(&p);
601 if (peekchar(&p) != '\0') {
602 parser_throw_error(&p, "Expect '<eof>' but got '%c', at: %s[:%lu]", peekchar(&p),
603 parser_error_content(&p), currpos(&p));
604 }
605 parser_free(&p);
606 //>>>}
607}
608
609//-----------------------------------------------------------------------------
610// dumpper
611
612typedef struct {
613 membuffer_t buff; // 临时缓存
614 int maxdepth; // 最大层次
615 int format; // 是否格式化
616 int empty_as_array; // 空表是否当成数组
617 int num_as_str; // 数字Key转为字符串
618 char errmsg[ERRMSG_SIZE]; // 保存错误消息
619} json_dumpper_t;
620
621// 足够转换数字的缓存大小
622#define NUMBER_BUFF_SZ 44
623#define INTEGER_BUFF_SZ 24
624
625// 抛出错误
626static void dumpper_throw_error(json_dumpper_t *d, lua_State *L, const char *fmt, ...) {
627 membuffer_free(&d->buff);
628 va_list arg;
629 va_start(arg, fmt);
630 vsnprintf(d->errmsg, ERRMSG_SIZE, fmt, arg);
631 va_end(arg);
632 luaL_error(L, d->errmsg);
633}
634
635static void dumpper_process_integer(json_dumpper_t *d, lua_State *L, int idx) {
636 char nbuff[INTEGER_BUFF_SZ];
637 int i = INTEGER_BUFF_SZ;
638 membuffer_ensure_space(&d->buff, INTEGER_BUFF_SZ);
639 int64_t x = (int64_t)lua_tointeger(L, idx);
640 uint64_t ux = (uint64_t)x;
641 if (x < 0) {
642 membuffer_putc_unsafe(&d->buff, '-');
643 ux = ~ux + 1;
644 }
645 do {
646 nbuff[--i] = (ux % 10) + '0';
647 } while (ux /= 10);
648 membuffer_putb_unsafe(&d->buff, nbuff+i, INTEGER_BUFF_SZ-i);
649}
650
651static void dumpper_process_number(json_dumpper_t *d, lua_State *L, int idx) {
652 lua_Number num = lua_tonumber(L, idx);
653 if (isinf(num) || isnan(num))
654 dumpper_throw_error(d, L, "The number is NaN or Infinity");
655 membuffer_ensure_space(&d->buff, NUMBER_BUFF_SZ);
656 char *p = membuffer_getp(&d->buff);
657 int len = sprintf(p, LUA_NUMBER_FMT, num);
658 membuffer_add_size(&d->buff, len);
659}
660
661// 字符转义表
662static const char char2escape[256] = {
663 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', 'u', 'u', 'u', 'u', // 0~19
664 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 0, 0, '"', 0, 0, 0, 0, 0, // 20~39
665 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59
666 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79
667 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, 0, 0, 0, 0, // 80~99
668 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100~119
669 0, 0, 0, 0, 0, 0, 0, 'u', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139
670 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159
671 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179
672 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199
673 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219
674 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239
675 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256
676};
677static const char hex_digits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
678
679static void dumpper_process_string(json_dumpper_t *d, lua_State *L, int idx) {
680 membuffer_t *buff = &d->buff;
681 size_t len, i;
682 const char *str = lua_tolstring(L, idx, &len);
683 membuffer_ensure_space(buff, len * 6 + 2);
684 membuffer_putc_unsafe(buff, '\"');
685 char esc;
686 unsigned char ch;
687 for (i = 0; i < len; ++i) {
688 ch = (unsigned char)str[i];
689 esc = char2escape[ch];
690 if (likely(!esc))
691 membuffer_putc_unsafe(buff, (char)ch);
692 else {
693 membuffer_putc_unsafe(buff, '\\');
694 membuffer_putc_unsafe(buff, esc);
695 if (esc == 'u') {
696 membuffer_putc_unsafe(buff, '0');
697 membuffer_putc_unsafe(buff, '0');
698 membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc >> 4]);
699 membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc & 0xF]);
700 }
701 }
702 }
703 membuffer_putc_unsafe(buff, '\"');
704}
705
706static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth);
707
708static int dumpper_check_array(json_dumpper_t *d, lua_State *L, int *len) {
709 int asize = lua_rawlen(L, -1);
710 if (asize > 0) {
711 lua_pushinteger(L, asize);
712 if (lua_next(L, -2) == 0) {
713 *len = asize;
714 return 1;
715 } else {
716 lua_pop(L, 2);
717 return 0;
718 }
719 } else {
720 lua_pushnil(L);
721 if (lua_next(L, -2) == 0) {
722 *len = asize;
723 return d->empty_as_array;
724 } else {
725 lua_pop(L, 2);
726 return 0;
727 }
728 }
729}
730
731static inline void dumpper_add_indent(json_dumpper_t *d, int count) {
732 membuffer_ensure_space(&d->buff, count);
733 int i;
734 for (i = 0; i < count; ++i)
735 membuffer_putc_unsafe(&d->buff, '\t');
736}
737
738static void dumpper_process_array(json_dumpper_t *d, lua_State *L, int len, int depth) {
739 membuffer_t *buff = &d->buff;
740 membuffer_putc(buff, '[');
741
742 int i;
743 for (i = 1; i <= len; ++i) {
744 if (unlikely(d->format && i == 1)) membuffer_putc(buff, '\n');
745 lua_rawgeti(L, -1, i);
746 if (unlikely(d->format)) dumpper_add_indent(d, depth);
747 dumpper_process_value(d, L, depth);
748 lua_pop(L, 1);
749 if (i < len)
750 membuffer_putc(buff, ',');
751 if (unlikely(d->format)) membuffer_putc(buff, '\n');
752 }
753
754 if (unlikely(d->format && i > 1)) dumpper_add_indent(d, depth-1);
755 membuffer_putc(buff, ']');
756}
757
758static void dumpper_process_object(json_dumpper_t *d, lua_State *L, int depth) {
759 membuffer_t *buff = &d->buff;
760 membuffer_putc(buff, '{');
761
762 int ktp;
763 int comma = 0;
764 lua_pushnil(L); // t nil
765 while (lua_next(L, -2) != 0) { // t k v
766 if (comma) {
767 membuffer_putc(buff, ',');
768 if (unlikely(d->format)) membuffer_putc(buff, '\n');
769 } else {
770 comma = 1;
771 if (unlikely(d->format)) membuffer_putc(buff, '\n');
772 }
773 // key
774 ktp = lua_type(L, -2);
775 if (ktp == LUA_TSTRING) {
776 if (unlikely(d->format)) dumpper_add_indent(d, depth);
777 dumpper_process_string(d, L, -2);
778 if (likely(!d->format))
779 membuffer_putc(buff, ':');
780 else
781 membuffer_putb(buff, " : ", 3);
782 } else if (ktp == LUA_TNUMBER && d->num_as_str) {
783 if (unlikely(d->format)) dumpper_add_indent(d, depth);
784 membuffer_putc(buff, '\"');
785 if (lua_isinteger(L, -2))
786 dumpper_process_integer(d, L, -2);
787 else
788 dumpper_process_number(d, L, -2);
789 if (likely(!d->format))
790 membuffer_putb(buff, "\":", 2);
791 else
792 membuffer_putb(buff, "\" : ", 4);
793 } else {
794 dumpper_throw_error(d, L, "Table key must be a string");
795 }
796 // value
797 dumpper_process_value(d, L, depth);
798 lua_pop(L, 1);
799 }
800 if (unlikely(d->format && comma)) {
801 membuffer_putc(buff, '\n');
802 dumpper_add_indent(d, depth-1);
803 }
804 membuffer_putc(buff, '}');
805}
806
807static inline void dumpper_process_table(json_dumpper_t *d, lua_State *L, int depth) {
808 depth++;
809 if (depth > d->maxdepth)
810 dumpper_throw_error(d, L, "Too many nested data, max depth is %d", d->maxdepth);
811 luaL_checkstack(L, 6, NULL);
812
813 int len;
814 if (dumpper_check_array(d, L, &len))
815 dumpper_process_array(d, L, len, depth);
816 else
817 dumpper_process_object(d, L, depth);
818}
819
820static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth) {
821 int tp = lua_type(L, -1);
822 switch (tp) {
823 case LUA_TSTRING:
824 dumpper_process_string(d, L, -1);
825 break;
826 case LUA_TNUMBER:
827 if (lua_isinteger(L, -1))
828 dumpper_process_integer(d, L, -1);
829 else
830 dumpper_process_number(d, L, -1);
831 break;
832 case LUA_TBOOLEAN:
833 if (lua_toboolean(L, -1))
834 membuffer_putb(&d->buff, "true", 4);
835 else
836 membuffer_putb(&d->buff, "false", 5);
837 break;
838 case LUA_TTABLE:
839 dumpper_process_table(d, L, depth);
840 break;
841 case LUA_TNIL:
842 membuffer_putb(&d->buff, "null", 4);
843 break;
844 case LUA_TLIGHTUSERDATA:
845 if (lua_touserdata(L, -1) == NULL) {
846 membuffer_putb(&d->buff, "null", 4);
847 break;
848 }
849 goto error;
850 default:
851 error:
852 dumpper_throw_error(d, L, "Unsupport type %s", lua_typename(L, tp));
853 }
854}
855
856//-----------------------------------------------------------------------------
857// 接口
858#define DEF_MAX_DEPTH 128
859
860// 从字符串加载:json.load(str, maxdepth) -> obj
861// 要求字符串必须以0结尾
862int colibc_json_load(lua_State *L) {
863 size_t size;
864 const char *str = luaL_checklstring(L, 1, &size);
865 int maxdepth = (int)luaL_optinteger(L, 2, DEF_MAX_DEPTH);
866 int allowcomment = lua_toboolean(L, 3);
867 parser_do_parse(str, size, L, maxdepth, allowcomment);
868 return 1;
869}
870
871// 保存到字符串: json.dump(obj) -> str
872int colibc_json_dump(lua_State *L) {
873 luaL_checkany(L, 1);
874 json_dumpper_t dumpper;
875 membuffer_init(&dumpper.buff);
876 dumpper.format = lua_toboolean(L, 2);
877 dumpper.empty_as_array = lua_toboolean(L, 3);
878 dumpper.num_as_str = lua_toboolean(L, 4);
879 dumpper.maxdepth = (int)luaL_optinteger(L, 5, DEF_MAX_DEPTH);
880
881 lua_settop(L, 1);
882 dumpper_process_value(&dumpper, L, 0);
883 lua_pushlstring(L, dumpper.buff.b, dumpper.buff.sz);
884 membuffer_free(&dumpper.buff);
885 return 1;
886}
887
888static const luaL_Reg lib[] = {
889 {"load", colibc_json_load},
890 {"dump", colibc_json_dump},
891 {NULL, NULL},
892};
893
894LUAMOD_API int luaopen_colibc_json(lua_State *L) {
895 luaL_newlib(L, lib);
896 // json.null
897 lua_pushlightuserdata(L, NULL);
898 lua_setfield(L, -2, "null");
899 return 1;
900}