Annotation of embedaddon/php/ext/json/JSON_parser.c, revision 1.1.1.2
1.1 misho 1: /* JSON_parser.c */
2:
3: /* 2005-12-30 */
4:
5: /*
6: Copyright (c) 2005 JSON.org
7:
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:
14:
15: The above copyright notice and this permission notice shall be included in all
16: copies or substantial portions of the Software.
17:
18: The Software shall be used for Good, not Evil.
19:
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
26: SOFTWARE.
27: */
28:
29: #include <stdio.h>
30: #include "JSON_parser.h"
31:
32: /* Windows defines IN for documentation */
33: #undef IN
34:
35: #define true 1
36: #define false 0
37: #define __ -1 /* the universal error code */
38:
39: /*
40: Characters are mapped into these 31 character classes. This allows for
41: a significant reduction in the size of the state transition table.
42: */
43:
44: enum classes {
45: C_SPACE, /* space */
46: C_WHITE, /* other whitespace */
47: C_LCURB, /* { */
48: C_RCURB, /* } */
49: C_LSQRB, /* [ */
50: C_RSQRB, /* ] */
51: C_COLON, /* : */
52: C_COMMA, /* , */
53: C_QUOTE, /* " */
54: C_BACKS, /* \ */
55: C_SLASH, /* / */
56: C_PLUS, /* + */
57: C_MINUS, /* - */
58: C_POINT, /* . */
59: C_ZERO , /* 0 */
60: C_DIGIT, /* 123456789 */
61: C_LOW_A, /* a */
62: C_LOW_B, /* b */
63: C_LOW_C, /* c */
64: C_LOW_D, /* d */
65: C_LOW_E, /* e */
66: C_LOW_F, /* f */
67: C_LOW_L, /* l */
68: C_LOW_N, /* n */
69: C_LOW_R, /* r */
70: C_LOW_S, /* s */
71: C_LOW_T, /* t */
72: C_LOW_U, /* u */
73: C_ABCDF, /* ABCDF */
74: C_E, /* E */
75: C_ETC, /* everything else */
76: NR_CLASSES
77: };
78:
79: static const int ascii_class[128] = {
80: /*
81: This array maps the 128 ASCII characters into character classes.
82: The remaining Unicode characters should be mapped to C_ETC.
83: Non-whitespace control characters are errors.
84: */
85: __, __, __, __, __, __, __, __,
86: __, C_WHITE, C_WHITE, __, __, C_WHITE, __, __,
87: __, __, __, __, __, __, __, __,
88: __, __, __, __, __, __, __, __,
89:
90: C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
91: C_ETC, C_ETC, C_ETC, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH,
92: C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT,
93: C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
94:
95: C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC,
96: C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
97: C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC,
98: C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC,
99:
100: C_ETC, C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC,
101: C_ETC, C_ETC, C_ETC, C_ETC, C_LOW_L, C_ETC, C_LOW_N, C_ETC,
102: C_ETC, C_ETC, C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC, C_ETC,
103: C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC
104: };
105:
106:
107: /*
108: The state codes.
109: */
110: enum states {
111: GO, /* start */
112: OK, /* ok */
113: OB, /* object */
114: KE, /* key */
115: CO, /* colon */
116: VA, /* value */
117: AR, /* array */
118: ST, /* string */
119: ES, /* escape */
120: U1, /* u1 */
121: U2, /* u2 */
122: U3, /* u3 */
123: U4, /* u4 */
124: MI, /* minus */
125: ZE, /* zero */
126: IN, /* integer */
127: FR, /* fraction */
128: E1, /* e */
129: E2, /* ex */
130: E3, /* exp */
131: T1, /* tr */
132: T2, /* tru */
133: T3, /* true */
134: F1, /* fa */
135: F2, /* fal */
136: F3, /* fals */
137: F4, /* false */
138: N1, /* nu */
139: N2, /* nul */
140: N3, /* null */
141: NR_STATES
142: };
143:
144:
145: static const int state_transition_table[NR_STATES][NR_CLASSES] = {
146: /*
147: The state transition table takes the current state and the current symbol,
148: and returns either a new state or an action. An action is represented as a
149: negative number. A JSON text is accepted if at the end of the text the
150: state is OK and if the mode is MODE_DONE.
151:
152: white 1-9 ABCDF etc
153: space | { } [ ] : , " \ / + - . 0 | a b c d e f l n r s t u | E |*/
154: /*start GO*/ {GO,GO,-6,__,-5,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
155: /*ok OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
156: /*object OB*/ {OB,OB,__,-9,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
157: /*key KE*/ {KE,KE,__,__,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
158: /*colon CO*/ {CO,CO,__,__,__,__,-2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
159: /*value VA*/ {VA,VA,-6,__,-5,__,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
160: /*array AR*/ {AR,AR,-6,__,-5,-7,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__},
161: /*string ST*/ {ST,__,ST,ST,ST,ST,ST,ST,-4,ES,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST,ST},
162: /*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__},
163: /*u1 U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__},
164: /*u2 U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__},
165: /*u3 U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__},
166: /*u4 U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ST,ST,ST,ST,ST,ST,ST,ST,__,__,__,__,__,__,ST,ST,__},
167: /*minus MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IN,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
168: /*zero ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,__,__,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
169: /*int IN*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,IN,IN,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
170: /*frac FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__},
171: /*e E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
172: /*ex E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
173: /*exp E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
174: /*tr T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__},
175: /*tru T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__},
176: /*true T3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
177: /*fa F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__},
178: /*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__},
179: /*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__},
180: /*false F4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__},
181: /*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__},
182: /*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__},
183: /*null N3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__},
184: };
185:
186:
187: /*
188: These modes can be pushed on the stack.
189: */
190: enum modes {
191: MODE_ARRAY,
192: MODE_DONE,
193: MODE_KEY,
194: MODE_OBJECT,
195: };
196:
197:
198: /*
199: Push a mode onto the stack. Return false if there is overflow.
200: */
201: static int
202: push(JSON_parser jp, int mode)
203: {
204: jp->top += 1;
205: if (jp->top >= jp->depth) {
206: jp->error_code = PHP_JSON_ERROR_DEPTH;
207: return false;
208: }
209: jp->stack[jp->top] = mode;
210: return true;
211: }
212:
213:
214: /*
215: Pop the stack, assuring that the current mode matches the expectation.
216: Return false if there is underflow or if the modes mismatch.
217: */
218: static int
219: pop(JSON_parser jp, int mode)
220: {
221: if (jp->top < 0 || jp->stack[jp->top] != mode) {
222: jp->error_code = PHP_JSON_ERROR_STATE_MISMATCH;
223: return false;
224: }
225: jp->top -= 1;
226: return true;
227: }
228:
229: /*
230: new_JSON_checker starts the checking process by constructing a JSON_checker
231: object. It takes a depth parameter that restricts the level of maximum
232: nesting.
233:
234: To continue the process, call JSON_checker_char for each character in the
235: JSON text, and then call JSON_checker_done to obtain the final result.
236: These functions are fully reentrant.
237:
238: The JSON_checker object will be deleted by JSON_checker_done.
239: JSON_checker_char will delete the JSON_checker object if it sees an error.
240: */
241: JSON_parser
242: new_JSON_parser(int depth)
243: {
244: JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct));
245: jp->state = GO;
246: jp->depth = depth;
247: jp->top = -1;
248: jp->error_code = PHP_JSON_ERROR_NONE;
249: jp->stack = (int*)ecalloc(depth, sizeof(int));
250: if (depth > JSON_PARSER_DEFAULT_DEPTH) {
251: jp->the_zstack = (zval **)safe_emalloc(depth, sizeof(zval), 0);
252: } else {
253: jp->the_zstack = &jp->the_static_zstack[0];
254: }
255: push(jp, MODE_DONE);
256: return jp;
257: }
258:
259: /*
260: Delete the JSON_parser object.
261: */
262: int
263: free_JSON_parser(JSON_parser jp)
264: {
265: efree((void*)jp->stack);
266: if (jp->the_zstack != &jp->the_static_zstack[0]) {
267: efree(jp->the_zstack);
268: }
269: efree((void*)jp);
270: return false;
271: }
272:
273: static int dehexchar(char c)
274: {
275: if (c >= '0' && c <= '9')
276: {
277: return c - '0';
278: }
279: else if (c >= 'A' && c <= 'F')
280: {
281: return c - ('A' - 10);
282: }
283: else if (c >= 'a' && c <= 'f')
284: {
285: return c - ('a' - 10);
286: }
287: else
288: {
289: return -1;
290: }
291: }
292:
293:
1.1.1.2 ! misho 294: static void json_create_zval(zval **z, smart_str *buf, int type, int options)
1.1 misho 295: {
296: ALLOC_INIT_ZVAL(*z);
297:
298: if (type == IS_LONG)
299: {
1.1.1.2 ! misho 300: zend_bool bigint = 0;
! 301:
1.1 misho 302: if (buf->c[0] == '-') {
303: buf->len--;
304: }
305:
306: if (buf->len >= MAX_LENGTH_OF_LONG - 1) {
307: if (buf->len == MAX_LENGTH_OF_LONG - 1) {
308: int cmp = strcmp(buf->c + (buf->c[0] == '-'), long_min_digits);
309:
310: if (!(cmp < 0 || (cmp == 0 && buf->c[0] == '-'))) {
1.1.1.2 ! misho 311: bigint = 1;
! 312: }
! 313: } else {
! 314: bigint = 1;
! 315: }
! 316: }
! 317:
! 318: if (bigint) {
! 319: /* value too large to represent as a long */
! 320: if (options & PHP_JSON_BIGINT_AS_STRING) {
! 321: if (buf->c[0] == '-') {
! 322: /* Restore last char consumed above */
! 323: buf->len++;
1.1 misho 324: }
1.1.1.2 ! misho 325: goto use_string;
1.1 misho 326: } else {
327: goto use_double;
328: }
329: }
330:
331: ZVAL_LONG(*z, strtol(buf->c, NULL, 10));
332: }
333: else if (type == IS_DOUBLE)
334: {
335: use_double:
336: ZVAL_DOUBLE(*z, zend_strtod(buf->c, NULL));
337: }
338: else if (type == IS_STRING)
339: {
1.1.1.2 ! misho 340: use_string:
1.1 misho 341: ZVAL_STRINGL(*z, buf->c, buf->len, 1);
342: }
343: else if (type == IS_BOOL)
344: {
345: ZVAL_BOOL(*z, (*(buf->c) == 't'));
346: }
347: else /* type == IS_NULL) || type unknown */
348: {
349: ZVAL_NULL(*z);
350: }
351: }
352:
353:
354: static void utf16_to_utf8(smart_str *buf, unsigned short utf16)
355: {
356: if (utf16 < 0x80)
357: {
358: smart_str_appendc(buf, (unsigned char) utf16);
359: }
360: else if (utf16 < 0x800)
361: {
362: smart_str_appendc(buf, 0xc0 | (utf16 >> 6));
363: smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
364: }
365: else if ((utf16 & 0xfc00) == 0xdc00
366: && buf->len >= 3
367: && ((unsigned char) buf->c[buf->len - 3]) == 0xed
368: && ((unsigned char) buf->c[buf->len - 2] & 0xf0) == 0xa0
369: && ((unsigned char) buf->c[buf->len - 1] & 0xc0) == 0x80)
370: {
371: /* found surrogate pair */
372: unsigned long utf32;
373:
374: utf32 = (((buf->c[buf->len - 2] & 0xf) << 16)
375: | ((buf->c[buf->len - 1] & 0x3f) << 10)
376: | (utf16 & 0x3ff)) + 0x10000;
377: buf->len -= 3;
378:
379: smart_str_appendc(buf, (unsigned char) (0xf0 | (utf32 >> 18)));
380: smart_str_appendc(buf, 0x80 | ((utf32 >> 12) & 0x3f));
381: smart_str_appendc(buf, 0x80 | ((utf32 >> 6) & 0x3f));
382: smart_str_appendc(buf, 0x80 | (utf32 & 0x3f));
383: }
384: else
385: {
386: smart_str_appendc(buf, 0xe0 | (utf16 >> 12));
387: smart_str_appendc(buf, 0x80 | ((utf16 >> 6) & 0x3f));
388: smart_str_appendc(buf, 0x80 | (utf16 & 0x3f));
389: }
390: }
391:
392: static void attach_zval(JSON_parser jp, int up, int cur, smart_str *key, int assoc TSRMLS_DC)
393: {
394: zval *root = jp->the_zstack[up];
395: zval *child = jp->the_zstack[cur];
396: int up_mode = jp->stack[up];
397:
398: if (up_mode == MODE_ARRAY)
399: {
400: add_next_index_zval(root, child);
401: }
402: else if (up_mode == MODE_OBJECT)
403: {
404: if (!assoc)
405: {
406: add_property_zval_ex(root, (key->len ? key->c : "_empty_"), (key->len ? (key->len + 1) : sizeof("_empty_")), child TSRMLS_CC);
407: Z_DELREF_P(child);
408: }
409: else
410: {
411: add_assoc_zval_ex(root, (key->len ? key->c : ""), (key->len ? (key->len + 1) : sizeof("")), child);
412: }
413: key->len = 0;
414: }
415: }
416:
417:
418: #define FREE_BUFFERS() smart_str_free(&buf); smart_str_free(&key);
419: #define SWAP_BUFFERS(from, to) do { \
420: char *t1 = from.c; \
421: int t2 = from.a; \
422: from.c = to.c; \
423: from.a = to.a; \
424: to.c = t1; \
425: to.a = t2; \
426: to.len = from.len; \
427: from.len = 0; \
428: } while(0);
429: #define JSON_RESET_TYPE() type = -1;
430:
431: /*
432: The JSON_parser takes a UTF-16 encoded string and determines if it is a
433: syntactically correct JSON text. Along the way, it creates a PHP variable.
434:
435: It is implemented as a Pushdown Automaton; that means it is a finite state
436: machine with a stack.
437: */
438: int
1.1.1.2 ! misho 439: parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC)
1.1 misho 440: {
441: int next_char; /* the next character */
442: int next_class; /* the next character class */
443: int next_state; /* the next state */
444: int the_index;
1.1.1.2 ! misho 445: int assoc = options & PHP_JSON_OBJECT_AS_ARRAY;
1.1 misho 446:
447: smart_str buf = {0};
448: smart_str key = {0};
449:
450: unsigned short utf16 = 0;
451: int type;
452:
453: JSON_RESET_TYPE();
454:
455: for (the_index = 0; the_index < length; the_index += 1) {
456: next_char = utf16_json[the_index];
457: if (next_char >= 128) {
458: next_class = C_ETC;
459: } else {
460: next_class = ascii_class[next_char];
461: if (next_class <= __) {
462: jp->error_code = PHP_JSON_ERROR_CTRL_CHAR;
463: FREE_BUFFERS();
464: return false;
465: }
466: }
467: /*
468: Get the next state from the transition table.
469: */
470: next_state = state_transition_table[jp->state][next_class];
471: if (next_state >= 0) {
472: /*
473: Change the state and iterate
474: */
475: if (type == IS_STRING) {
476: if (next_state == ST && jp->state != U4) {
477: if (jp->state != ES) {
478: utf16_to_utf8(&buf, next_char);
479: } else {
480: switch (next_char) {
481: case 'b':
482: smart_str_appendc(&buf, '\b');
483: break;
484: case 't':
485: smart_str_appendc(&buf, '\t');
486: break;
487: case 'n':
488: smart_str_appendc(&buf, '\n');
489: break;
490: case 'f':
491: smart_str_appendc(&buf, '\f');
492: break;
493: case 'r':
494: smart_str_appendc(&buf, '\r');
495: break;
496: default:
497: utf16_to_utf8(&buf, next_char);
498: break;
499: }
500: }
501: } else if (next_state == U2) {
502: utf16 = dehexchar(next_char) << 12;
503: } else if (next_state == U3) {
504: utf16 += dehexchar(next_char) << 8;
505: } else if (next_state == U4) {
506: utf16 += dehexchar(next_char) << 4;
507: } else if (next_state == ST && jp->state == U4) {
508: utf16 += dehexchar(next_char);
509: utf16_to_utf8(&buf, utf16);
510: }
511: } else if (type < IS_LONG && (next_class == C_DIGIT || next_class == C_ZERO)) {
512: type = IS_LONG;
513: smart_str_appendc(&buf, next_char);
514: } else if (type == IS_LONG && next_state == E1) {
515: type = IS_DOUBLE;
516: smart_str_appendc(&buf, next_char);
517: } else if (type < IS_DOUBLE && next_class == C_POINT) {
518: type = IS_DOUBLE;
519: smart_str_appendc(&buf, next_char);
520: } else if (type < IS_STRING && next_class == C_QUOTE) {
521: type = IS_STRING;
522: } else if (type < IS_BOOL && ((jp->state == T3 && next_state == OK) || (jp->state == F4 && next_state == OK))) {
523: type = IS_BOOL;
524: } else if (type < IS_NULL && jp->state == N3 && next_state == OK) {
525: type = IS_NULL;
526: } else if (type != IS_STRING && next_class > C_WHITE) {
527: utf16_to_utf8(&buf, next_char);
528: }
529: jp->state = next_state;
530: } else {
531: /*
532: Perform one of the predefined actions.
533: */
534: switch (next_state) {
535: /* empty } */
536: case -9:
537: if (!pop(jp, MODE_KEY)) {
538: FREE_BUFFERS();
539: return false;
540: }
541: jp->state = OK;
542: break;
543: /* } */
544: case -8:
545: if (type != -1 && jp->stack[jp->top] == MODE_OBJECT)
546: {
547: zval *mval;
548: smart_str_0(&buf);
549:
1.1.1.2 ! misho 550: json_create_zval(&mval, &buf, type, options);
1.1 misho 551:
552: if (!assoc) {
553: add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC);
554: Z_DELREF_P(mval);
555: } else {
556: add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
557: }
558: key.len = 0;
559: buf.len = 0;
560: JSON_RESET_TYPE();
561: }
562:
563:
564: if (!pop(jp, MODE_OBJECT)) {
565: FREE_BUFFERS();
566: return false;
567: }
568: jp->state = OK;
569: break;
570: /* ] */
571: case -7:
572: {
573: if (type != -1 && jp->stack[jp->top] == MODE_ARRAY)
574: {
575: zval *mval;
576: smart_str_0(&buf);
577:
1.1.1.2 ! misho 578: json_create_zval(&mval, &buf, type, options);
1.1 misho 579: add_next_index_zval(jp->the_zstack[jp->top], mval);
580: buf.len = 0;
581: JSON_RESET_TYPE();
582: }
583:
584: if (!pop(jp, MODE_ARRAY)) {
585: FREE_BUFFERS();
586: return false;
587: }
588: jp->state = OK;
589: }
590: break;
591: /* { */
592: case -6:
593: if (!push(jp, MODE_KEY)) {
594: FREE_BUFFERS();
595: return false;
596: }
597:
598: jp->state = OB;
599: if (jp->top > 0) {
600: zval *obj;
601:
602: if (jp->top == 1) {
603: obj = z;
604: } else {
605: ALLOC_INIT_ZVAL(obj);
606: }
607:
608: if (!assoc) {
609: object_init(obj);
610: } else {
611: array_init(obj);
612: }
613:
614: jp->the_zstack[jp->top] = obj;
615:
616: if (jp->top > 1) {
617: attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
618: }
619:
620: JSON_RESET_TYPE();
621: }
622:
623: break;
624: /* [ */
625: case -5:
626: if (!push(jp, MODE_ARRAY)) {
627: FREE_BUFFERS();
628: return false;
629: }
630: jp->state = AR;
631:
632: if (jp->top > 0) {
633: zval *arr;
634:
635: if (jp->top == 1) {
636: arr = z;
637: } else {
638: ALLOC_INIT_ZVAL(arr);
639: }
640:
641: array_init(arr);
642: jp->the_zstack[jp->top] = arr;
643:
644: if (jp->top > 1) {
645: attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
646: }
647:
648: JSON_RESET_TYPE();
649: }
650:
651: break;
652:
653: /* " */
654: case -4:
655: switch (jp->stack[jp->top]) {
656: case MODE_KEY:
657: jp->state = CO;
658: smart_str_0(&buf);
659: SWAP_BUFFERS(buf, key);
660: JSON_RESET_TYPE();
661: break;
662: case MODE_ARRAY:
663: case MODE_OBJECT:
664: jp->state = OK;
665: break;
666: case MODE_DONE:
667: if (type == IS_STRING) {
668: smart_str_0(&buf);
669: ZVAL_STRINGL(z, buf.c, buf.len, 1);
670: jp->state = OK;
671: break;
672: }
673: /* fall through if not IS_STRING */
674: default:
675: FREE_BUFFERS();
676: jp->error_code = PHP_JSON_ERROR_SYNTAX;
677: return false;
678: }
679: break;
680: /* , */
681: case -3:
682: {
683: zval *mval;
684:
685: if (type != -1 &&
686: (jp->stack[jp->top] == MODE_OBJECT ||
687: jp->stack[jp->top] == MODE_ARRAY))
688: {
689: smart_str_0(&buf);
1.1.1.2 ! misho 690: json_create_zval(&mval, &buf, type, options);
1.1 misho 691: }
692:
693: switch (jp->stack[jp->top]) {
694: case MODE_OBJECT:
695: if (pop(jp, MODE_OBJECT) && push(jp, MODE_KEY)) {
696: if (type != -1) {
697: if (!assoc) {
698: add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC);
699: Z_DELREF_P(mval);
700: } else {
701: add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
702: }
703: key.len = 0;
704: }
705: jp->state = KE;
706: }
707: break;
708: case MODE_ARRAY:
709: if (type != -1) {
710: add_next_index_zval(jp->the_zstack[jp->top], mval);
711: }
712: jp->state = VA;
713: break;
714: default:
715: FREE_BUFFERS();
716: jp->error_code = PHP_JSON_ERROR_SYNTAX;
717: return false;
718: }
719: buf.len = 0;
720: JSON_RESET_TYPE();
721: }
722: break;
723: /* : */
724: case -2:
725: if (pop(jp, MODE_KEY) && push(jp, MODE_OBJECT)) {
726: jp->state = VA;
727: break;
728: }
729: /*
730: syntax error
731: */
732: default:
733: {
734: jp->error_code = PHP_JSON_ERROR_SYNTAX;
735: FREE_BUFFERS();
736: return false;
737: }
738: }
739: }
740: }
741:
742: FREE_BUFFERS();
743: if (jp->state == OK && pop(jp, MODE_DONE)) {
744: return true;
745: }
746:
747: jp->error_code = PHP_JSON_ERROR_SYNTAX;
748: return false;
749: }
750:
751:
752: /*
753: * Local variables:
754: * tab-width: 4
755: * c-basic-offset: 4
756: * End:
757: * vim600: noet sw=4 ts=4
758: * vim<600: noet sw=4 ts=4
759: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>