6 Copyright (c) 2005 JSON.org
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
18 The Software shall be used for Good, not Evil.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 #include "hphp/runtime/ext/JSON_parser.h"
31 #include "hphp/runtime/base/util/string_buffer.h"
32 #include "hphp/runtime/base/complex_types.h"
33 #include "hphp/runtime/base/type_conversions.h"
34 #include "hphp/runtime/base/builtin_functions.h"
35 #include "hphp/runtime/base/zend/utf8_decode.h"
37 #include "hphp/system/lib/systemlib.h"
39 #define MAX_LENGTH_OF_LONG 20
40 static const char long_min_digits
[] = "9223372036854775808";
56 Characters are mapped into these 32 symbol classes. This allows for
57 significant reductions in the size of the state transition table.
66 /* other whitespace */
153 /* everything else */
158 This table maps the 128 ASCII characters into the 32 character classes.
159 The remaining Unicode characters should be mapped to S_ETC.
161 static const int ascii_class
[128] = {
162 S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
,
163 S_ERR
, S_WSP
, S_WSP
, S_ERR
, S_ERR
, S_WSP
, S_ERR
, S_ERR
,
164 S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
,
165 S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
,
167 S_SPA
, S_ETC
, S_QUO
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
,
168 S_ETC
, S_ETC
, S_ETC
, S_PLU
, S_COM
, S_MIN
, S_DOT
, S_SLA
,
169 S_ZER
, S_DIG
, S_DIG
, S_DIG
, S_DIG
, S_DIG
, S_DIG
, S_DIG
,
170 S_DIG
, S_DIG
, S_COL
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
,
172 S_ETC
, S_A_F
, S_A_F
, S_A_F
, S_A_F
, S_E
, S_A_F
, S_ETC
,
173 S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
,
174 S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
,
175 S_ETC
, S_ETC
, S_ETC
, S_LBT
, S_BAC
, S_RBT
, S_ETC
, S_ETC
,
177 S_ETC
, S__A_
, S__B_
, S__C_
, S__D_
, S__E_
, S__F_
, S_ETC
,
178 S_ETC
, S_ETC
, S_ETC
, S_ETC
, S__L_
, S_ETC
, S__N_
, S_ETC
,
179 S_ETC
, S_ETC
, S__R_
, S__S_
, S__T_
, S__U_
, S_ETC
, S_ETC
,
180 S_ETC
, S_ETC
, S_ETC
, S_LBE
, S_ETC
, S_RBE
, S_ETC
, S_ETC
184 static const int loose_ascii_class
[128] = {
185 S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
,
186 S_ERR
, S_WSP
, S_WSP
, S_ERR
, S_ERR
, S_WSP
, S_ERR
, S_ERR
,
187 S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
,
188 S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
, S_ERR
,
190 S_SPA
, S_ETC
, S_QUO
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_QUO
,
191 S_ETC
, S_ETC
, S_ETC
, S_PLU
, S_COM
, S_MIN
, S_DOT
, S_SLA
,
192 S_ZER
, S_DIG
, S_DIG
, S_DIG
, S_DIG
, S_DIG
, S_DIG
, S_DIG
,
193 S_DIG
, S_DIG
, S_COL
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
,
195 S_ETC
, S_A_F
, S_A_F
, S_A_F
, S_A_F
, S_E
, S_A_F
, S_ETC
,
196 S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
,
197 S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
, S_ETC
,
198 S_ETC
, S_ETC
, S_ETC
, S_LBT
, S_BAC
, S_RBT
, S_ETC
, S_ETC
,
200 S_ETC
, S__A_
, S__B_
, S__C_
, S__D_
, S__E_
, S__F_
, S_ETC
,
201 S_ETC
, S_ETC
, S_ETC
, S_ETC
, S__L_
, S_ETC
, S__N_
, S_ETC
,
202 S_ETC
, S_ETC
, S__R_
, S__S_
, S__T_
, S__U_
, S_ETC
, S_ETC
,
203 S_ETC
, S_ETC
, S_ETC
, S_LBE
, S_ETC
, S_RBE
, S_ETC
, S_ETC
210 The state transition table takes the current state and the current symbol,
211 and returns either a new state or an action. A new state is a number between
212 0 and 29. An action is a negative number between -1 and -9. A JSON text is
213 accepted if the end of the text is in state 9 and mode is MODE_DONE.
215 static const int state_transition_table
[30][31] = {
216 /* 0*/ { 0, 0,-8,-1,-6,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
217 /* 1*/ { 1, 1,-1,-9,-1,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
218 /* 2*/ { 2, 2,-8,-1,-6,-5,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1},
219 /* 3*/ { 3,-1, 3, 3, 3, 3, 3, 3,-4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
220 /* 4*/ {-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1, 3,-1, 3, 3,-1, 3, 5,-1,-1,-1},
221 /* 5*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 6, 6, 6, 6, 6, 6, 6, 6,-1,-1,-1,-1,-1,-1, 6, 6,-1},
222 /* 6*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 7, 7, 7, 7, 7, 7, 7, 7,-1,-1,-1,-1,-1,-1, 7, 7,-1},
223 /* 7*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 8, 8, 8, 8, 8, 8, 8, 8,-1,-1,-1,-1,-1,-1, 8, 8,-1},
224 /* 8*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3, 3,-1},
225 /* 9*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
226 /*10*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,-1,-1,-1,-1,-1,-1},
227 /*11*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1},
228 /*12*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
229 /*13*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
230 /*14*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,15,-1,-1,-1,-1,-1,-1,-1,-1},
231 /*15*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,16,-1,-1,-1,-1,-1},
232 /*16*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
233 /*17*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,18,-1,-1,-1},
234 /*18*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,19,-1,-1,-1,-1,-1,-1,-1,-1},
235 /*19*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1},
236 /*20*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,22,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
237 /*21*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
238 /*22*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,22,22,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1},
239 /*23*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,23,23,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1},
240 /*24*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,25,25,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
241 /*25*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
242 /*26*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
243 /*27*/ {27,27,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
244 /*28*/ {28,28,-8,-1,-6,-1,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1},
245 /*29*/ {29,29,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}
250 Alternate "loose" transition table to support unquoted keys.
252 static const int loose_state_transition_table
[31][31] = {
253 /* 0*/ { 0, 0,-8,-1,-6,-1,-1,-1, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
254 /* 1*/ { 1, 1,-1,-9,-1,-1,-1,-1, 3,-1,-1,-1,-1,-1,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30},
255 /* 2*/ { 2, 2,-8,-1,-6,-5,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1},
256 /* 3*/ { 3,-1, 3, 3, 3, 3, 3, 3,-4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3},
257 /* 4*/ {-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3,-1,-1,-1, 3,-1, 3, 3,-1, 3, 5,-1,-1,-1},
258 /* 5*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 6, 6, 6, 6, 6, 6, 6, 6,-1,-1,-1,-1,-1,-1, 6, 6,-1},
259 /* 6*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 7, 7, 7, 7, 7, 7, 7, 7,-1,-1,-1,-1,-1,-1, 7, 7,-1},
260 /* 7*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 8, 8, 8, 8, 8, 8, 8, 8,-1,-1,-1,-1,-1,-1, 8, 8,-1},
261 /* 8*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1, 3, 3,-1},
262 /* 9*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
263 /*10*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,-1,-1,-1,-1,-1,-1},
264 /*11*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1},
265 /*12*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
266 /*13*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
267 /*14*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,15,-1,-1,-1,-1,-1,-1,-1,-1},
268 /*15*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,16,-1,-1,-1,-1,-1},
269 /*16*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
270 /*17*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,18,-1,-1,-1},
271 /*18*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,19,-1,-1,-1,-1,-1,-1,-1,-1},
272 /*19*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 9,-1,-1,-1,-1,-1,-1,-1,-1},
273 /*20*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,22,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
274 /*21*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
275 /*22*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,23,22,22,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1},
276 /*23*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,23,23,-1,-1,-1,-1,24,-1,-1,-1,-1,-1,-1,-1,-1,24,-1},
277 /*24*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,25,25,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
278 /*25*/ {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
279 /*26*/ { 9, 9,-1,-7,-1,-5,-1,-3,-1,-1,-1,-1,-1,-1,26,26,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
280 /*27*/ {27,27,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
281 /*28*/ {28,28,-8,-1,-6,-5,-1,-1, 3,-1,-1,-1,20,-1,21,22,-1,-1,-1,-1,-1,13,-1,17,-1,-1,10,-1,-1,-1,-1},
282 /*29*/ {29,29,-1,-7,-1,-1,-1,-7, 3,-1,-1,-1,-1,-1,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30},
283 /*30*/ {30,-1,30,30,30,30,-10,30,-4,4,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30}
288 #define JSON_PARSER_MAX_DEPTH 512
291 * A stack maintains the states of nested structures.
294 int the_stack
[JSON_PARSER_MAX_DEPTH
];
295 Variant the_zstack
[JSON_PARSER_MAX_DEPTH
];
296 String the_kstack
[JSON_PARSER_MAX_DEPTH
];
298 int the_mark
; // the watermark
301 IMPLEMENT_THREAD_LOCAL(json_parser
, s_json_parser
);
303 class JsonParserCleaner
{
305 explicit JsonParserCleaner(json_parser
*json
) : m_json(json
) {}
306 ~JsonParserCleaner() {
307 for (int i
= 0; i
<= m_json
->the_mark
; i
++) {
308 m_json
->the_zstack
[i
].unset();
309 m_json
->the_kstack
[i
].reset();
317 * These modes can be pushed on the PDA stack.
321 #define MODE_OBJECT 3
325 * Push a mode onto the stack. Return false if there is overflow.
327 static int push(json_parser
*json
, int mode
) {
329 if (json
->the_top
>= JSON_PARSER_MAX_DEPTH
) {
332 json
->the_stack
[json
->the_top
] = mode
;
333 if (json
->the_top
> json
->the_mark
) {
334 json
->the_mark
= json
->the_top
;
341 * Pop the stack, assuring that the current mode matches the expectation.
342 * Return false if there is underflow or if the modes mismatch.
344 static int pop(json_parser
*json
, int mode
) {
345 if (json
->the_top
< 0 || json
->the_stack
[json
->the_top
] != mode
) {
348 json
->the_stack
[json
->the_top
] = 0;
353 static int dehexchar(char c
) {
354 if (c
>= '0' && c
<= '9') return c
- '0';
355 if (c
>= 'A' && c
<= 'F') return c
- ('A' - 10);
356 if (c
>= 'a' && c
<= 'f') return c
- ('a' - 10);
360 static void json_create_zval(Variant
&z
, StringBuffer
&buf
, int type
) {
364 const char *p
= buf
.data();
371 bool neg
= (buf
.charAt(0) == '-');
373 int len
= buf
.size();
375 if (len
>= MAX_LENGTH_OF_LONG
- 1) {
376 if (len
== MAX_LENGTH_OF_LONG
- 1) {
377 int cmp
= strcmp(p
+ (neg
? 1 : 0), long_min_digits
);
378 if (!(cmp
< 0 || (cmp
== 0 && neg
))) {
387 z
= int64_t(strtoll(buf
.data(), NULL
, 10));
391 z
= buf
.data() ? strtod(buf
.data(), NULL
) : 0.0;
397 z
= (buf
.data() && (*buf
.data() == 't'));
405 static void utf16_to_utf8(StringBuffer
&buf
, unsigned short utf16
) {
408 } else if (utf16
< 0x800) {
409 buf
+= (char)(0xc0 | (utf16
>> 6));
410 buf
+= (char)(0x80 | (utf16
& 0x3f));
411 } else if ((utf16
& 0xfc00) == 0xdc00
413 && ((unsigned char)buf
.charAt(buf
.size() - 3)) == 0xed
414 && ((unsigned char)buf
.charAt(buf
.size() - 2) & 0xf0) == 0xa0
415 && ((unsigned char)buf
.charAt(buf
.size() - 1) & 0xc0) == 0x80) {
416 /* found surrogate pair */
419 utf32
= (((buf
.charAt(buf
.size() - 2) & 0xf) << 16)
420 | ((buf
.charAt(buf
.size() - 1) & 0x3f) << 10)
421 | (utf16
& 0x3ff)) + 0x10000;
422 buf
.resize(buf
.size() - 3);
424 buf
+= (char)(0xf0 | (utf32
>> 18));
425 buf
+= (char)(0x80 | ((utf32
>> 12) & 0x3f));
426 buf
+= (char)(0x80 | ((utf32
>> 6) & 0x3f));
427 buf
+= (char)(0x80 | (utf32
& 0x3f));
429 buf
+= (char)(0xe0 | (utf16
>> 12));
430 buf
+= (char)(0x80 | ((utf16
>> 6) & 0x3f));
431 buf
+= (char)(0x80 | (utf16
& 0x3f));
435 static void object_set(Variant
&var
, CStrRef key
, CVarRef value
,
438 // We know it is stdClass, and everything is public (and dynamic).
440 var
.getObjectData()->o_set("_empty_", value
);
442 var
.getObjectData()->o_set(key
, value
);
449 static void attach_zval(json_parser
*json
, CStrRef key
,
451 Variant
&root
= json
->the_zstack
[json
->the_top
- 1];
452 Variant
&child
= json
->the_zstack
[json
->the_top
];
453 int up_mode
= json
->the_stack
[json
->the_top
- 1];
455 if (up_mode
== MODE_ARRAY
) {
457 } else if (up_mode
== MODE_OBJECT
) {
458 object_set(root
, key
, child
, assoc
);
462 #define SWAP_BUFFERS(from, to) do { \
463 StringBuffer *tmp = from; \
467 #define JSON_RESET_TYPE() do { type = -1; } while(0);
468 #define JSON(x) the_json->x
471 * The JSON_parser takes a UTF-8 encoded string and determines if it is a
472 * syntactically correct JSON text. Along the way, it creates a PHP variable.
474 * It is implemented as a Pushdown Automaton; that means it is a finite state
475 * machine with a stack.
477 bool JSON_parser(Variant
&z
, const char *p
, int length
, bool assoc
/*<fb>*/,
478 bool loose
/*</fb>*/) {
479 int b
; /* the next character */
480 int c
; /* the next character class */
481 int s
; /* the next state */
482 json_parser
*the_json
= s_json_parser
.get(); /* the parser state */
483 JsonParserCleaner
cleaner(the_json
);
488 int const *byte_class
;
490 byte_class
= loose_ascii_class
;
492 byte_class
= ascii_class
;
496 StringBuffer
sb_buf(127), sb_key(127);
497 StringBuffer
*buf
= &sb_buf
;
498 StringBuffer
*key
= &sb_key
;
501 unsigned short utf16
= 0;
503 JSON(the_mark
) = JSON(the_top
) = -1;
504 push(the_json
, MODE_DONE
);
506 UTF8To16Decoder
decoder(p
, length
, loose
);
508 b
= decoder
.decode();
509 if (b
== UTF8_END
) break; // UTF-8 decoding finishes successfully.
510 if (b
== UTF8_ERROR
) {
515 if ((b
& 127) == b
) {
526 Get the next state from the transition table.
531 s
= loose_state_transition_table
[the_state
][c
];
533 s
= state_transition_table
[the_state
][c
];
547 Perform one of the predefined actions.
554 if (!pop(the_json
, MODE_KEY
)) {
563 if (!push(the_json
, MODE_KEY
)) {
568 if (JSON(the_top
) > 0) {
569 Variant
&top
= JSON(the_zstack
)[JSON(the_top
)];
570 if (JSON(the_top
) == 1) {
576 top
= SystemLib::AllocStdClassObject();
578 top
= Array::Create();
580 JSON(the_kstack
)[JSON(the_top
)] = key
->detach();
588 /*** BEGIN Facebook: json_utf8_loose ***/
590 If this is a trailing comma in an object definition,
591 we're in MODE_KEY. In that case, throw that off the
592 stack and restore MODE_OBJECT so that we pretend the
593 trailing comma just didn't happen.
596 if (pop(the_json
, MODE_KEY
)) {
597 push(the_json
, MODE_OBJECT
);
600 /*** END Facebook: json_utf8_loose ***/
603 JSON(the_stack
)[JSON(the_top
)] == MODE_OBJECT
) {
605 json_create_zval(mval
, *buf
, type
);
606 Variant
&top
= JSON(the_zstack
)[JSON(the_top
)];
607 object_set(top
, key
->detach(), mval
, assoc
);
612 attach_zval(the_json
, JSON(the_kstack
)[JSON(the_top
)], assoc
);
614 if (!pop(the_json
, MODE_OBJECT
)) {
623 if (!push(the_json
, MODE_ARRAY
)) {
628 if (JSON(the_top
) > 0) {
629 if (JSON(the_top
) == 1) {
630 JSON(the_zstack
)[JSON(the_top
)].assignRef(z
);
632 JSON(the_zstack
)[JSON(the_top
)].unset();
634 JSON(the_zstack
)[JSON(the_top
)] = Array::Create();
635 JSON(the_kstack
)[JSON(the_top
)] = key
->detach();
645 JSON(the_stack
)[JSON(the_top
)] == MODE_ARRAY
) {
647 json_create_zval(mval
, *buf
, type
);
648 JSON(the_zstack
)[JSON(the_top
)].append(mval
);
653 attach_zval(the_json
, JSON(the_kstack
[JSON(the_top
)]), assoc
);
655 if (!pop(the_json
, MODE_ARRAY
)) {
665 switch (JSON(the_stack
)[JSON(the_top
)]) {
668 SWAP_BUFFERS(buf
, key
);
676 if (type
== KindOfString
) {
681 /* fall through if not KindOfString */
693 (JSON(the_stack
)[JSON(the_top
)] == MODE_OBJECT
||
694 JSON(the_stack
)[JSON(the_top
)] == MODE_ARRAY
)) {
695 json_create_zval(mval
, *buf
, type
);
698 switch (JSON(the_stack
)[JSON(the_top
)]) {
700 if (pop(the_json
, MODE_OBJECT
) &&
701 push(the_json
, MODE_KEY
)) {
703 Variant
&top
= JSON(the_zstack
)[JSON(the_top
)];
704 object_set(top
, key
->detach(), mval
, assoc
);
711 JSON(the_zstack
)[JSON(the_top
)].append(mval
);
725 : (after unquoted string)
728 if (JSON(the_stack
)[JSON(the_top
)] == MODE_KEY
) {
730 SWAP_BUFFERS(buf
, key
);
743 if (pop(the_json
, MODE_KEY
) && push(the_json
, MODE_OBJECT
)) {
755 Change the state and iterate.
757 if (type
== KindOfString
) {
758 if (/*<fb>*/(/*</fb>*/s
== 3/*<fb>*/ || s
== 30)/*</fb>*/ &&
760 if (the_state
!= 4) {
761 utf16_to_utf8(*buf
, b
);
764 case 'b': buf
->append('\b'); break;
765 case 't': buf
->append('\t'); break;
766 case 'n': buf
->append('\n'); break;
767 case 'f': buf
->append('\f'); break;
768 case 'r': buf
->append('\r'); break;
770 utf16_to_utf8(*buf
, b
);
775 utf16
= dehexchar(b
) << 12;
777 utf16
+= dehexchar(b
) << 8;
779 utf16
+= dehexchar(b
) << 4;
780 } else if (s
== 3 && the_state
== 8) {
781 utf16
+= dehexchar(b
);
782 utf16_to_utf8(*buf
, utf16
);
784 } else if ((type
< 0 || type
== KindOfNull
) &&
785 (c
== S_DIG
|| c
== S_ZER
)) {
787 buf
->append((char)b
);
788 } else if (type
== KindOfInt64
&& s
== 24) {
790 buf
->append((char)b
);
791 } else if ((type
< 0 || type
== KindOfNull
|| type
== KindOfInt64
) &&
794 buf
->append((char)b
);
795 } else if (type
!= KindOfString
&& c
== S_QUO
) {
797 /*<fb>*/qchr
= b
;/*</fb>*/
798 } else if ((type
< 0 || type
== KindOfNull
|| type
== KindOfInt64
||
799 type
== KindOfDouble
) &&
800 ((the_state
== 12 && s
== 9) ||
801 (the_state
== 16 && s
== 9))) {
802 type
= KindOfBoolean
;
803 } else if (type
< 0 && the_state
== 19 && s
== 9) {
805 } else if (type
!= KindOfString
&& c
> S_WSP
) {
806 utf16_to_utf8(*buf
, b
);
813 return the_state
== 9 && pop(the_json
, MODE_DONE
);