forked from quartzjer/js0n
-
Notifications
You must be signed in to change notification settings - Fork 0
/
js0n.c
134 lines (114 loc) · 3.03 KB
/
js0n.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// by jeremie miller - 2010
// public domain, contributions/improvements welcome via github at https://github.com/quartzjer/js0n
// gcc started warning for the init syntax used here, is not helpful so don't generate the spam
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Winitializer-overrides"
// opportunity to further optimize would be having different jump tables for higher depths
#define PUSH(i) if(depth == 1) prev = *out++ = ((cur+i) - js)
#define CAP(i) if(depth == 1) prev = *out++ = ((cur+i) - (js + prev) + 1)
int js0n(const unsigned char *js, unsigned int len, unsigned short *out, unsigned int olen)
{
unsigned short prev = 0, *oend;
const unsigned char *cur, *end;
int depth=0;
int utf8_remain=0;
static void *gostruct[] =
{
[0 ... 255] = &&l_bad,
['\t'] = &&l_loop, [' '] = &&l_loop, ['\r'] = &&l_loop, ['\n'] = &&l_loop,
['"'] = &&l_qup,
[':'] = &&l_loop,[','] = &&l_loop,
['['] = &&l_up, [']'] = &&l_down, // tracking [] and {} individually would allow fuller validation but is really messy
['{'] = &&l_up, ['}'] = &&l_down,
['-'] = &&l_bare, [48 ... 57] = &&l_bare, // 0-9
['t'] = &&l_bare, ['f'] = &&l_bare, ['n'] = &&l_bare // true, false, null
};
static void *gobare[] =
{
[0 ... 31] = &&l_bad,
[32 ... 126] = &&l_loop, // could be more pedantic/validation-checking
['\t'] = &&l_unbare, [' '] = &&l_unbare, ['\r'] = &&l_unbare, ['\n'] = &&l_unbare,
[','] = &&l_unbare, [']'] = &&l_unbare, ['}'] = &&l_unbare,
[127 ... 255] = &&l_bad
};
static void *gostring[] =
{
[0 ... 31] = &&l_bad, [127] = &&l_bad,
[32 ... 126] = &&l_loop,
['\\'] = &&l_esc, ['"'] = &&l_qdown,
[128 ... 191] = &&l_bad,
[192 ... 223] = &&l_utf8_2,
[224 ... 239] = &&l_utf8_3,
[240 ... 247] = &&l_utf8_4,
[248 ... 255] = &&l_bad
};
static void *goutf8_continue[] =
{
[0 ... 127] = &&l_bad,
[128 ... 191] = &&l_utf_continue,
[192 ... 255] = &&l_bad
};
static void *goesc[] =
{
[0 ... 255] = &&l_bad,
['"'] = &&l_unesc, ['\\'] = &&l_unesc, ['/'] = &&l_unesc, ['b'] = &&l_unesc,
['f'] = &&l_unesc, ['n'] = &&l_unesc, ['r'] = &&l_unesc, ['t'] = &&l_unesc, ['u'] = &&l_unesc
};
void **go = gostruct;
for(cur=js,end=js+len,oend=out+olen; cur<end && out<oend; cur++)
{
goto *go[*cur];
l_loop:;
}
if(out < oend) *out = 0;
return depth; // 0 if successful full parse, >0 for incomplete data
l_bad:
return 1;
l_up:
PUSH(0);
++depth;
goto l_loop;
l_down:
--depth;
CAP(0);
goto l_loop;
l_qup:
PUSH(1);
go=gostring;
goto l_loop;
l_qdown:
CAP(-1);
go=gostruct;
goto l_loop;
l_esc:
go = goesc;
goto l_loop;
l_unesc:
go = gostring;
goto l_loop;
l_bare:
PUSH(0);
go = gobare;
goto l_loop;
l_unbare:
CAP(-1);
go = gostruct;
goto *go[*cur];
l_utf8_2:
go = goutf8_continue;
utf8_remain = 1;
goto l_loop;
l_utf8_3:
go = goutf8_continue;
utf8_remain = 2;
goto l_loop;
l_utf8_4:
go = goutf8_continue;
utf8_remain = 3;
goto l_loop;
l_utf_continue:
if (!--utf8_remain)
go=gostring;
goto l_loop;
}
#pragma GCC diagnostic pop