diff options
Diffstat (limited to 'ext/json')
31 files changed, 5048 insertions, 1849 deletions
diff --git a/ext/json/CREDITS b/ext/json/CREDITS index 9bd7f44f21..a9a0dc70c4 100644 --- a/ext/json/CREDITS +++ b/ext/json/CREDITS @@ -1,2 +1,2 @@ JSON -Omar Kilani, Scott MacVicar +Jakub Zelenka, Omar Kilani, Scott MacVicar diff --git a/ext/json/JSON_parser.c b/ext/json/JSON_parser.c deleted file mode 100644 index dd832a7cbd..0000000000 --- a/ext/json/JSON_parser.c +++ /dev/null @@ -1,759 +0,0 @@ -/* JSON_parser.c */ - -/* 2005-12-30 */ - -/* -Copyright (c) 2005 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include <stdio.h> -#include "JSON_parser.h" - -/* Windows defines IN for documentation */ -#undef IN - -#define true 1 -#define false 0 -#define __ -1 /* the universal error code */ - -/* - Characters are mapped into these 31 character classes. This allows for - a significant reduction in the size of the state transition table. -*/ - -enum classes { - C_SPACE, /* space */ - C_WHITE, /* other whitespace */ - C_LCURB, /* { */ - C_RCURB, /* } */ - C_LSQRB, /* [ */ - C_RSQRB, /* ] */ - C_COLON, /* : */ - C_COMMA, /* , */ - C_QUOTE, /* " */ - C_BACKS, /* \ */ - C_SLASH, /* / */ - C_PLUS, /* + */ - C_MINUS, /* - */ - C_POINT, /* . */ - C_ZERO , /* 0 */ - C_DIGIT, /* 123456789 */ - C_LOW_A, /* a */ - C_LOW_B, /* b */ - C_LOW_C, /* c */ - C_LOW_D, /* d */ - C_LOW_E, /* e */ - C_LOW_F, /* f */ - C_LOW_L, /* l */ - C_LOW_N, /* n */ - C_LOW_R, /* r */ - C_LOW_S, /* s */ - C_LOW_T, /* t */ - C_LOW_U, /* u */ - C_ABCDF, /* ABCDF */ - C_E, /* E */ - C_ETC, /* everything else */ - NR_CLASSES -}; - -static const int ascii_class[128] = { -/* - This array maps the 128 ASCII characters into character classes. - The remaining Unicode characters should be mapped to C_ETC. - Non-whitespace control characters are errors. -*/ - __, __, __, __, __, __, __, __, - __, C_WHITE, C_WHITE, __, __, C_WHITE, __, __, - __, __, __, __, __, __, __, __, - __, __, __, __, __, __, __, __, - - C_SPACE, C_ETC, C_QUOTE, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, - C_ETC, C_ETC, C_ETC, C_PLUS, C_COMMA, C_MINUS, C_POINT, C_SLASH, - C_ZERO, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, C_DIGIT, - C_DIGIT, C_DIGIT, C_COLON, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, - - C_ETC, C_ABCDF, C_ABCDF, C_ABCDF, C_ABCDF, C_E, C_ABCDF, C_ETC, - C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, - C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, C_ETC, - C_ETC, C_ETC, C_ETC, C_LSQRB, C_BACKS, C_RSQRB, C_ETC, C_ETC, - - C_ETC, C_LOW_A, C_LOW_B, C_LOW_C, C_LOW_D, C_LOW_E, C_LOW_F, C_ETC, - C_ETC, C_ETC, C_ETC, C_ETC, C_LOW_L, C_ETC, C_LOW_N, C_ETC, - C_ETC, C_ETC, C_LOW_R, C_LOW_S, C_LOW_T, C_LOW_U, C_ETC, C_ETC, - C_ETC, C_ETC, C_ETC, C_LCURB, C_ETC, C_RCURB, C_ETC, C_ETC -}; - - -/* - The state codes. -*/ -enum states { - GO, /* start */ - OK, /* ok */ - OB, /* object */ - KE, /* key */ - CO, /* colon */ - VA, /* value */ - AR, /* array */ - ST, /* string */ - ES, /* escape */ - U1, /* u1 */ - U2, /* u2 */ - U3, /* u3 */ - U4, /* u4 */ - MI, /* minus */ - ZE, /* zero */ - IN, /* integer */ - FR, /* fraction */ - E1, /* e */ - E2, /* ex */ - E3, /* exp */ - T1, /* tr */ - T2, /* tru */ - T3, /* true */ - F1, /* fa */ - F2, /* fal */ - F3, /* fals */ - F4, /* false */ - N1, /* nu */ - N2, /* nul */ - N3, /* null */ - NR_STATES -}; - - -static const int state_transition_table[NR_STATES][NR_CLASSES] = { -/* - The state transition table takes the current state and the current symbol, - and returns either a new state or an action. An action is represented as a - negative number. A JSON text is accepted if at the end of the text the - state is OK and if the mode is MODE_DONE. - - white 1-9 ABCDF etc - space | { } [ ] : , " \ / + - . 0 | a b c d e f l n r s t u | E |*/ -/*start GO*/ {GO,GO,-6,__,-5,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*ok OK*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*object OB*/ {OB,OB,__,-9,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*key KE*/ {KE,KE,__,__,__,__,__,__,ST,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*colon CO*/ {CO,CO,__,__,__,__,-2,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*value VA*/ {VA,VA,-6,__,-5,__,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__}, -/*array AR*/ {AR,AR,-6,__,-5,-7,__,__,ST,__,__,__,MI,__,ZE,IN,__,__,__,__,__,F1,__,N1,__,__,T1,__,__,__,__}, -/*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}, -/*escape ES*/ {__,__,__,__,__,__,__,__,ST,ST,ST,__,__,__,__,__,__,ST,__,__,__,ST,__,ST,ST,__,ST,U1,__,__,__}, -/*u1 U1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U2,U2,U2,U2,U2,U2,U2,U2,__,__,__,__,__,__,U2,U2,__}, -/*u2 U2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U3,U3,U3,U3,U3,U3,U3,U3,__,__,__,__,__,__,U3,U3,__}, -/*u3 U3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,U4,U4,U4,U4,U4,U4,U4,U4,__,__,__,__,__,__,U4,U4,__}, -/*u4 U4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ST,ST,ST,ST,ST,ST,ST,ST,__,__,__,__,__,__,ST,ST,__}, -/*minus MI*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,ZE,IN,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*zero ZE*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,__,__,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__}, -/*int IN*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,FR,IN,IN,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__}, -/*frac FR*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,FR,FR,__,__,__,__,E1,__,__,__,__,__,__,__,__,E1,__}, -/*e E1*/ {__,__,__,__,__,__,__,__,__,__,__,E2,E2,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*ex E2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*exp E3*/ {OK,OK,__,-8,__,-7,__,-3,__,__,__,__,__,__,E3,E3,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*tr T1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T2,__,__,__,__,__,__}, -/*tru T2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,T3,__,__,__}, -/*true T3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__}, -/*fa F1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F2,__,__,__,__,__,__,__,__,__,__,__,__,__,__}, -/*fal F2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F3,__,__,__,__,__,__,__,__}, -/*fals F3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,F4,__,__,__,__,__}, -/*false F4*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__,__,__}, -/*nu N1*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N2,__,__,__}, -/*nul N2*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,N3,__,__,__,__,__,__,__,__}, -/*null N3*/ {__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,OK,__,__,__,__,__,__,__,__}, -}; - - -/* - These modes can be pushed on the stack. -*/ -enum modes { - MODE_ARRAY, - MODE_DONE, - MODE_KEY, - MODE_OBJECT, -}; - - -/* - Push a mode onto the stack. Return false if there is overflow. -*/ -static int -push(JSON_parser jp, int mode) -{ - jp->top += 1; - if (jp->top >= jp->depth) { - jp->error_code = PHP_JSON_ERROR_DEPTH; - return false; - } - jp->stack[jp->top] = mode; - return true; -} - - -/* - Pop the stack, assuring that the current mode matches the expectation. - Return false if there is underflow or if the modes mismatch. -*/ -static int -pop(JSON_parser jp, int mode) -{ - if (jp->top < 0 || jp->stack[jp->top] != mode) { - jp->error_code = PHP_JSON_ERROR_STATE_MISMATCH; - return false; - } - jp->top -= 1; - return true; -} - -/* - new_JSON_checker starts the checking process by constructing a JSON_checker - object. It takes a depth parameter that restricts the level of maximum - nesting. - - To continue the process, call JSON_checker_char for each character in the - JSON text, and then call JSON_checker_done to obtain the final result. - These functions are fully reentrant. - - The JSON_checker object will be deleted by JSON_checker_done. - JSON_checker_char will delete the JSON_checker object if it sees an error. -*/ -JSON_parser -new_JSON_parser(int depth) -{ - JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct)); - jp->state = GO; - jp->depth = depth; - jp->top = -1; - jp->error_code = PHP_JSON_ERROR_NONE; - jp->stack = (int*)ecalloc(depth, sizeof(int)); - if (depth > JSON_PARSER_DEFAULT_DEPTH) { - jp->the_zstack = (zval **)safe_emalloc(depth, sizeof(zval), 0); - } else { - jp->the_zstack = &jp->the_static_zstack[0]; - } - push(jp, MODE_DONE); - return jp; -} - -/* - Delete the JSON_parser object. -*/ -int -free_JSON_parser(JSON_parser jp) -{ - efree((void*)jp->stack); - if (jp->the_zstack != &jp->the_static_zstack[0]) { - efree(jp->the_zstack); - } - efree((void*)jp); - return false; -} - -static int dehexchar(char c) -{ - if (c >= '0' && c <= '9') - { - return c - '0'; - } - else if (c >= 'A' && c <= 'F') - { - return c - ('A' - 10); - } - else if (c >= 'a' && c <= 'f') - { - return c - ('a' - 10); - } - else - { - return -1; - } -} - - -static void json_create_zval(zval **z, smart_str *buf, int type, int options) -{ - ALLOC_INIT_ZVAL(*z); - - if (type == IS_LONG) - { - zend_bool bigint = 0; - - if (buf->c[0] == '-') { - buf->len--; - } - - if (buf->len >= MAX_LENGTH_OF_LONG - 1) { - if (buf->len == MAX_LENGTH_OF_LONG - 1) { - int cmp = strcmp(buf->c + (buf->c[0] == '-'), long_min_digits); - - if (!(cmp < 0 || (cmp == 0 && buf->c[0] == '-'))) { - bigint = 1; - } - } else { - bigint = 1; - } - } - - if (bigint) { - /* value too large to represent as a long */ - if (options & PHP_JSON_BIGINT_AS_STRING) { - if (buf->c[0] == '-') { - /* Restore last char consumed above */ - buf->len++; - } - goto use_string; - } else { - goto use_double; - } - } - - ZVAL_LONG(*z, strtol(buf->c, NULL, 10)); - } - else if (type == IS_DOUBLE) - { -use_double: - ZVAL_DOUBLE(*z, zend_strtod(buf->c, NULL)); - } - else if (type == IS_STRING) - { -use_string: - ZVAL_STRINGL(*z, buf->c, buf->len, 1); - } - else if (type == IS_BOOL) - { - ZVAL_BOOL(*z, (*(buf->c) == 't')); - } - else /* type == IS_NULL) || type unknown */ - { - ZVAL_NULL(*z); - } -} - - -static void utf16_to_utf8(smart_str *buf, unsigned short utf16) -{ - if (utf16 < 0x80) - { - smart_str_appendc(buf, (unsigned char) utf16); - } - else if (utf16 < 0x800) - { - smart_str_appendc(buf, 0xc0 | (utf16 >> 6)); - smart_str_appendc(buf, 0x80 | (utf16 & 0x3f)); - } - else if ((utf16 & 0xfc00) == 0xdc00 - && buf->len >= 3 - && ((unsigned char) buf->c[buf->len - 3]) == 0xed - && ((unsigned char) buf->c[buf->len - 2] & 0xf0) == 0xa0 - && ((unsigned char) buf->c[buf->len - 1] & 0xc0) == 0x80) - { - /* found surrogate pair */ - unsigned long utf32; - - utf32 = (((buf->c[buf->len - 2] & 0xf) << 16) - | ((buf->c[buf->len - 1] & 0x3f) << 10) - | (utf16 & 0x3ff)) + 0x10000; - buf->len -= 3; - - smart_str_appendc(buf, (unsigned char) (0xf0 | (utf32 >> 18))); - smart_str_appendc(buf, 0x80 | ((utf32 >> 12) & 0x3f)); - smart_str_appendc(buf, 0x80 | ((utf32 >> 6) & 0x3f)); - smart_str_appendc(buf, 0x80 | (utf32 & 0x3f)); - } - else - { - smart_str_appendc(buf, 0xe0 | (utf16 >> 12)); - smart_str_appendc(buf, 0x80 | ((utf16 >> 6) & 0x3f)); - smart_str_appendc(buf, 0x80 | (utf16 & 0x3f)); - } -} - -static void attach_zval(JSON_parser jp, int up, int cur, smart_str *key, int assoc TSRMLS_DC) -{ - zval *root = jp->the_zstack[up]; - zval *child = jp->the_zstack[cur]; - int up_mode = jp->stack[up]; - - if (up_mode == MODE_ARRAY) - { - add_next_index_zval(root, child); - } - else if (up_mode == MODE_OBJECT) - { - if (!assoc) - { - add_property_zval_ex(root, (key->len ? key->c : "_empty_"), (key->len ? (key->len + 1) : sizeof("_empty_")), child TSRMLS_CC); - Z_DELREF_P(child); - } - else - { - add_assoc_zval_ex(root, (key->len ? key->c : ""), (key->len ? (key->len + 1) : sizeof("")), child); - } - key->len = 0; - } -} - - -#define FREE_BUFFERS() smart_str_free(&buf); smart_str_free(&key); -#define SWAP_BUFFERS(from, to) do { \ - char *t1 = from.c; \ - int t2 = from.a; \ - from.c = to.c; \ - from.a = to.a; \ - to.c = t1; \ - to.a = t2; \ - to.len = from.len; \ - from.len = 0; \ - } while(0); -#define JSON_RESET_TYPE() type = -1; - -/* - The JSON_parser takes a UTF-16 encoded string and determines if it is a - syntactically correct JSON text. Along the way, it creates a PHP variable. - - It is implemented as a Pushdown Automaton; that means it is a finite state - machine with a stack. -*/ -int -parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC) -{ - int next_char; /* the next character */ - int next_class; /* the next character class */ - int next_state; /* the next state */ - int the_index; - int assoc = options & PHP_JSON_OBJECT_AS_ARRAY; - - smart_str buf = {0}; - smart_str key = {0}; - - unsigned short utf16 = 0; - int type; - - JSON_RESET_TYPE(); - - for (the_index = 0; the_index < length; the_index += 1) { - next_char = utf16_json[the_index]; - if (next_char >= 128) { - next_class = C_ETC; - } else { - next_class = ascii_class[next_char]; - if (next_class <= __) { - jp->error_code = PHP_JSON_ERROR_CTRL_CHAR; - FREE_BUFFERS(); - return false; - } - } -/* - Get the next state from the transition table. -*/ - next_state = state_transition_table[jp->state][next_class]; - if (next_state >= 0) { -/* - Change the state and iterate -*/ - if (type == IS_STRING) { - if (next_state == ST && jp->state != U4) { - if (jp->state != ES) { - utf16_to_utf8(&buf, next_char); - } else { - switch (next_char) { - case 'b': - smart_str_appendc(&buf, '\b'); - break; - case 't': - smart_str_appendc(&buf, '\t'); - break; - case 'n': - smart_str_appendc(&buf, '\n'); - break; - case 'f': - smart_str_appendc(&buf, '\f'); - break; - case 'r': - smart_str_appendc(&buf, '\r'); - break; - default: - utf16_to_utf8(&buf, next_char); - break; - } - } - } else if (next_state == U2) { - utf16 = dehexchar(next_char) << 12; - } else if (next_state == U3) { - utf16 += dehexchar(next_char) << 8; - } else if (next_state == U4) { - utf16 += dehexchar(next_char) << 4; - } else if (next_state == ST && jp->state == U4) { - utf16 += dehexchar(next_char); - utf16_to_utf8(&buf, utf16); - } - } else if (type < IS_LONG && (next_class == C_DIGIT || next_class == C_ZERO)) { - type = IS_LONG; - smart_str_appendc(&buf, next_char); - } else if (type == IS_LONG && next_state == E1) { - type = IS_DOUBLE; - smart_str_appendc(&buf, next_char); - } else if (type < IS_DOUBLE && next_class == C_POINT) { - type = IS_DOUBLE; - smart_str_appendc(&buf, next_char); - } else if (type < IS_STRING && next_class == C_QUOTE) { - type = IS_STRING; - } else if (type < IS_BOOL && ((jp->state == T3 && next_state == OK) || (jp->state == F4 && next_state == OK))) { - type = IS_BOOL; - } else if (type < IS_NULL && jp->state == N3 && next_state == OK) { - type = IS_NULL; - } else if (type != IS_STRING && next_class > C_WHITE) { - utf16_to_utf8(&buf, next_char); - } - jp->state = next_state; - } else { -/* - Perform one of the predefined actions. -*/ - switch (next_state) { -/* empty } */ - case -9: - if (!pop(jp, MODE_KEY)) { - FREE_BUFFERS(); - return false; - } - jp->state = OK; - break; -/* } */ - case -8: - if (type != -1 && jp->stack[jp->top] == MODE_OBJECT) - { - zval *mval; - smart_str_0(&buf); - - json_create_zval(&mval, &buf, type, options); - - if (!assoc) { - add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC); - Z_DELREF_P(mval); - } else { - add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval); - } - key.len = 0; - buf.len = 0; - JSON_RESET_TYPE(); - } - - - if (!pop(jp, MODE_OBJECT)) { - FREE_BUFFERS(); - return false; - } - jp->state = OK; - break; -/* ] */ - case -7: - { - if (type != -1 && jp->stack[jp->top] == MODE_ARRAY) - { - zval *mval; - smart_str_0(&buf); - - json_create_zval(&mval, &buf, type, options); - add_next_index_zval(jp->the_zstack[jp->top], mval); - buf.len = 0; - JSON_RESET_TYPE(); - } - - if (!pop(jp, MODE_ARRAY)) { - FREE_BUFFERS(); - return false; - } - jp->state = OK; - } - break; -/* { */ - case -6: - if (!push(jp, MODE_KEY)) { - FREE_BUFFERS(); - return false; - } - - jp->state = OB; - if (jp->top > 0) { - zval *obj; - - if (jp->top == 1) { - obj = z; - } else { - ALLOC_INIT_ZVAL(obj); - } - - if (!assoc) { - object_init(obj); - } else { - array_init(obj); - } - - jp->the_zstack[jp->top] = obj; - - if (jp->top > 1) { - attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC); - } - - JSON_RESET_TYPE(); - } - - break; -/* [ */ - case -5: - if (!push(jp, MODE_ARRAY)) { - FREE_BUFFERS(); - return false; - } - jp->state = AR; - - if (jp->top > 0) { - zval *arr; - - if (jp->top == 1) { - arr = z; - } else { - ALLOC_INIT_ZVAL(arr); - } - - array_init(arr); - jp->the_zstack[jp->top] = arr; - - if (jp->top > 1) { - attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC); - } - - JSON_RESET_TYPE(); - } - - break; - -/* " */ - case -4: - switch (jp->stack[jp->top]) { - case MODE_KEY: - jp->state = CO; - smart_str_0(&buf); - SWAP_BUFFERS(buf, key); - JSON_RESET_TYPE(); - break; - case MODE_ARRAY: - case MODE_OBJECT: - jp->state = OK; - break; - case MODE_DONE: - if (type == IS_STRING) { - smart_str_0(&buf); - ZVAL_STRINGL(z, buf.c, buf.len, 1); - jp->state = OK; - break; - } - /* fall through if not IS_STRING */ - default: - FREE_BUFFERS(); - jp->error_code = PHP_JSON_ERROR_SYNTAX; - return false; - } - break; -/* , */ - case -3: - { - zval *mval; - - if (type != -1 && - (jp->stack[jp->top] == MODE_OBJECT || - jp->stack[jp->top] == MODE_ARRAY)) - { - smart_str_0(&buf); - json_create_zval(&mval, &buf, type, options); - } - - switch (jp->stack[jp->top]) { - case MODE_OBJECT: - if (pop(jp, MODE_OBJECT) && push(jp, MODE_KEY)) { - if (type != -1) { - if (!assoc) { - add_property_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : "_empty_"), (key.len ? (key.len + 1) : sizeof("_empty_")), mval TSRMLS_CC); - Z_DELREF_P(mval); - } else { - add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval); - } - key.len = 0; - } - jp->state = KE; - } - break; - case MODE_ARRAY: - if (type != -1) { - add_next_index_zval(jp->the_zstack[jp->top], mval); - } - jp->state = VA; - break; - default: - FREE_BUFFERS(); - jp->error_code = PHP_JSON_ERROR_SYNTAX; - return false; - } - buf.len = 0; - JSON_RESET_TYPE(); - } - break; -/* : */ - case -2: - if (pop(jp, MODE_KEY) && push(jp, MODE_OBJECT)) { - jp->state = VA; - break; - } -/* - syntax error -*/ - default: - { - jp->error_code = PHP_JSON_ERROR_SYNTAX; - FREE_BUFFERS(); - return false; - } - } - } - } - - FREE_BUFFERS(); - if (jp->state == OK && pop(jp, MODE_DONE)) { - return true; - } - - jp->error_code = PHP_JSON_ERROR_SYNTAX; - return false; -} - - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 - * vim<600: noet sw=4 ts=4 - */ diff --git a/ext/json/JSON_parser.h b/ext/json/JSON_parser.h deleted file mode 100644 index 8671765b4d..0000000000 --- a/ext/json/JSON_parser.h +++ /dev/null @@ -1,43 +0,0 @@ -/* JSON_parser.h */ - -#ifndef JSON_PARSER_H -#define JSON_PARSER_H - -#include "php.h" -#include "ext/standard/php_smart_str.h" -#include "php_json.h" - -#define JSON_PARSER_DEFAULT_DEPTH 512 - -typedef struct JSON_parser_struct { - int state; - int depth; - int top; - int error_code; - int* stack; - zval **the_zstack; - zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH]; -} * JSON_parser; - -enum error_codes { - PHP_JSON_ERROR_NONE = 0, - PHP_JSON_ERROR_DEPTH, - PHP_JSON_ERROR_STATE_MISMATCH, - PHP_JSON_ERROR_CTRL_CHAR, - PHP_JSON_ERROR_SYNTAX, - PHP_JSON_ERROR_UTF8, - PHP_JSON_ERROR_RECURSION, - PHP_JSON_ERROR_INF_OR_NAN, - PHP_JSON_ERROR_UNSUPPORTED_TYPE -}; - -extern JSON_parser new_JSON_parser(int depth); -extern int parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC); -extern int free_JSON_parser(JSON_parser jp); - -static inline int parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int assoc TSRMLS_DC) -{ - return parse_JSON_ex(jp, z, utf16_json, length, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0 TSRMLS_CC); -} - -#endif diff --git a/ext/json/Makefile.frag b/ext/json/Makefile.frag new file mode 100644 index 0000000000..cb26acabc7 --- /dev/null +++ b/ext/json/Makefile.frag @@ -0,0 +1,5 @@ +$(srcdir)/json_scanner.c: $(srcdir)/json_scanner.re + $(RE2C) -t $(srcdir)/php_json_scanner_defs.h --no-generation-date -bci -o $@ $(srcdir)/json_scanner.re + +$(srcdir)/json_parser.tab.c: $(srcdir)/json_parser.y + $(YACC) --defines -l $(srcdir)/json_parser.y -o $@ diff --git a/ext/json/README b/ext/json/README index d680b0c592..4daa800ff3 100644 --- a/ext/json/README +++ b/ext/json/README @@ -1,76 +1,16 @@ -json 1.2.0 +JSON ========== -This extension implements the JavaScript Object Notation (JSON) -data-interchange format as specified in [0]. - -Two functions are implemented: encoding and decoding. The decoding -is handled by a parser based on JSON_checker[1] by Douglas Crockford. - - -Function overview ------------------ - - string json_encode ( mixed value ) - -json_encode returns a string containing the JSON representation of value. -value can be any type except a resource. - - mixed json_decode ( string json, [bool assoc] ) - -json_decode takes a JSON string and converts it into a PHP variable. -When assoc is given, and evaluates to TRUE, json_decode() will return -any objects as associative arrays. - - -Example usage -------------- -$arr = array("a"=>1,"b"=>2,"c"=>3,"d"=>4,"e"=>5); -echo json_encode($arr); - ----> {"a":1,"b":2,"c":3,"d":4,"e":5} - -$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}'; -var_dump(json_decode($json)); - ----> object(stdClass)#1 (5) { - ["a"]=> - int(1) - ["b"]=> - int(2) - ["c"]=> - int(3) - ["d"]=> - int(4) - ["e"]=> - int(5) - } - -$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}'; -var_dump(json_decode($json, true)); - ----> array(5) { - ["a"]=> - int(1) - ["b"]=> - int(2) - ["c"]=> - int(3) - ["d"]=> - int(4) - ["e"]=> - int(5) - } - - -Authors -------- - -Omar Kilani <omar@php.net> +This extension implements the JavaScript Object Notation (JSON) +data-interchange format as specified in RFC 7159 +The parser is implemented using re2c and Bison. The used versions +of both tools for generating files in the repository are following: ---- +re2c 0.14.3 +Bison 3.0.4 -[0] http://www.crockford.com/JSON/draft-jsonorg-json-00.txt -[1] http://www.crockford.com/JSON/JSON_checker/ +It is recommended to do all contributions to the JSON extension +through the Github Pull Requests and preferably ping @bukka +who maintains the extension. diff --git a/ext/json/config.m4 b/ext/json/config.m4 index 51cc5087c8..fb87a93992 100644 --- a/ext/json/config.m4 +++ b/ext/json/config.m4 @@ -9,7 +9,13 @@ if test "$PHP_JSON" != "no"; then AC_DEFINE([HAVE_JSON],1 ,[whether to enable JavaScript Object Serialization support]) AC_HEADER_STDC - PHP_NEW_EXTENSION(json, json.c JSON_parser.c, $ext_shared) +PHP_NEW_EXTENSION(json, + json.c \ + json_encoder.c \ + json_parser.tab.c \ + json_scanner.c, + $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_INSTALL_HEADERS([ext/json], [php_json.h]) + PHP_ADD_MAKEFILE_FRAGMENT() PHP_SUBST(JSON_SHARED_LIBADD) fi diff --git a/ext/json/config.w32 b/ext/json/config.w32 index 6e318c5d0d..c37d9a9025 100644 --- a/ext/json/config.w32 +++ b/ext/json/config.w32 @@ -4,8 +4,19 @@ ARG_ENABLE("json", "JavaScript Object Serialization support", "yes"); if (PHP_JSON != "no") { - EXTENSION('json', 'json.c', PHP_JSON_SHARED, ""); - ADD_SOURCES(configure_module_dirname, "JSON_parser.c", "json"); + EXTENSION('json', 'json.c', PHP_JSON_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); + + if (!FSO.FileExists("ext/json/json_scanner.c")) { + STDOUT.WriteLine("Generating ext/json/json_scanner.c"); + STDOUT.WriteLine(execute(PATH_PROG("re2c") + " -t ext/json/php_json_scanner_defs.h --no-generation-date -bci -o ext/json/json_scanner.c ext/json/json_scanner.re")); + } + if (!FSO.FileExists("ext/json/json_parser.tab.c")) { + STDOUT.WriteLine("Generating ext/json/json_parser.tab.c"); + STDOUT.WriteLine(execute(PATH_PROG("bison") + " --defines -l ext/json/json_parser.y -o ext/json/json_parser.tab.c")); + } + + ADD_SOURCES(configure_module_dirname, "json_encoder.c json_parser.tab.c json_scanner.c", "json"); + PHP_INSTALL_HEADERS("ext/json/", "php_json.h"); } diff --git a/ext/json/json.c b/ext/json/json.c index 1e37e50ccb..01319d5f5b 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ @@ -13,6 +13,7 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Omar Kilani <omar@php.net> | + | Jakub Zelenka <bukka@php.net> | +----------------------------------------------------------------------+ */ @@ -26,9 +27,10 @@ #include "php_ini.h" #include "ext/standard/info.h" #include "ext/standard/html.h" -#include "ext/standard/php_smart_str.h" -#include "JSON_parser.h" +#include "zend_smart_str.h" #include "php_json.h" +#include "php_json_encoder.h" +#include "php_json_parser.h" #include <zend_exceptions.h> #include <float.h> @@ -45,11 +47,9 @@ static PHP_FUNCTION(json_decode); static PHP_FUNCTION(json_last_error); static PHP_FUNCTION(json_last_error_msg); -static const char digits[] = "0123456789abcdef"; - PHP_JSON_API zend_class_entry *php_json_serializable_ce; -ZEND_DECLARE_MODULE_GLOBALS(json) +PHP_JSON_API ZEND_DECLARE_MODULE_GLOBALS(json) /* {{{ arginfo */ ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1) @@ -93,38 +93,47 @@ static const zend_function_entry json_serializable_interface[] = { }; /* }}} */ +/* Register constant for options and errors */ +#define PHP_JSON_REGISTER_CONSTANT(_name, _value) \ + REGISTER_LONG_CONSTANT(_name, _value, CONST_CS | CONST_PERSISTENT); + /* {{{ MINIT */ static PHP_MINIT_FUNCTION(json) { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "JsonSerializable", json_serializable_interface); - php_json_serializable_ce = zend_register_internal_interface(&ce TSRMLS_CC); - - REGISTER_LONG_CONSTANT("JSON_HEX_TAG", PHP_JSON_HEX_TAG, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_HEX_AMP", PHP_JSON_HEX_AMP, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION, CONST_CS | CONST_PERSISTENT); - - REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT); - - REGISTER_LONG_CONSTANT("JSON_OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY, CONST_CS | CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("JSON_BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING, CONST_CS | CONST_PERSISTENT); + php_json_serializable_ce = zend_register_internal_interface(&ce); + + /* options for json_encode */ + PHP_JSON_REGISTER_CONSTANT("JSON_HEX_TAG", PHP_JSON_HEX_TAG); + PHP_JSON_REGISTER_CONSTANT("JSON_HEX_AMP", PHP_JSON_HEX_AMP); + PHP_JSON_REGISTER_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS); + PHP_JSON_REGISTER_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT); + PHP_JSON_REGISTER_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT); + PHP_JSON_REGISTER_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK); + PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES); + PHP_JSON_REGISTER_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT); + PHP_JSON_REGISTER_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE); + PHP_JSON_REGISTER_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR); + PHP_JSON_REGISTER_CONSTANT("JSON_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION); + + /* options for json_decode */ + PHP_JSON_REGISTER_CONSTANT("JSON_OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY); + PHP_JSON_REGISTER_CONSTANT("JSON_BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING); + + /* json error constants */ + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_INVALID_PROPERTY_NAME", PHP_JSON_ERROR_INVALID_PROPERTY_NAME); + PHP_JSON_REGISTER_CONSTANT("JSON_ERROR_UTF16", PHP_JSON_ERROR_UTF16); return SUCCESS; } @@ -134,9 +143,12 @@ static PHP_MINIT_FUNCTION(json) */ static PHP_GINIT_FUNCTION(json) { +#if defined(COMPILE_DL_JSON) && defined(ZTS) + ZEND_TSRMLS_CACHE_UPDATE(); +#endif json_globals->encoder_depth = 0; json_globals->error_code = 0; - json_globals->encode_max_depth = 0; + json_globals->encode_max_depth = PHP_JSON_PARSER_DEFAULT_DEPTH; } /* }}} */ @@ -162,6 +174,9 @@ zend_module_entry json_module_entry = { /* }}} */ #ifdef COMPILE_DL_JSON +#ifdef ZTS +ZEND_TSRMLS_CACHE_DEFINE() +#endif ZEND_GET_MODULE(json) #endif @@ -176,653 +191,51 @@ static PHP_MINFO_FUNCTION(json) } /* }}} */ -static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC); - -static int json_determine_array_type(zval **val TSRMLS_DC) /* {{{ */ -{ - int i; - HashTable *myht = HASH_OF(*val); - - i = myht ? zend_hash_num_elements(myht) : 0; - if (i > 0) { - char *key; - ulong index, idx; - uint key_len; - HashPosition pos; - - zend_hash_internal_pointer_reset_ex(myht, &pos); - idx = 0; - for (;; zend_hash_move_forward_ex(myht, &pos)) { - i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); - if (i == HASH_KEY_NON_EXISTENT) { - break; - } - - if (i == HASH_KEY_IS_STRING) { - return 1; - } else { - if (index != idx) { - return 1; - } - } - idx++; - } - } - - return PHP_JSON_OUTPUT_ARRAY; -} -/* }}} */ - -/* {{{ Pretty printing support functions */ - -static inline void json_pretty_print_char(smart_str *buf, int options, char c TSRMLS_DC) /* {{{ */ -{ - if (options & PHP_JSON_PRETTY_PRINT) { - smart_str_appendc(buf, c); - } -} -/* }}} */ - -static inline void json_pretty_print_indent(smart_str *buf, int options TSRMLS_DC) /* {{{ */ +PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options) /* {{{ */ { - int i; - - if (options & PHP_JSON_PRETTY_PRINT) { - for (i = 0; i < JSON_G(encoder_depth); ++i) { - smart_str_appendl(buf, " ", 4); - } - } + php_json_encode_zval(buf, val, options); } /* }}} */ -/* }}} */ - -static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */ +PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, size_t str_len, zend_long options, zend_long depth) /* {{{ */ { - int i, r, need_comma = 0; - HashTable *myht; - - if (Z_TYPE_PP(val) == IS_ARRAY) { - myht = HASH_OF(*val); - r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC); - } else { - myht = Z_OBJPROP_PP(val); - r = PHP_JSON_OUTPUT_OBJECT; - } - - if (myht && myht->nApplyCount > 1) { - JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; - smart_str_appendl(buf, "null", 4); - return; - } - - if (r == PHP_JSON_OUTPUT_ARRAY) { - smart_str_appendc(buf, '['); - } else { - smart_str_appendc(buf, '{'); - } + php_json_parser parser; - ++JSON_G(encoder_depth); - - i = myht ? zend_hash_num_elements(myht) : 0; - - if (i > 0) - { - char *key; - zval **data; - ulong index; - uint key_len; - HashPosition pos; - HashTable *tmp_ht; - - zend_hash_internal_pointer_reset_ex(myht, &pos); - for (;; zend_hash_move_forward_ex(myht, &pos)) { - i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); - if (i == HASH_KEY_NON_EXISTENT) - break; - - if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) { - tmp_ht = HASH_OF(*data); - if (tmp_ht) { - tmp_ht->nApplyCount++; - } - - if (r == PHP_JSON_OUTPUT_ARRAY) { - if (need_comma) { - smart_str_appendc(buf, ','); - } else { - need_comma = 1; - } - - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - json_pretty_print_indent(buf, options TSRMLS_CC); - php_json_encode(buf, *data, options TSRMLS_CC); - } else if (r == PHP_JSON_OUTPUT_OBJECT) { - if (i == HASH_KEY_IS_STRING) { - if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) { - /* Skip protected and private members. */ - if (tmp_ht) { - tmp_ht->nApplyCount--; - } - continue; - } - - if (need_comma) { - smart_str_appendc(buf, ','); - } else { - need_comma = 1; - } - - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - json_pretty_print_indent(buf, options TSRMLS_CC); - - json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC); - smart_str_appendc(buf, ':'); - - json_pretty_print_char(buf, options, ' ' TSRMLS_CC); - - php_json_encode(buf, *data, options TSRMLS_CC); - } else { - if (need_comma) { - smart_str_appendc(buf, ','); - } else { - need_comma = 1; - } - - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - json_pretty_print_indent(buf, options TSRMLS_CC); - - smart_str_appendc(buf, '"'); - smart_str_append_long(buf, (long) index); - smart_str_appendc(buf, '"'); - smart_str_appendc(buf, ':'); - - json_pretty_print_char(buf, options, ' ' TSRMLS_CC); - - php_json_encode(buf, *data, options TSRMLS_CC); - } - } - - if (tmp_ht) { - tmp_ht->nApplyCount--; - } - } - } - } - - if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) { - JSON_G(error_code) = PHP_JSON_ERROR_DEPTH; - } - --JSON_G(encoder_depth); - - /* Only keep closing bracket on same line for empty arrays/objects */ - if (need_comma) { - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - json_pretty_print_indent(buf, options TSRMLS_CC); - } - - if (r == PHP_JSON_OUTPUT_ARRAY) { - smart_str_appendc(buf, ']'); - } else { - smart_str_appendc(buf, '}'); - } -} -/* }}} */ - -static int json_utf8_to_utf16(unsigned short *utf16, char utf8[], int len) /* {{{ */ -{ - size_t pos = 0, us; - int j, status; - - if (utf16) { - /* really convert the utf8 string */ - for (j=0 ; pos < len ; j++) { - us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status); - if (status != SUCCESS) { - return -1; - } - /* From http://en.wikipedia.org/wiki/UTF16 */ - if (us >= 0x10000) { - us -= 0x10000; - utf16[j++] = (unsigned short)((us >> 10) | 0xd800); - utf16[j] = (unsigned short)((us & 0x3ff) | 0xdc00); - } else { - utf16[j] = (unsigned short)us; - } - } - } else { - /* Only check if utf8 string is valid, and compute utf16 length */ - for (j=0 ; pos < len ; j++) { - us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status); - if (status != SUCCESS) { - return -1; - } - if (us >= 0x10000) { - j++; - } - } - } - return j; -} -/* }}} */ - - -static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */ -{ - int pos = 0, ulen = 0; - unsigned short us; - unsigned short *utf16; - size_t newlen; - - if (len == 0) { - smart_str_appendl(buf, "\"\"", 2); - return; - } - - if (options & PHP_JSON_NUMERIC_CHECK) { - double d; - int type; - long p; - - if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { - if (type == IS_LONG) { - smart_str_append_long(buf, p); - return; - } else if (type == IS_DOUBLE && !zend_isinf(d) && !zend_isnan(d)) { - char num[NUM_BUF_SIZE]; - int l; - - php_gcvt(d, EG(precision), '.', 'e', (char *)num); - l = strlen(num); - if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && l < NUM_BUF_SIZE - 2) { - num[l++] = '.'; - num[l++] = '0'; - num[l] = '\0'; - } - smart_str_appendl(buf, num, l); - return; - } - } - - } - - utf16 = (options & PHP_JSON_UNESCAPED_UNICODE) ? NULL : (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0); - ulen = json_utf8_to_utf16(utf16, s, len); - if (ulen <= 0) { - if (utf16) { - efree(utf16); - } - if (ulen < 0) { - JSON_G(error_code) = PHP_JSON_ERROR_UTF8; - smart_str_appendl(buf, "null", 4); - } else { - smart_str_appendl(buf, "\"\"", 2); - } - return; - } - if (!(options & PHP_JSON_UNESCAPED_UNICODE)) { - len = ulen; - } + php_json_parser_init(&parser, return_value, str, str_len, (int)options, (int)depth); - /* pre-allocate for string length plus 2 quotes */ - smart_str_alloc(buf, len+2, 0); - smart_str_appendc(buf, '"'); - - while (pos < len) - { - us = (options & PHP_JSON_UNESCAPED_UNICODE) ? s[pos++] : utf16[pos++]; - - switch (us) - { - case '"': - if (options & PHP_JSON_HEX_QUOT) { - smart_str_appendl(buf, "\\u0022", 6); - } else { - smart_str_appendl(buf, "\\\"", 2); - } - break; - - case '\\': - smart_str_appendl(buf, "\\\\", 2); - break; - - case '/': - if (options & PHP_JSON_UNESCAPED_SLASHES) { - smart_str_appendc(buf, '/'); - } else { - smart_str_appendl(buf, "\\/", 2); - } - break; - - case '\b': - smart_str_appendl(buf, "\\b", 2); - break; - - case '\f': - smart_str_appendl(buf, "\\f", 2); - break; - - case '\n': - smart_str_appendl(buf, "\\n", 2); - break; - - case '\r': - smart_str_appendl(buf, "\\r", 2); - break; - - case '\t': - smart_str_appendl(buf, "\\t", 2); - break; - - case '<': - if (options & PHP_JSON_HEX_TAG) { - smart_str_appendl(buf, "\\u003C", 6); - } else { - smart_str_appendc(buf, '<'); - } - break; - - case '>': - if (options & PHP_JSON_HEX_TAG) { - smart_str_appendl(buf, "\\u003E", 6); - } else { - smart_str_appendc(buf, '>'); - } - break; - - case '&': - if (options & PHP_JSON_HEX_AMP) { - smart_str_appendl(buf, "\\u0026", 6); - } else { - smart_str_appendc(buf, '&'); - } - break; - - case '\'': - if (options & PHP_JSON_HEX_APOS) { - smart_str_appendl(buf, "\\u0027", 6); - } else { - smart_str_appendc(buf, '\''); - } - break; - - default: - if (us >= ' ' && ((options & PHP_JSON_UNESCAPED_UNICODE) || (us & 127) == us)) { - smart_str_appendc(buf, (unsigned char) us); - } else { - smart_str_appendl(buf, "\\u", 2); - smart_str_appendc(buf, digits[(us & 0xf000) >> 12]); - smart_str_appendc(buf, digits[(us & 0xf00) >> 8]); - smart_str_appendc(buf, digits[(us & 0xf0) >> 4]); - smart_str_appendc(buf, digits[(us & 0xf)]); - } - break; - } - } - - smart_str_appendc(buf, '"'); - if (utf16) { - efree(utf16); - } -} -/* }}} */ - - -static void json_encode_serializable_object(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ -{ - zend_class_entry *ce = Z_OBJCE_P(val); - zval *retval = NULL, fname; - HashTable* myht; - - if (Z_TYPE_P(val) == IS_ARRAY) { - myht = HASH_OF(val); - } else { - myht = Z_OBJPROP_P(val); - } - - if (myht && myht->nApplyCount > 1) { - JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; - smart_str_appendl(buf, "null", 4); - return; - } - - ZVAL_STRING(&fname, "jsonSerialize", 0); - - if (FAILURE == call_user_function_ex(EG(function_table), &val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || !retval) { - if (!EG(exception)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name); - } - smart_str_appendl(buf, "null", sizeof("null") - 1); - return; - } - - if (EG(exception)) { - /* Error already raised */ - zval_ptr_dtor(&retval); - smart_str_appendl(buf, "null", sizeof("null") - 1); - return; - } - - if ((Z_TYPE_P(retval) == IS_OBJECT) && - (Z_OBJ_HANDLE_P(retval) == Z_OBJ_HANDLE_P(val))) { - /* Handle the case where jsonSerialize does: return $this; by going straight to encode array */ - json_encode_array(buf, &retval, options TSRMLS_CC); - } else { - /* All other types, encode as normal */ - php_json_encode(buf, retval, options TSRMLS_CC); - } - - zval_ptr_dtor(&retval); -} -/* }}} */ - -PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ -{ - switch (Z_TYPE_P(val)) - { - case IS_NULL: - smart_str_appendl(buf, "null", 4); - break; - - case IS_BOOL: - if (Z_BVAL_P(val)) { - smart_str_appendl(buf, "true", 4); - } else { - smart_str_appendl(buf, "false", 5); - } - break; - - case IS_LONG: - smart_str_append_long(buf, Z_LVAL_P(val)); - break; - - case IS_DOUBLE: - { - char num[NUM_BUF_SIZE]; - int len; - double dbl = Z_DVAL_P(val); - - if (!zend_isinf(dbl) && !zend_isnan(dbl)) { - php_gcvt(dbl, EG(precision), '.', 'e', (char *)num); - len = strlen(num); - if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < NUM_BUF_SIZE - 2) { - num[len++] = '.'; - num[len++] = '0'; - num[len] = '\0'; - } - smart_str_appendl(buf, num, len); - } else { - JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN; - smart_str_appendc(buf, '0'); - } - } - break; - - case IS_STRING: - json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC); - break; - - case IS_OBJECT: - if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce TSRMLS_CC)) { - json_encode_serializable_object(buf, val, options TSRMLS_CC); - break; - } - /* fallthrough -- Non-serializable object */ - case IS_ARRAY: - json_encode_array(buf, &val, options TSRMLS_CC); - break; - - default: - JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE; - smart_str_appendl(buf, "null", 4); - break; - } - - return; -} -/* }}} */ - -PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */ -{ - int utf16_len; - zval *z; - unsigned short *utf16; - JSON_parser jp; - - utf16 = (unsigned short *) safe_emalloc((str_len+1), sizeof(unsigned short), 1); - - utf16_len = json_utf8_to_utf16(utf16, str, str_len); - if (utf16_len <= 0) { - if (utf16) { - efree(utf16); - } - JSON_G(error_code) = PHP_JSON_ERROR_UTF8; - RETURN_NULL(); - } - - if (depth <= 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be greater than zero"); - efree(utf16); - RETURN_NULL(); - } - - if (depth > INT_MAX) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be lower than %d", INT_MAX); - efree(utf16); + if (php_json_yyparse(&parser)) { + JSON_G(error_code) = php_json_parser_error_code(&parser); RETURN_NULL(); } - - ALLOC_INIT_ZVAL(z); - jp = new_JSON_parser(depth); - if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) { - *return_value = *z; - } - else - { - double d; - int type, overflow_info; - long p; - char *trim = str; - int trim_len = str_len; - - /* Increment trimmed string pointer to strip leading whitespace */ - /* JSON RFC says to consider as whitespace: space, tab, LF or CR */ - while (trim_len && (*trim == ' ' || *trim == '\t' || *trim == '\n' || *trim == '\r')) { - trim++; - trim_len--; - } - - /* Decrement trimmed string length to strip trailing whitespace */ - while (trim_len && (trim[trim_len - 1] == ' ' || trim[trim_len - 1] == '\t' || trim[trim_len - 1] == '\n' || trim[trim_len - 1] == '\r')) { - trim_len--; - } - - RETVAL_NULL(); - if (trim_len == 4) { - if (!strncmp(trim, "null", trim_len)) { - /* We need to explicitly clear the error because its an actual NULL and not an error */ - jp->error_code = PHP_JSON_ERROR_NONE; - RETVAL_NULL(); - } else if (!strncmp(trim, "true", trim_len)) { - RETVAL_BOOL(1); - } - } else if (trim_len == 5 && !strncmp(trim, "false", trim_len)) { - RETVAL_BOOL(0); - } - - if ((type = is_numeric_string_ex(trim, trim_len, &p, &d, 0, &overflow_info)) != 0) { - if (type == IS_LONG) { - RETVAL_LONG(p); - } else if (type == IS_DOUBLE) { - if (options & PHP_JSON_BIGINT_AS_STRING && overflow_info) { - /* Within an object or array, a numeric literal is assumed - * to be an integer if and only if it's entirely made up of - * digits (exponent notation will result in the number - * being treated as a double). We'll match that behaviour - * here. */ - int i; - zend_bool is_float = 0; - - for (i = (trim[0] == '-' ? 1 : 0); i < trim_len; i++) { - /* Not using isdigit() because it's locale specific, - * but we expect JSON input to always be UTF-8. */ - if (trim[i] < '0' || trim[i] > '9') { - is_float = 1; - break; - } - } - - if (is_float) { - RETVAL_DOUBLE(d); - } else { - RETVAL_STRINGL(trim, trim_len, 1); - } - } else { - RETVAL_DOUBLE(d); - } - } - } - - if (Z_TYPE_P(return_value) != IS_NULL) { - jp->error_code = PHP_JSON_ERROR_NONE; - } - - zval_dtor(z); - } - FREE_ZVAL(z); - efree(utf16); - JSON_G(error_code) = jp->error_code; - free_JSON_parser(jp); } /* }}} */ - /* {{{ proto string json_encode(mixed data [, int options[, int depth]]) Returns the JSON representation of a value */ static PHP_FUNCTION(json_encode) { zval *parameter; smart_str buf = {0}; - long options = 0; - long depth = JSON_PARSER_DEFAULT_DEPTH; + zend_long options = 0; + zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", ¶meter, &options, &depth) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", ¶meter, &options, &depth) == FAILURE) { return; } JSON_G(error_code) = PHP_JSON_ERROR_NONE; - JSON_G(encode_max_depth) = depth; + JSON_G(encode_max_depth) = (int)depth; - php_json_encode(&buf, parameter, options TSRMLS_CC); + php_json_encode(&buf, parameter, (int)options); if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { + smart_str_free(&buf); ZVAL_FALSE(return_value); } else { - ZVAL_STRINGL(return_value, buf.c, buf.len, 1); + smart_str_0(&buf); /* copy? */ + ZVAL_NEW_STR(return_value, buf.s); } - - smart_str_free(&buf); } /* }}} */ @@ -831,18 +244,29 @@ static PHP_FUNCTION(json_encode) static PHP_FUNCTION(json_decode) { char *str; - int str_len; + size_t str_len; zend_bool assoc = 0; /* return JS objects as PHP objects by default */ - long depth = JSON_PARSER_DEFAULT_DEPTH; - long options = 0; + zend_long depth = PHP_JSON_PARSER_DEFAULT_DEPTH; + zend_long options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) { return; } - JSON_G(error_code) = 0; + JSON_G(error_code) = PHP_JSON_ERROR_NONE; if (!str_len) { + JSON_G(error_code) = PHP_JSON_ERROR_SYNTAX; + RETURN_NULL(); + } + + if (depth <= 0) { + php_error_docref(NULL, E_WARNING, "Depth must be greater than zero"); + RETURN_NULL(); + } + + if (depth > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Depth must be lower than %d", INT_MAX); RETURN_NULL(); } @@ -853,7 +277,7 @@ static PHP_FUNCTION(json_decode) options &= ~PHP_JSON_OBJECT_AS_ARRAY; } - php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC); + php_json_decode_ex(return_value, str, str_len, options, depth); } /* }}} */ @@ -879,25 +303,29 @@ static PHP_FUNCTION(json_last_error_msg) switch(JSON_G(error_code)) { case PHP_JSON_ERROR_NONE: - RETURN_STRING("No error", 1); + RETURN_STRING("No error"); case PHP_JSON_ERROR_DEPTH: - RETURN_STRING("Maximum stack depth exceeded", 1); + RETURN_STRING("Maximum stack depth exceeded"); case PHP_JSON_ERROR_STATE_MISMATCH: - RETURN_STRING("State mismatch (invalid or malformed JSON)", 1); + RETURN_STRING("State mismatch (invalid or malformed JSON)"); case PHP_JSON_ERROR_CTRL_CHAR: - RETURN_STRING("Control character error, possibly incorrectly encoded", 1); + RETURN_STRING("Control character error, possibly incorrectly encoded"); case PHP_JSON_ERROR_SYNTAX: - RETURN_STRING("Syntax error", 1); + RETURN_STRING("Syntax error"); case PHP_JSON_ERROR_UTF8: - RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded", 1); + RETURN_STRING("Malformed UTF-8 characters, possibly incorrectly encoded"); case PHP_JSON_ERROR_RECURSION: - RETURN_STRING("Recursion detected", 1); + RETURN_STRING("Recursion detected"); case PHP_JSON_ERROR_INF_OR_NAN: - RETURN_STRING("Inf and NaN cannot be JSON encoded", 1); + RETURN_STRING("Inf and NaN cannot be JSON encoded"); case PHP_JSON_ERROR_UNSUPPORTED_TYPE: - RETURN_STRING("Type is not supported", 1); + RETURN_STRING("Type is not supported"); + case PHP_JSON_ERROR_INVALID_PROPERTY_NAME: + RETURN_STRING("The decoded property name is invalid"); + case PHP_JSON_ERROR_UTF16: + RETURN_STRING("Single unpaired UTF-16 surrogate in unicode escape"); default: - RETURN_STRING("Unknown error", 1); + RETURN_STRING("Unknown error"); } } diff --git a/ext/json/json.dsp b/ext/json/json.dsp deleted file mode 100644 index 9ef97bb80e..0000000000 --- a/ext/json/json.dsp +++ /dev/null @@ -1,119 +0,0 @@ -# Microsoft Developer Studio Project File - Name="json" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=json - Win32 Debug_TS
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "json.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "json.mak" CFG="json - Win32 Debug_TS"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "json - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "json - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "json - Win32 Debug_TS"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug_TS"
-# PROP BASE Intermediate_Dir "Debug_TS"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug_TS"
-# PROP Intermediate_Dir "Debug_TS"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D ZEND_DEBUG=1 /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x1009 /d "_DEBUG"
-# ADD RSC /l 0x1009 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 iconv.lib php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_json.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
-
-!ELSEIF "$(CFG)" == "json - Win32 Release_TS"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release_TS"
-# PROP BASE Intermediate_Dir "Release_TS"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release_TS"
-# PROP Intermediate_Dir "Release_TS"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "json_c" /D HAVE_JSON=1 /D "ZEND_WIN32" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D ZTS=1 /D COMPILE_DL_JSON=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "JSON_EXPORTS" /D "HAVE_FCNTL_H" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x1009 /d "NDEBUG"
-# ADD RSC /l 0x1009 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 iconv.lib php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_json.dll" /libpath:"..\..\Release_TS"
-
-!ENDIF
-
-# Begin Target
-
-# Name "json - Win32 Debug_TS"
-# Name "json - Win32 Release_TS"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=".\json.c"
-# End Source File
-# Begin Source File
-
-SOURCE=.\JSON_parser.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\JSON_parser.h
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\php_json.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c new file mode 100644 index 0000000000..8da2761e99 --- /dev/null +++ b/ext/json/json_encoder.c @@ -0,0 +1,565 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Omar Kilani <omar@php.net> | + | Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "ext/standard/html.h" +#include "zend_smart_str.h" +#include "php_json.h" +#include <zend_exceptions.h> + +/* double limits */ +#include <float.h> +#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP) +#define PHP_JSON_DOUBLE_MAX_LENGTH (3 + DBL_MANT_DIG - DBL_MIN_EXP) +#else +#define PHP_JSON_DOUBLE_MAX_LENGTH 1080 +#endif + +static const char digits[] = "0123456789abcdef"; + +static void php_json_escape_string(smart_str *buf, char *s, size_t len, int options); + +static int php_json_determine_array_type(zval *val) /* {{{ */ +{ + int i; + HashTable *myht = Z_ARRVAL_P(val); + + i = myht ? zend_hash_num_elements(myht) : 0; + if (i > 0) { + zend_string *key; + zend_ulong index, idx; + + idx = 0; + ZEND_HASH_FOREACH_KEY(myht, index, key) { + if (key) { + return PHP_JSON_OUTPUT_OBJECT; + } else { + if (index != idx) { + return PHP_JSON_OUTPUT_OBJECT; + } + } + idx++; + } ZEND_HASH_FOREACH_END(); + } + + return PHP_JSON_OUTPUT_ARRAY; +} +/* }}} */ + +/* {{{ Pretty printing support functions */ + +static inline void php_json_pretty_print_char(smart_str *buf, int options, char c) /* {{{ */ +{ + if (options & PHP_JSON_PRETTY_PRINT) { + smart_str_appendc(buf, c); + } +} +/* }}} */ + +static inline void php_json_pretty_print_indent(smart_str *buf, int options) /* {{{ */ +{ + int i; + + if (options & PHP_JSON_PRETTY_PRINT) { + for (i = 0; i < JSON_G(encoder_depth); ++i) { + smart_str_appendl(buf, " ", 4); + } + } +} +/* }}} */ + +/* }}} */ + +static inline int php_json_is_valid_double(double d) /* {{{ */ +{ + return !zend_isinf(d) && !zend_isnan(d); +} +/* }}} */ + +static inline void php_json_encode_double(smart_str *buf, double d, int options) /* {{{ */ +{ + size_t len; + char num[PHP_JSON_DOUBLE_MAX_LENGTH]; + php_gcvt(d, (int)EG(precision), '.', 'e', &num[0]); + len = strlen(num); + if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < PHP_JSON_DOUBLE_MAX_LENGTH - 2) { + num[len++] = '.'; + num[len++] = '0'; + num[len] = '\0'; + } + smart_str_appendl(buf, num, len); +} +/* }}} */ + +static void php_json_encode_array(smart_str *buf, zval *val, int options) /* {{{ */ +{ + int i, r, need_comma = 0; + HashTable *myht; + + if (Z_TYPE_P(val) == IS_ARRAY) { + myht = Z_ARRVAL_P(val); + r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(val); + } else { + myht = Z_OBJPROP_P(val); + r = PHP_JSON_OUTPUT_OBJECT; + } + + if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { + JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; + smart_str_appendl(buf, "null", 4); + return; + } + + if (r == PHP_JSON_OUTPUT_ARRAY) { + smart_str_appendc(buf, '['); + } else { + smart_str_appendc(buf, '{'); + } + + ++JSON_G(encoder_depth); + + i = myht ? zend_hash_num_elements(myht) : 0; + + if (i > 0) { + zend_string *key; + zval *data; + zend_ulong index; + HashTable *tmp_ht; + + ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) { + ZVAL_DEREF(data); + tmp_ht = HASH_OF(data); + if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) { + ZEND_HASH_INC_APPLY_COUNT(tmp_ht); + } + + if (r == PHP_JSON_OUTPUT_ARRAY) { + if (need_comma) { + smart_str_appendc(buf, ','); + } else { + need_comma = 1; + } + + php_json_pretty_print_char(buf, options, '\n'); + php_json_pretty_print_indent(buf, options); + php_json_encode(buf, data, options); + } else if (r == PHP_JSON_OUTPUT_OBJECT) { + if (key) { + if (ZSTR_VAL(key)[0] == '\0' && Z_TYPE_P(val) == IS_OBJECT) { + /* Skip protected and private members. */ + if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) { + ZEND_HASH_DEC_APPLY_COUNT(tmp_ht); + } + continue; + } + + if (need_comma) { + smart_str_appendc(buf, ','); + } else { + need_comma = 1; + } + + php_json_pretty_print_char(buf, options, '\n'); + php_json_pretty_print_indent(buf, options); + + php_json_escape_string(buf, ZSTR_VAL(key), ZSTR_LEN(key), options & ~PHP_JSON_NUMERIC_CHECK); + smart_str_appendc(buf, ':'); + + php_json_pretty_print_char(buf, options, ' '); + + php_json_encode(buf, data, options); + } else { + if (need_comma) { + smart_str_appendc(buf, ','); + } else { + need_comma = 1; + } + + php_json_pretty_print_char(buf, options, '\n'); + php_json_pretty_print_indent(buf, options); + + smart_str_appendc(buf, '"'); + smart_str_append_long(buf, (zend_long) index); + smart_str_appendc(buf, '"'); + smart_str_appendc(buf, ':'); + + php_json_pretty_print_char(buf, options, ' '); + + php_json_encode(buf, data, options); + } + } + + if (tmp_ht && ZEND_HASH_APPLY_PROTECTION(tmp_ht)) { + ZEND_HASH_DEC_APPLY_COUNT(tmp_ht); + } + } ZEND_HASH_FOREACH_END(); + } + + if (JSON_G(encoder_depth) > JSON_G(encode_max_depth)) { + JSON_G(error_code) = PHP_JSON_ERROR_DEPTH; + } + --JSON_G(encoder_depth); + + /* Only keep closing bracket on same line for empty arrays/objects */ + if (need_comma) { + php_json_pretty_print_char(buf, options, '\n'); + php_json_pretty_print_indent(buf, options); + } + + if (r == PHP_JSON_OUTPUT_ARRAY) { + smart_str_appendc(buf, ']'); + } else { + smart_str_appendc(buf, '}'); + } +} +/* }}} */ + +static int php_json_utf8_to_utf16(unsigned short *utf16, char utf8[], size_t len) /* {{{ */ +{ + size_t pos = 0, us; + int j, status; + + if (utf16) { + /* really convert the utf8 string */ + for (j=0 ; pos < len ; j++) { + us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status); + if (status != SUCCESS) { + return -1; + } + /* From http://en.wikipedia.org/wiki/UTF16 */ + if (us >= 0x10000) { + us -= 0x10000; + utf16[j++] = (unsigned short)((us >> 10) | 0xd800); + utf16[j] = (unsigned short)((us & 0x3ff) | 0xdc00); + } else { + utf16[j] = (unsigned short)us; + } + } + } else { + /* Only check if utf8 string is valid, and compute utf16 length */ + for (j=0 ; pos < len ; j++) { + us = php_next_utf8_char((const unsigned char *)utf8, len, &pos, &status); + if (status != SUCCESS) { + return -1; + } + if (us >= 0x10000) { + j++; + } + } + } + return j; +} +/* }}} */ + +static void php_json_escape_string(smart_str *buf, char *s, size_t len, int options) /* {{{ */ +{ + int status; + unsigned int us; + size_t pos, checkpoint; + + if (len == 0) { + smart_str_appendl(buf, "\"\"", 2); + return; + } + + if (options & PHP_JSON_NUMERIC_CHECK) { + double d; + int type; + zend_long p; + + if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { + if (type == IS_LONG) { + smart_str_append_long(buf, p); + return; + } else if (type == IS_DOUBLE && php_json_is_valid_double(d)) { + php_json_encode_double(buf, d, options); + return; + } + } + + } + + if (options & PHP_JSON_UNESCAPED_UNICODE) { + /* validate UTF-8 string first */ + if (php_json_utf8_to_utf16(NULL, s, len) < 0) { + JSON_G(error_code) = PHP_JSON_ERROR_UTF8; + smart_str_appendl(buf, "null", 4); + return; + } + } + + pos = 0; + checkpoint = buf->s ? ZSTR_LEN(buf->s) : 0; + + /* pre-allocate for string length plus 2 quotes */ + smart_str_alloc(buf, len+2, 0); + smart_str_appendc(buf, '"'); + + do { + us = (unsigned char)s[pos]; + if (us >= 0x80 && !(options & PHP_JSON_UNESCAPED_UNICODE)) { + /* UTF-8 character */ + us = php_next_utf8_char((const unsigned char *)s, len, &pos, &status); + if (status != SUCCESS) { + if (buf->s) { + ZSTR_LEN(buf->s) = checkpoint; + } + JSON_G(error_code) = PHP_JSON_ERROR_UTF8; + smart_str_appendl(buf, "null", 4); + return; + } + /* From http://en.wikipedia.org/wiki/UTF16 */ + if (us >= 0x10000) { + unsigned int next_us; + us -= 0x10000; + next_us = (unsigned short)((us & 0x3ff) | 0xdc00); + us = (unsigned short)((us >> 10) | 0xd800); + smart_str_appendl(buf, "\\u", 2); + smart_str_appendc(buf, digits[(us & 0xf000) >> 12]); + smart_str_appendc(buf, digits[(us & 0xf00) >> 8]); + smart_str_appendc(buf, digits[(us & 0xf0) >> 4]); + smart_str_appendc(buf, digits[(us & 0xf)]); + us = next_us; + } + smart_str_appendl(buf, "\\u", 2); + smart_str_appendc(buf, digits[(us & 0xf000) >> 12]); + smart_str_appendc(buf, digits[(us & 0xf00) >> 8]); + smart_str_appendc(buf, digits[(us & 0xf0) >> 4]); + smart_str_appendc(buf, digits[(us & 0xf)]); + } else { + pos++; + + switch (us) { + case '"': + if (options & PHP_JSON_HEX_QUOT) { + smart_str_appendl(buf, "\\u0022", 6); + } else { + smart_str_appendl(buf, "\\\"", 2); + } + break; + + case '\\': + smart_str_appendl(buf, "\\\\", 2); + break; + + case '/': + if (options & PHP_JSON_UNESCAPED_SLASHES) { + smart_str_appendc(buf, '/'); + } else { + smart_str_appendl(buf, "\\/", 2); + } + break; + + case '\b': + smart_str_appendl(buf, "\\b", 2); + break; + + case '\f': + smart_str_appendl(buf, "\\f", 2); + break; + + case '\n': + smart_str_appendl(buf, "\\n", 2); + break; + + case '\r': + smart_str_appendl(buf, "\\r", 2); + break; + + case '\t': + smart_str_appendl(buf, "\\t", 2); + break; + + case '<': + if (options & PHP_JSON_HEX_TAG) { + smart_str_appendl(buf, "\\u003C", 6); + } else { + smart_str_appendc(buf, '<'); + } + break; + + case '>': + if (options & PHP_JSON_HEX_TAG) { + smart_str_appendl(buf, "\\u003E", 6); + } else { + smart_str_appendc(buf, '>'); + } + break; + + case '&': + if (options & PHP_JSON_HEX_AMP) { + smart_str_appendl(buf, "\\u0026", 6); + } else { + smart_str_appendc(buf, '&'); + } + break; + + case '\'': + if (options & PHP_JSON_HEX_APOS) { + smart_str_appendl(buf, "\\u0027", 6); + } else { + smart_str_appendc(buf, '\''); + } + break; + + default: + if (us >= ' ') { + smart_str_appendc(buf, (unsigned char) us); + } else { + smart_str_appendl(buf, "\\u00", sizeof("\\u00")-1); + smart_str_appendc(buf, digits[(us & 0xf0) >> 4]); + smart_str_appendc(buf, digits[(us & 0xf)]); + } + break; + } + } + } while (pos < len); + + smart_str_appendc(buf, '"'); +} +/* }}} */ + +static void php_json_encode_serializable_object(smart_str *buf, zval *val, int options) /* {{{ */ +{ + zend_class_entry *ce = Z_OBJCE_P(val); + zval retval, fname; + HashTable* myht; + int origin_error_code; + + if (Z_TYPE_P(val) == IS_ARRAY) { + myht = Z_ARRVAL_P(val); + } else { + myht = Z_OBJPROP_P(val); + } + + if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { + JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; + smart_str_appendl(buf, "null", 4); + return; + } + + + ZVAL_STRING(&fname, "jsonSerialize"); + + origin_error_code = JSON_G(error_code); + if (FAILURE == call_user_function_ex(EG(function_table), val, &fname, &retval, 0, NULL, 1, NULL) || Z_TYPE(retval) == IS_UNDEF) { + if (!EG(exception)) { + zend_throw_exception_ex(NULL, 0, "Failed calling %s::jsonSerialize()", ZSTR_VAL(ce->name)); + } + smart_str_appendl(buf, "null", sizeof("null") - 1); + zval_ptr_dtor(&fname); + return; + } + + JSON_G(error_code) = origin_error_code; + if (EG(exception)) { + /* Error already raised */ + zval_ptr_dtor(&retval); + zval_ptr_dtor(&fname); + smart_str_appendl(buf, "null", sizeof("null") - 1); + return; + } + + if ((Z_TYPE(retval) == IS_OBJECT) && + (Z_OBJ(retval) == Z_OBJ_P(val))) { + /* Handle the case where jsonSerialize does: return $this; by going straight to encode array */ + php_json_encode_array(buf, &retval, options); + } else { + /* All other types, encode as normal */ + php_json_encode(buf, &retval, options); + } + + zval_ptr_dtor(&retval); + zval_ptr_dtor(&fname); +} +/* }}} */ + +void php_json_encode_zval(smart_str *buf, zval *val, int options) /* {{{ */ +{ +again: + switch (Z_TYPE_P(val)) + { + case IS_NULL: + smart_str_appendl(buf, "null", 4); + break; + + case IS_TRUE: + smart_str_appendl(buf, "true", 4); + break; + case IS_FALSE: + smart_str_appendl(buf, "false", 5); + break; + + case IS_LONG: + smart_str_append_long(buf, Z_LVAL_P(val)); + break; + + case IS_DOUBLE: + if (php_json_is_valid_double(Z_DVAL_P(val))) { + php_json_encode_double(buf, Z_DVAL_P(val), options); + } else { + JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN; + smart_str_appendc(buf, '0'); + } + break; + + case IS_STRING: + php_json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options); + break; + + case IS_OBJECT: + if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce)) { + php_json_encode_serializable_object(buf, val, options); + break; + } + /* fallthrough -- Non-serializable object */ + case IS_ARRAY: + php_json_encode_array(buf, val, options); + break; + + case IS_REFERENCE: + val = Z_REFVAL_P(val); + goto again; + + default: + JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE; + smart_str_appendl(buf, "null", 4); + break; + } + + return; +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ diff --git a/ext/json/json_parser.tab.c b/ext/json/json_parser.tab.c new file mode 100644 index 0000000000..b01d031f14 --- /dev/null +++ b/ext/json/json_parser.tab.c @@ -0,0 +1,1916 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* "%code top" blocks. */ + + +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_json.h" +#include "php_json_parser.h" + +#define YYDEBUG 0 + +#if YYDEBUG +int json_yydebug = 1; +#endif + +#ifdef _MSC_VER +#define YYMALLOC malloc +#define YYFREE free +#endif + +#define PHP_JSON_USE(uv) ((void) (uv)) +#define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1) +#define PHP_JSON_USE_2(uvr, uv1, uv2) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2) + + + + +/* Substitute the variable and function names. */ +#define yyparse php_json_yyparse +#define yylex php_json_yylex +#define yyerror php_json_yyerror +#define yydebug php_json_yydebug +#define yynerrs php_json_yynerrs + + +/* Copy the first part of user declarations. */ + + + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "json_parser.tab.h". */ +#ifndef YY_PHP_JSON_YY_HOME_JAKUB_PROG_PHP_MASTER_EXT_JSON_JSON_PARSER_TAB_H_INCLUDED +# define YY_PHP_JSON_YY_HOME_JAKUB_PROG_PHP_MASTER_EXT_JSON_JSON_PARSER_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int php_json_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + PHP_JSON_T_NUL = 258, + PHP_JSON_T_TRUE = 259, + PHP_JSON_T_FALSE = 260, + PHP_JSON_T_INT = 261, + PHP_JSON_T_DOUBLE = 262, + PHP_JSON_T_STRING = 263, + PHP_JSON_T_ESTRING = 264, + PHP_JSON_T_EOI = 265, + PHP_JSON_T_ERROR = 266 + }; +#endif +/* Tokens. */ +#define PHP_JSON_T_NUL 258 +#define PHP_JSON_T_TRUE 259 +#define PHP_JSON_T_FALSE 260 +#define PHP_JSON_T_INT 261 +#define PHP_JSON_T_DOUBLE 262 +#define PHP_JSON_T_STRING 263 +#define PHP_JSON_T_ESTRING 264 +#define PHP_JSON_T_EOI 265 +#define PHP_JSON_T_ERROR 266 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ + + + zval value; + struct { + zend_string *key; + zval val; + } pair; + + +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int php_json_yyparse (php_json_parser *parser); + +#endif /* !YY_PHP_JSON_YY_HOME_JAKUB_PROG_PHP_MASTER_EXT_JSON_JSON_PARSER_TAB_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + + +/* Unqualified %code blocks. */ + + +int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); +void php_json_yyerror(php_json_parser *parser, char const *msg); +void php_json_parser_object_init(php_json_parser *parser, zval *object); +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); +void php_json_parser_array_init(zval *object); +void php_json_parser_array_append(zval *array, zval *zvalue); + +#define PHP_JSON_DEPTH_DEC --parser->depth +#define PHP_JSON_DEPTH_INC \ + if (parser->max_depth && parser->depth >= parser->max_depth) { \ + parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \ + YYERROR; \ + } \ + ++parser->depth + + + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 18 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 34 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 18 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 16 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 36 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 45 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 266 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 15, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 16, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 17, 2, 14, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 12, 2, 13, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint8 yyrline[] = +{ + 0, 92, 92, 98, 105, 105, 113, 114, 123, 126, + 130, 136, 142, 149, 154, 161, 161, 169, 170, 179, + 182, 186, 191, 196, 203, 204, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 221 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "PHP_JSON_T_NUL", "PHP_JSON_T_TRUE", + "PHP_JSON_T_FALSE", "PHP_JSON_T_INT", "PHP_JSON_T_DOUBLE", + "PHP_JSON_T_STRING", "PHP_JSON_T_ESTRING", "PHP_JSON_T_EOI", + "PHP_JSON_T_ERROR", "'{'", "'}'", "']'", "','", "':'", "'['", "$accept", + "start", "object", "$@1", "object_end", "members", "member", "pair", + "array", "$@2", "array_end", "elements", "element", "key", "value", + "errlex", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 123, 125, 93, 44, 58, 91 +}; +# endif + +#define YYPACT_NINF -18 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-18))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int8 yypact[] = +{ + -2, -18, -18, -18, -18, -18, -18, -18, -18, -18, + -18, 11, -18, -18, 9, -18, 21, -2, -18, -18, + -18, -18, -18, 18, 1, -18, -3, 20, 6, -18, + -18, -18, -18, 21, -18, -2, -18, -18, -18, -18, + -2, -18, -18, -18, -18 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 32, 33, 34, 30, 31, 28, 29, 36, 4, + 15, 0, 26, 27, 0, 35, 8, 19, 1, 2, + 3, 24, 25, 0, 9, 10, 0, 0, 20, 21, + 6, 7, 5, 0, 12, 0, 14, 18, 17, 16, + 0, 23, 11, 13, 22 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -18, -18, -18, -18, -18, -18, -18, -11, -18, -18, + -18, -18, -18, -18, -17, 0 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 11, 12, 16, 32, 23, 24, 25, 13, 17, + 39, 27, 28, 26, 14, 15 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 29, 1, 2, 3, 4, 5, 6, 7, 8, 8, + 9, 18, 8, 35, 20, 10, 33, 8, 43, 19, + 8, 40, 42, 44, 34, 0, 36, 0, 41, 21, + 22, 30, 31, 37, 38 +}; + +static const yytype_int8 yycheck[] = +{ + 17, 3, 4, 5, 6, 7, 8, 9, 11, 11, + 12, 0, 11, 16, 14, 17, 15, 11, 35, 10, + 11, 15, 33, 40, 24, -1, 26, -1, 28, 8, + 9, 13, 14, 13, 14 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 11, 12, + 17, 19, 20, 26, 32, 33, 21, 27, 0, 10, + 33, 8, 9, 23, 24, 25, 31, 29, 30, 32, + 13, 14, 22, 15, 33, 16, 33, 13, 14, 28, + 15, 33, 25, 32, 32 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 18, 19, 19, 21, 20, 22, 22, 23, 23, + 24, 24, 24, 25, 25, 27, 26, 28, 28, 29, + 29, 30, 30, 30, 31, 31, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 33 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 2, 0, 4, 1, 1, 0, 1, + 1, 3, 2, 3, 2, 0, 4, 1, 1, 0, + 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (parser, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + +/* This macro is provided for backward compatibility. */ +#ifndef YY_LOCATION_PRINT +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, parser); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, php_json_parser *parser) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (parser); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, php_json_parser *parser) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep, parser); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule, php_json_parser *parser) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , parser); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule, parser); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, php_json_parser *parser) +{ + YYUSE (yyvaluep); + YYUSE (parser); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + switch (yytype) + { + case 3: /* PHP_JSON_T_NUL */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 4: /* PHP_JSON_T_TRUE */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 5: /* PHP_JSON_T_FALSE */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 6: /* PHP_JSON_T_INT */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 7: /* PHP_JSON_T_DOUBLE */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 8: /* PHP_JSON_T_STRING */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 9: /* PHP_JSON_T_ESTRING */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 10: /* PHP_JSON_T_EOI */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 11: /* PHP_JSON_T_ERROR */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 19: /* start */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 20: /* object */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 23: /* members */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 24: /* member */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 25: /* pair */ + + { zend_string_release(((*yyvaluep).pair).key); zval_dtor(&((*yyvaluep).pair).val); } + + break; + + case 26: /* array */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 29: /* elements */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 30: /* element */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 31: /* key */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 32: /* value */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + case 33: /* errlex */ + + { zval_dtor(&((*yyvaluep).value)); } + + break; + + + default: + break; + } + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (php_json_parser *parser) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, parser); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: + + { + ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); + ZVAL_COPY_VALUE(parser->return_value, &(yyvsp[-1].value)); + PHP_JSON_USE((yyvsp[0].value)); YYACCEPT; + } + + break; + + case 3: + + { + PHP_JSON_USE_2((yyval.value), (yyvsp[-1].value), (yyvsp[0].value)); + } + + break; + + case 4: + + { PHP_JSON_DEPTH_INC; } + + break; + + case 5: + + { + PHP_JSON_DEPTH_DEC; + (yyval.value) = (yyvsp[-1].value); + } + + break; + + case 7: + + { + parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH; + YYERROR; + } + + break; + + case 8: + + { + php_json_parser_object_init(parser, &(yyval.value)); + } + + break; + + case 10: + + { + php_json_parser_object_init(parser, &(yyval.value)); + if (php_json_parser_object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + YYERROR; + } + + break; + + case 11: + + { + if (php_json_parser_object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE) + YYERROR; + ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); + } + + break; + + case 12: + + { + PHP_JSON_USE_2((yyval.value), (yyvsp[-1].value), (yyvsp[0].value)); + } + + break; + + case 13: + + { + (yyval.pair).key = Z_STR((yyvsp[-2].value)); + ZVAL_COPY_VALUE(&(yyval.pair).val, &(yyvsp[0].value)); + } + + break; + + case 14: + + { + PHP_JSON_USE_2((yyval.pair), (yyvsp[-1].value), (yyvsp[0].value)); + } + + break; + + case 15: + + { PHP_JSON_DEPTH_INC; } + + break; + + case 16: + + { + PHP_JSON_DEPTH_DEC; + ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value)); + } + + break; + + case 18: + + { + parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH; + YYERROR; + } + + break; + + case 19: + + { + php_json_parser_array_init(&(yyval.value)); + } + + break; + + case 21: + + { + php_json_parser_array_init(&(yyval.value)); + php_json_parser_array_append(&(yyval.value), &(yyvsp[0].value)); + } + + break; + + case 22: + + { + php_json_parser_array_append(&(yyvsp[-2].value), &(yyvsp[0].value)); + ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value)); + } + + break; + + case 23: + + { + PHP_JSON_USE_2((yyval.value), (yyvsp[-1].value), (yyvsp[0].value)); + } + + break; + + case 36: + + { + PHP_JSON_USE_1((yyval.value), (yyvsp[0].value)); + YYERROR; + } + + break; + + + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (parser, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (parser, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, parser); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp, parser); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (parser, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, parser); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, parser); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} + + /* Functions */ + +void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth) +{ + memset(parser, 0, sizeof(php_json_parser)); + php_json_scanner_init(&parser->scanner, str, str_len, options); + parser->depth = 1; + parser->max_depth = max_depth; + parser->return_value = return_value; +} + +php_json_error_code php_json_parser_error_code(php_json_parser *parser) +{ + return parser->scanner.errcode; +} + +void php_json_parser_object_init(php_json_parser *parser, zval *object) +{ + if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { + array_init(object); + } else { + object_init(object); + } +} + +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +{ + /* if JSON_OBJECT_AS_ARRAY is set */ + if (Z_TYPE_P(object) == IS_ARRAY) { + zend_symtable_update(Z_ARRVAL_P(object), key, zvalue); + } else { + zval zkey; + if (ZSTR_LEN(key) == 0) { + zend_string_release(key); + key = zend_string_init("_empty_", sizeof("_empty_") - 1, 0); + } else if (ZSTR_VAL(key)[0] == '\0') { + parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME; + zend_string_release(key); + zval_dtor(zvalue); + zval_dtor(object); + return FAILURE; + } + ZVAL_NEW_STR(&zkey, key); + zend_std_write_property(object, &zkey, zvalue, NULL); + + if (Z_REFCOUNTED_P(zvalue)) { + Z_DELREF_P(zvalue); + } + } + zend_string_release(key); + + return SUCCESS; +} + +void php_json_parser_array_init(zval *array) +{ + array_init(array); +} + +void php_json_parser_array_append(zval *array, zval *zvalue) +{ + zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); +} + +int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) +{ + int token = php_json_scan(&parser->scanner); + value->value = parser->scanner.value; + return token; +} + +void php_json_yyerror(php_json_parser *parser, char const *msg) +{ + if (!parser->scanner.errcode) { + parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; + } +} diff --git a/ext/json/json_parser.tab.h b/ext/json/json_parser.tab.h new file mode 100644 index 0000000000..56bc2c40c9 --- /dev/null +++ b/ext/json/json_parser.tab.h @@ -0,0 +1,95 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_PHP_JSON_YY_HOME_JAKUB_PROG_PHP_MASTER_EXT_JSON_JSON_PARSER_TAB_H_INCLUDED +# define YY_PHP_JSON_YY_HOME_JAKUB_PROG_PHP_MASTER_EXT_JSON_JSON_PARSER_TAB_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int php_json_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + PHP_JSON_T_NUL = 258, + PHP_JSON_T_TRUE = 259, + PHP_JSON_T_FALSE = 260, + PHP_JSON_T_INT = 261, + PHP_JSON_T_DOUBLE = 262, + PHP_JSON_T_STRING = 263, + PHP_JSON_T_ESTRING = 264, + PHP_JSON_T_EOI = 265, + PHP_JSON_T_ERROR = 266 + }; +#endif +/* Tokens. */ +#define PHP_JSON_T_NUL 258 +#define PHP_JSON_T_TRUE 259 +#define PHP_JSON_T_FALSE 260 +#define PHP_JSON_T_INT 261 +#define PHP_JSON_T_DOUBLE 262 +#define PHP_JSON_T_STRING 263 +#define PHP_JSON_T_ESTRING 264 +#define PHP_JSON_T_EOI 265 +#define PHP_JSON_T_ERROR 266 + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ + + + zval value; + struct { + zend_string *key; + zval val; + } pair; + + +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + + +int php_json_yyparse (php_json_parser *parser); + +#endif /* !YY_PHP_JSON_YY_HOME_JAKUB_PROG_PHP_MASTER_EXT_JSON_JSON_PARSER_TAB_H_INCLUDED */ diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y new file mode 100644 index 0000000000..2f37641c0c --- /dev/null +++ b/ext/json/json_parser.y @@ -0,0 +1,304 @@ +%code top { +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_json.h" +#include "php_json_parser.h" + +#define YYDEBUG 0 + +#if YYDEBUG +int json_yydebug = 1; +#endif + +#ifdef _MSC_VER +#define YYMALLOC malloc +#define YYFREE free +#endif + +#define PHP_JSON_USE(uv) ((void) (uv)) +#define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1) +#define PHP_JSON_USE_2(uvr, uv1, uv2) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2) + +} + +%pure-parser +%name-prefix "php_json_yy" +%lex-param { php_json_parser *parser } +%parse-param { php_json_parser *parser } + +%union { + zval value; + struct { + zend_string *key; + zval val; + } pair; +} + + +%token <value> PHP_JSON_T_NUL +%token <value> PHP_JSON_T_TRUE +%token <value> PHP_JSON_T_FALSE +%token <value> PHP_JSON_T_INT +%token <value> PHP_JSON_T_DOUBLE +%token <value> PHP_JSON_T_STRING +%token <value> PHP_JSON_T_ESTRING +%token <value> PHP_JSON_T_EOI +%token <value> PHP_JSON_T_ERROR + +%type <value> start object key value array errlex +%type <value> members member elements element +%type <pair> pair + +%destructor { zval_dtor(&$$); } <value> +%destructor { zend_string_release($$.key); zval_dtor(&$$.val); } <pair> + +%code { +int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); +void php_json_yyerror(php_json_parser *parser, char const *msg); +void php_json_parser_object_init(php_json_parser *parser, zval *object); +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue); +void php_json_parser_array_init(zval *object); +void php_json_parser_array_append(zval *array, zval *zvalue); + +#define PHP_JSON_DEPTH_DEC --parser->depth +#define PHP_JSON_DEPTH_INC \ + if (parser->max_depth && parser->depth >= parser->max_depth) { \ + parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \ + YYERROR; \ + } \ + ++parser->depth +} + +%% /* Rules */ + +start: + value PHP_JSON_T_EOI + { + ZVAL_COPY_VALUE(&$$, &$1); + ZVAL_COPY_VALUE(parser->return_value, &$1); + PHP_JSON_USE($2); YYACCEPT; + } + | value errlex + { + PHP_JSON_USE_2($$, $1, $2); + } +; + +object: + '{' { PHP_JSON_DEPTH_INC; } members object_end + { + PHP_JSON_DEPTH_DEC; + $$ = $3; + } +; + +object_end: + '}' + | ']' + { + parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH; + YYERROR; + } +; + +members: + /* empty */ + { + php_json_parser_object_init(parser, &$$); + } + | member +; + +member: + pair + { + php_json_parser_object_init(parser, &$$); + if (php_json_parser_object_update(parser, &$$, $1.key, &$1.val) == FAILURE) + YYERROR; + } + | member ',' pair + { + if (php_json_parser_object_update(parser, &$1, $3.key, &$3.val) == FAILURE) + YYERROR; + ZVAL_COPY_VALUE(&$$, &$1); + } + | member errlex + { + PHP_JSON_USE_2($$, $1, $2); + } +; + +pair: + key ':' value + { + $$.key = Z_STR($1); + ZVAL_COPY_VALUE(&$$.val, &$3); + } + | key errlex + { + PHP_JSON_USE_2($$, $1, $2); + } +; + +array: + '[' { PHP_JSON_DEPTH_INC; } elements array_end + { + PHP_JSON_DEPTH_DEC; + ZVAL_COPY_VALUE(&$$, &$3); + } +; + +array_end: + ']' + | '}' + { + parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH; + YYERROR; + } +; + +elements: + /* empty */ + { + php_json_parser_array_init(&$$); + } + | element +; + +element: + value + { + php_json_parser_array_init(&$$); + php_json_parser_array_append(&$$, &$1); + } + | element ',' value + { + php_json_parser_array_append(&$1, &$3); + ZVAL_COPY_VALUE(&$$, &$1); + } + | element errlex + { + PHP_JSON_USE_2($$, $1, $2); + } +; + +key: + PHP_JSON_T_STRING + | PHP_JSON_T_ESTRING +; + +value: + object + | array + | PHP_JSON_T_STRING + | PHP_JSON_T_ESTRING + | PHP_JSON_T_INT + | PHP_JSON_T_DOUBLE + | PHP_JSON_T_NUL + | PHP_JSON_T_TRUE + | PHP_JSON_T_FALSE + | errlex +; + +errlex: + PHP_JSON_T_ERROR + { + PHP_JSON_USE_1($$, $1); + YYERROR; + } +; + +%% /* Functions */ + +void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth) +{ + memset(parser, 0, sizeof(php_json_parser)); + php_json_scanner_init(&parser->scanner, str, str_len, options); + parser->depth = 1; + parser->max_depth = max_depth; + parser->return_value = return_value; +} + +php_json_error_code php_json_parser_error_code(php_json_parser *parser) +{ + return parser->scanner.errcode; +} + +void php_json_parser_object_init(php_json_parser *parser, zval *object) +{ + if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { + array_init(object); + } else { + object_init(object); + } +} + +int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue) +{ + /* if JSON_OBJECT_AS_ARRAY is set */ + if (Z_TYPE_P(object) == IS_ARRAY) { + zend_symtable_update(Z_ARRVAL_P(object), key, zvalue); + } else { + zval zkey; + if (ZSTR_LEN(key) == 0) { + zend_string_release(key); + key = zend_string_init("_empty_", sizeof("_empty_") - 1, 0); + } else if (ZSTR_VAL(key)[0] == '\0') { + parser->scanner.errcode = PHP_JSON_ERROR_INVALID_PROPERTY_NAME; + zend_string_release(key); + zval_dtor(zvalue); + zval_dtor(object); + return FAILURE; + } + ZVAL_NEW_STR(&zkey, key); + zend_std_write_property(object, &zkey, zvalue, NULL); + + if (Z_REFCOUNTED_P(zvalue)) { + Z_DELREF_P(zvalue); + } + } + zend_string_release(key); + + return SUCCESS; +} + +void php_json_parser_array_init(zval *array) +{ + array_init(array); +} + +void php_json_parser_array_append(zval *array, zval *zvalue) +{ + zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue); +} + +int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) +{ + int token = php_json_scan(&parser->scanner); + value->value = parser->scanner.value; + return token; +} + +void php_json_yyerror(php_json_parser *parser, char const *msg) +{ + if (!parser->scanner.errcode) { + parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; + } +} diff --git a/ext/json/json_scanner.c b/ext/json/json_scanner.c new file mode 100644 index 0000000000..ee46a13198 --- /dev/null +++ b/ext/json/json_scanner.c @@ -0,0 +1,1322 @@ +/* Generated by re2c 0.14.3 */ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_json_scanner.h" +#include "php_json_scanner_defs.h" +#include "php_json_parser.h" +#include "json_parser.tab.h" + +#define YYCTYPE php_json_ctype +#define YYCURSOR s->cursor +#define YYLIMIT s->limit +#define YYMARKER s->marker +#define YYCTXMARKER s->ctxmarker + +#define YYGETCONDITION() s->state +#define YYSETCONDITION(yystate) s->state = yystate + +#define YYFILL(n) + +#define PHP_JSON_CONDITION_SET(condition) YYSETCONDITION(yyc##condition) +#define PHP_JSON_CONDITION_GOTO(condition) goto yyc_##condition + +#define PHP_JSON_SCANNER_COPY_ESC() php_json_scanner_copy_string(s, 0) +#define PHP_JSON_SCANNER_COPY_UTF() php_json_scanner_copy_string(s, 5) +#define PHP_JSON_SCANNER_COPY_UTF_SP() php_json_scanner_copy_string(s, 11) + +#define PHP_JSON_INT_MAX_LENGTH (MAX_LENGTH_OF_LONG - 1) + + +static void php_json_scanner_copy_string(php_json_scanner *s, int esc_size) +{ + size_t len = s->cursor - s->str_start - esc_size - 1; + if (len) { + memcpy(s->pstr, s->str_start, len); + s->pstr += len; + } +} + +static int php_json_hex_to_int(char code) +{ + if (code >= '0' && code <= '9') { + return code - '0'; + } else if (code >= 'A' && code <= 'F') { + return code - ('A' - 10); + } else if (code >= 'a' && code <= 'f') { + return code - ('a' - 10); + } else { + /* this should never happened (just to suppress compiler warning) */ + return -1; + } +} + +static int php_json_ucs2_to_int_ex(php_json_scanner *s, int size, int start) +{ + int i, code = 0; + php_json_ctype *pc = s->cursor - start; + for (i = 0; i < size; i++) { + code |= php_json_hex_to_int(*(pc--)) << (i * 4); + } + return code; +} + +static int php_json_ucs2_to_int(php_json_scanner *s, int size) +{ + return php_json_ucs2_to_int_ex(s, size, 1); +} + +void php_json_scanner_init(php_json_scanner *s, char *str, size_t str_len, int options) +{ + s->cursor = (php_json_ctype *) str; + s->limit = (php_json_ctype *) str + str_len; + s->options = options; + PHP_JSON_CONDITION_SET(JS); +} + +int php_json_scan(php_json_scanner *s) +{ + ZVAL_NULL(&s->value); + +std: + s->token = s->cursor; + + + { + YYCTYPE yych; + unsigned int yyaccept = 0; + if (YYGETCONDITION() < 1) { + goto yyc_JS; + } else { + if (YYGETCONDITION() < 2) { + goto yyc_STR_P1; + } else { + goto yyc_STR_P2; + } + } +/* *********************************** */ +yyc_JS: + { + static const unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 128, 0, 0, 0, 128, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + yych = *YYCURSOR; + if (yych <= ']') { + if (yych <= '"') { + if (yych <= '\f') { + if (yych <= 0x08) { + if (yych >= 0x01) goto yy5; + } else { + if (yych <= '\t') goto yy7; + if (yych <= '\n') goto yy9; + goto yy5; + } + } else { + if (yych <= 0x1F) { + if (yych <= '\r') goto yy10; + goto yy5; + } else { + if (yych <= ' ') goto yy11; + if (yych <= '!') goto yy12; + goto yy14; + } + } + } else { + if (yych <= '0') { + if (yych <= ',') { + if (yych <= '+') goto yy12; + goto yy16; + } else { + if (yych <= '-') goto yy18; + if (yych <= '/') goto yy12; + goto yy19; + } + } else { + if (yych <= 'Z') { + if (yych <= '9') goto yy21; + if (yych <= ':') goto yy22; + goto yy12; + } else { + if (yych <= '[') goto yy24; + if (yych <= '\\') goto yy12; + goto yy26; + } + } + } + } else { + if (yych <= '}') { + if (yych <= 's') { + if (yych <= 'f') { + if (yych <= 'e') goto yy12; + goto yy28; + } else { + if (yych == 'n') goto yy29; + goto yy12; + } + } else { + if (yych <= 'z') { + if (yych <= 't') goto yy30; + goto yy12; + } else { + if (yych <= '{') goto yy31; + if (yych <= '|') goto yy12; + goto yy33; + } + } + } else { + if (yych <= 0xEC) { + if (yych <= 0xC1) { + if (yych <= 0x7F) goto yy12; + goto yy35; + } else { + if (yych <= 0xDF) goto yy37; + if (yych <= 0xE0) goto yy38; + goto yy39; + } + } else { + if (yych <= 0xF0) { + if (yych <= 0xED) goto yy40; + if (yych <= 0xEF) goto yy41; + goto yy42; + } else { + if (yych <= 0xF3) goto yy43; + if (yych <= 0xF4) goto yy44; + goto yy35; + } + } + } + } + ++YYCURSOR; + { + if (s->limit < s->cursor) { + return PHP_JSON_T_EOI; + } else { + s->errcode = PHP_JSON_ERROR_CTRL_CHAR; + return PHP_JSON_T_ERROR; + } + } +yy5: + ++YYCURSOR; + { + s->errcode = PHP_JSON_ERROR_CTRL_CHAR; + return PHP_JSON_T_ERROR; + } +yy7: + ++YYCURSOR; + yych = *YYCURSOR; + goto yy82; +yy8: + { goto std; } +yy9: + yych = *++YYCURSOR; + goto yy8; +yy10: + yych = *++YYCURSOR; + if (yych == '\n') goto yy83; + goto yy82; +yy11: + yych = *++YYCURSOR; + goto yy82; +yy12: + ++YYCURSOR; +yy13: + { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } +yy14: + ++YYCURSOR; + { + s->str_start = s->cursor; + s->str_esc = 0; + PHP_JSON_CONDITION_SET(STR_P1); + PHP_JSON_CONDITION_GOTO(STR_P1); + } +yy16: + ++YYCURSOR; + { return ','; } +yy18: + yych = *++YYCURSOR; + if (yych <= '/') goto yy13; + if (yych <= '0') goto yy80; + if (yych <= '9') goto yy70; + goto yy13; +yy19: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'D') { + if (yych == '.') goto yy72; + } else { + if (yych <= 'E') goto yy73; + if (yych == 'e') goto yy73; + } +yy20: + { + zend_bool bigint = 0, negative = s->token[0] == '-'; + size_t digits = (size_t) (s->cursor - s->token - negative); + if (digits >= PHP_JSON_INT_MAX_LENGTH) { + if (digits == PHP_JSON_INT_MAX_LENGTH) { + int cmp = strncmp((char *) (s->token + negative), LONG_MIN_DIGITS, PHP_JSON_INT_MAX_LENGTH); + if (!(cmp < 0 || (cmp == 0 && negative))) { + bigint = 1; + } + } else { + bigint = 1; + } + } + if (!bigint) { + ZVAL_LONG(&s->value, ZEND_STRTOL((char *) s->token, NULL, 10)); + return PHP_JSON_T_INT; + } else if (s->options & PHP_JSON_BIGINT_AS_STRING) { + ZVAL_STRINGL(&s->value, (char *) s->token, s->cursor - s->token); + return PHP_JSON_T_STRING; + } else { + ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); + return PHP_JSON_T_DOUBLE; + } + } +yy21: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + goto yy71; +yy22: + ++YYCURSOR; + { return ':'; } +yy24: + ++YYCURSOR; + { return '['; } +yy26: + ++YYCURSOR; + { return ']'; } +yy28: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'a') goto yy65; + goto yy13; +yy29: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy61; + goto yy13; +yy30: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'r') goto yy57; + goto yy13; +yy31: + ++YYCURSOR; + { return '{'; } +yy33: + ++YYCURSOR; + { return '}'; } +yy35: + ++YYCURSOR; +yy36: + { + s->errcode = PHP_JSON_ERROR_UTF8; + return PHP_JSON_T_ERROR; + } +yy37: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy36; + if (yych <= 0xBF) goto yy48; + goto yy36; +yy38: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x9F) goto yy36; + if (yych <= 0xBF) goto yy56; + goto yy36; +yy39: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy36; + if (yych <= 0xBF) goto yy55; + goto yy36; +yy40: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy36; + if (yych <= 0x9F) goto yy54; + goto yy36; +yy41: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy36; + if (yych <= 0xBF) goto yy53; + goto yy36; +yy42: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x8F) goto yy36; + if (yych <= 0xBF) goto yy51; + goto yy36; +yy43: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy36; + if (yych <= 0xBF) goto yy49; + goto yy36; +yy44: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy36; + if (yych >= 0x90) goto yy36; + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych <= 0xBF) goto yy47; +yy46: + YYCURSOR = YYMARKER; + if (yyaccept <= 1) { + if (yyaccept == 0) { + goto yy20; + } else { + goto yy13; + } + } else { + if (yyaccept == 2) { + goto yy36; + } else { + goto yy77; + } + } +yy47: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych >= 0xC0) goto yy46; +yy48: + yych = *++YYCURSOR; + goto yy13; +yy49: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych >= 0xC0) goto yy46; + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych <= 0xBF) goto yy48; + goto yy46; +yy51: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych >= 0xC0) goto yy46; + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych <= 0xBF) goto yy48; + goto yy46; +yy53: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych <= 0xBF) goto yy48; + goto yy46; +yy54: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych <= 0xBF) goto yy48; + goto yy46; +yy55: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych <= 0xBF) goto yy48; + goto yy46; +yy56: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy46; + if (yych <= 0xBF) goto yy48; + goto yy46; +yy57: + yych = *++YYCURSOR; + if (yych != 'u') goto yy46; + yych = *++YYCURSOR; + if (yych != 'e') goto yy46; + ++YYCURSOR; + { + ZVAL_TRUE(&s->value); + return PHP_JSON_T_TRUE; + } +yy61: + yych = *++YYCURSOR; + if (yych != 'l') goto yy46; + yych = *++YYCURSOR; + if (yych != 'l') goto yy46; + ++YYCURSOR; + { + ZVAL_NULL(&s->value); + return PHP_JSON_T_NUL; + } +yy65: + yych = *++YYCURSOR; + if (yych != 'l') goto yy46; + yych = *++YYCURSOR; + if (yych != 's') goto yy46; + yych = *++YYCURSOR; + if (yych != 'e') goto yy46; + ++YYCURSOR; + { + ZVAL_FALSE(&s->value); + return PHP_JSON_T_FALSE; + } +yy70: + yyaccept = 0; + YYMARKER = ++YYCURSOR; + yych = *YYCURSOR; +yy71: + if (yybm[0+yych] & 64) { + goto yy70; + } + if (yych <= 'D') { + if (yych != '.') goto yy20; + } else { + if (yych <= 'E') goto yy73; + if (yych == 'e') goto yy73; + goto yy20; + } +yy72: + yych = *++YYCURSOR; + if (yych <= '/') goto yy46; + if (yych <= '9') goto yy78; + goto yy46; +yy73: + yych = *++YYCURSOR; + if (yych <= ',') { + if (yych != '+') goto yy46; + } else { + if (yych <= '-') goto yy74; + if (yych <= '/') goto yy46; + if (yych <= '9') goto yy75; + goto yy46; + } +yy74: + yych = *++YYCURSOR; + if (yych <= '/') goto yy46; + if (yych >= ':') goto yy46; +yy75: + ++YYCURSOR; + yych = *YYCURSOR; + if (yych <= '/') goto yy77; + if (yych <= '9') goto yy75; +yy77: + { + ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); + return PHP_JSON_T_DOUBLE; + } +yy78: + yyaccept = 3; + YYMARKER = ++YYCURSOR; + yych = *YYCURSOR; + if (yych <= 'D') { + if (yych <= '/') goto yy77; + if (yych <= '9') goto yy78; + goto yy77; + } else { + if (yych <= 'E') goto yy73; + if (yych == 'e') goto yy73; + goto yy77; + } +yy80: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'D') { + if (yych == '.') goto yy72; + goto yy20; + } else { + if (yych <= 'E') goto yy73; + if (yych == 'e') goto yy73; + goto yy20; + } +yy81: + ++YYCURSOR; + yych = *YYCURSOR; +yy82: + if (yybm[0+yych] & 128) { + goto yy81; + } + goto yy8; +yy83: + ++YYCURSOR; + yych = *YYCURSOR; + goto yy8; + } +/* *********************************** */ +yyc_STR_P1: + yych = *YYCURSOR; + if (yych <= 0xDF) { + if (yych <= '[') { + if (yych <= 0x1F) goto yy86; + if (yych == '"') goto yy90; + goto yy88; + } else { + if (yych <= '\\') goto yy92; + if (yych <= 0x7F) goto yy88; + if (yych <= 0xC1) goto yy94; + goto yy96; + } + } else { + if (yych <= 0xEF) { + if (yych <= 0xE0) goto yy97; + if (yych <= 0xEC) goto yy98; + if (yych <= 0xED) goto yy99; + goto yy100; + } else { + if (yych <= 0xF0) goto yy101; + if (yych <= 0xF3) goto yy102; + if (yych <= 0xF4) goto yy103; + goto yy94; + } + } +yy86: + ++YYCURSOR; + { + s->errcode = PHP_JSON_ERROR_CTRL_CHAR; + return PHP_JSON_T_ERROR; + } +yy88: + ++YYCURSOR; +yy89: + { PHP_JSON_CONDITION_GOTO(STR_P1); } +yy90: + ++YYCURSOR; + { + zend_string *str; + size_t len = s->cursor - s->str_start - s->str_esc - 1; + if (len == 0) { + PHP_JSON_CONDITION_SET(JS); + ZVAL_EMPTY_STRING(&s->value); + return PHP_JSON_T_ESTRING; + } + str = zend_string_alloc(len, 0); + ZSTR_VAL(str)[len] = '\0'; + ZVAL_STR(&s->value, str); + if (s->str_esc) { + s->pstr = (php_json_ctype *) Z_STRVAL(s->value); + s->cursor = s->str_start; + PHP_JSON_CONDITION_SET(STR_P2); + PHP_JSON_CONDITION_GOTO(STR_P2); + } else { + memcpy(Z_STRVAL(s->value), s->str_start, len); + PHP_JSON_CONDITION_SET(JS); + return PHP_JSON_T_STRING; + } + } +yy92: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 'e') { + if (yych <= '/') { + if (yych == '"') goto yy116; + if (yych >= '/') goto yy116; + } else { + if (yych <= '\\') { + if (yych >= '\\') goto yy116; + } else { + if (yych == 'b') goto yy116; + } + } + } else { + if (yych <= 'q') { + if (yych <= 'f') goto yy116; + if (yych == 'n') goto yy116; + } else { + if (yych <= 's') { + if (yych <= 'r') goto yy116; + } else { + if (yych <= 't') goto yy116; + if (yych <= 'u') goto yy118; + } + } + } +yy93: + { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } +yy94: + ++YYCURSOR; +yy95: + { + s->errcode = PHP_JSON_ERROR_UTF8; + return PHP_JSON_T_ERROR; + } +yy96: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy95; + if (yych <= 0xBF) goto yy107; + goto yy95; +yy97: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x9F) goto yy95; + if (yych <= 0xBF) goto yy115; + goto yy95; +yy98: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy95; + if (yych <= 0xBF) goto yy114; + goto yy95; +yy99: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy95; + if (yych <= 0x9F) goto yy113; + goto yy95; +yy100: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy95; + if (yych <= 0xBF) goto yy112; + goto yy95; +yy101: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x8F) goto yy95; + if (yych <= 0xBF) goto yy110; + goto yy95; +yy102: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy95; + if (yych <= 0xBF) goto yy108; + goto yy95; +yy103: + yyaccept = 1; + yych = *(YYMARKER = ++YYCURSOR); + if (yych <= 0x7F) goto yy95; + if (yych >= 0x90) goto yy95; + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych <= 0xBF) goto yy106; +yy105: + YYCURSOR = YYMARKER; + if (yyaccept <= 1) { + if (yyaccept == 0) { + goto yy93; + } else { + goto yy95; + } + } else { + goto yy127; + } +yy106: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych >= 0xC0) goto yy105; +yy107: + yych = *++YYCURSOR; + goto yy89; +yy108: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych >= 0xC0) goto yy105; + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych <= 0xBF) goto yy107; + goto yy105; +yy110: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych >= 0xC0) goto yy105; + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych <= 0xBF) goto yy107; + goto yy105; +yy112: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych <= 0xBF) goto yy107; + goto yy105; +yy113: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych <= 0xBF) goto yy107; + goto yy105; +yy114: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych <= 0xBF) goto yy107; + goto yy105; +yy115: + yych = *++YYCURSOR; + if (yych <= 0x7F) goto yy105; + if (yych <= 0xBF) goto yy107; + goto yy105; +yy116: + ++YYCURSOR; + { + s->str_esc++; + PHP_JSON_CONDITION_GOTO(STR_P1); + } +yy118: + yych = *++YYCURSOR; + if (yych <= 'D') { + if (yych <= '9') { + if (yych <= '/') goto yy105; + if (yych >= '1') goto yy120; + } else { + if (yych <= '@') goto yy105; + if (yych <= 'C') goto yy120; + goto yy121; + } + } else { + if (yych <= 'c') { + if (yych <= 'F') goto yy120; + if (yych <= '`') goto yy105; + goto yy120; + } else { + if (yych <= 'd') goto yy121; + if (yych <= 'f') goto yy120; + goto yy105; + } + } + yych = *++YYCURSOR; + if (yych <= '9') { + if (yych <= '/') goto yy105; + if (yych <= '0') goto yy140; + if (yych <= '7') goto yy141; + goto yy122; + } else { + if (yych <= 'F') { + if (yych <= '@') goto yy105; + goto yy122; + } else { + if (yych <= '`') goto yy105; + if (yych <= 'f') goto yy122; + goto yy105; + } + } +yy120: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych <= '9') goto yy122; + goto yy105; + } else { + if (yych <= 'F') goto yy122; + if (yych <= '`') goto yy105; + if (yych <= 'f') goto yy122; + goto yy105; + } +yy121: + yych = *++YYCURSOR; + if (yych <= 'B') { + if (yych <= '7') { + if (yych <= '/') goto yy105; + } else { + if (yych <= '9') goto yy123; + if (yych <= '@') goto yy105; + goto yy123; + } + } else { + if (yych <= '`') { + if (yych <= 'F') goto yy124; + goto yy105; + } else { + if (yych <= 'b') goto yy123; + if (yych <= 'f') goto yy124; + goto yy105; + } + } +yy122: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych <= '9') goto yy137; + goto yy105; + } else { + if (yych <= 'F') goto yy137; + if (yych <= '`') goto yy105; + if (yych <= 'f') goto yy137; + goto yy105; + } +yy123: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych <= '9') goto yy128; + goto yy105; + } else { + if (yych <= 'F') goto yy128; + if (yych <= '`') goto yy105; + if (yych <= 'f') goto yy128; + goto yy105; + } +yy124: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy125; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy125: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy126; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy126: + ++YYCURSOR; +yy127: + { + s->errcode = PHP_JSON_ERROR_UTF16; + return PHP_JSON_T_ERROR; + } +yy128: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy129; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy129: + yyaccept = 2; + yych = *(YYMARKER = ++YYCURSOR); + if (yych != '\\') goto yy127; + yych = *++YYCURSOR; + if (yych != 'u') goto yy105; + yych = *++YYCURSOR; + if (yych == 'D') goto yy132; + if (yych != 'd') goto yy105; +yy132: + yych = *++YYCURSOR; + if (yych <= 'B') goto yy105; + if (yych <= 'F') goto yy133; + if (yych <= 'b') goto yy105; + if (yych >= 'g') goto yy105; +yy133: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy134; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy134: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy135; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy135: + ++YYCURSOR; + { + s->str_esc += 8; + PHP_JSON_CONDITION_GOTO(STR_P1); + } +yy137: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy138; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy138: + ++YYCURSOR; + { + s->str_esc += 3; + PHP_JSON_CONDITION_GOTO(STR_P1); + } +yy140: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych <= '7') goto yy145; + if (yych <= '9') goto yy142; + goto yy105; + } else { + if (yych <= 'F') goto yy142; + if (yych <= '`') goto yy105; + if (yych <= 'f') goto yy142; + goto yy105; + } +yy141: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy142; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy142: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy143; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy143: + ++YYCURSOR; + { + s->str_esc += 4; + PHP_JSON_CONDITION_GOTO(STR_P1); + } +yy145: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy105; + if (yych >= ':') goto yy105; + } else { + if (yych <= 'F') goto yy146; + if (yych <= '`') goto yy105; + if (yych >= 'g') goto yy105; + } +yy146: + ++YYCURSOR; + { + s->str_esc += 5; + PHP_JSON_CONDITION_GOTO(STR_P1); + } +/* *********************************** */ +yyc_STR_P2: + yych = *YYCURSOR; + if (yych == '"') goto yy152; + if (yych == '\\') goto yy154; + ++YYCURSOR; + { PHP_JSON_CONDITION_GOTO(STR_P2); } +yy152: + ++YYCURSOR; + YYSETCONDITION(yycJS); + { + PHP_JSON_SCANNER_COPY_ESC(); + return PHP_JSON_T_STRING; + } +yy154: + yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if (yych == 'u') goto yy156; +yy155: + { + char esc; + PHP_JSON_SCANNER_COPY_ESC(); + switch (*s->cursor) { + case 'b': + esc = '\b'; + break; + case 'f': + esc = '\f'; + break; + case 'n': + esc = '\n'; + break; + case 'r': + esc = '\r'; + break; + case 't': + esc = '\t'; + break; + case '\\': + case '/': + case '"': + esc = *s->cursor; + break; + default: + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } + *(s->pstr++) = esc; + ++YYCURSOR; + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } +yy156: + yych = *++YYCURSOR; + if (yych <= 'D') { + if (yych <= '9') { + if (yych <= '/') goto yy157; + if (yych <= '0') goto yy158; + goto yy159; + } else { + if (yych <= '@') goto yy157; + if (yych <= 'C') goto yy159; + goto yy160; + } + } else { + if (yych <= 'c') { + if (yych <= 'F') goto yy159; + if (yych >= 'a') goto yy159; + } else { + if (yych <= 'd') goto yy160; + if (yych <= 'f') goto yy159; + } + } +yy157: + YYCURSOR = YYMARKER; + goto yy155; +yy158: + yych = *++YYCURSOR; + if (yych <= '9') { + if (yych <= '/') goto yy157; + if (yych <= '0') goto yy175; + if (yych <= '7') goto yy176; + goto yy162; + } else { + if (yych <= 'F') { + if (yych <= '@') goto yy157; + goto yy162; + } else { + if (yych <= '`') goto yy157; + if (yych <= 'f') goto yy162; + goto yy157; + } + } +yy159: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych <= '9') goto yy162; + goto yy157; + } else { + if (yych <= 'F') goto yy162; + if (yych <= '`') goto yy157; + if (yych <= 'f') goto yy162; + goto yy157; + } +yy160: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych <= '7') goto yy162; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'B') goto yy161; + if (yych <= '`') goto yy157; + if (yych >= 'c') goto yy157; + } +yy161: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych <= '9') goto yy166; + goto yy157; + } else { + if (yych <= 'F') goto yy166; + if (yych <= '`') goto yy157; + if (yych <= 'f') goto yy166; + goto yy157; + } +yy162: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy163; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy163: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy164; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy164: + ++YYCURSOR; + { + int utf16 = php_json_ucs2_to_int(s, 4); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) (0xe0 | (utf16 >> 12)); + *(s->pstr++) = (char) (0x80 | ((utf16 >> 6) & 0x3f)); + *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } +yy166: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy167; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy167: + yych = *++YYCURSOR; + if (yych != '\\') goto yy157; + yych = *++YYCURSOR; + if (yych != 'u') goto yy157; + yych = *++YYCURSOR; + if (yych == 'D') goto yy170; + if (yych != 'd') goto yy157; +yy170: + yych = *++YYCURSOR; + if (yych <= 'B') goto yy157; + if (yych <= 'F') goto yy171; + if (yych <= 'b') goto yy157; + if (yych >= 'g') goto yy157; +yy171: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy172; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy172: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy173; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy173: + ++YYCURSOR; + { + int utf32, utf16_hi, utf16_lo; + utf16_hi = php_json_ucs2_to_int(s, 4); + utf16_lo = php_json_ucs2_to_int_ex(s, 4, 7); + utf32 = ((utf16_lo & 0x3FF) << 10) + (utf16_hi & 0x3FF) + 0x10000; + PHP_JSON_SCANNER_COPY_UTF_SP(); + *(s->pstr++) = (char) (0xf0 | (utf32 >> 18)); + *(s->pstr++) = (char) (0x80 | ((utf32 >> 12) & 0x3f)); + *(s->pstr++) = (char) (0x80 | ((utf32 >> 6) & 0x3f)); + *(s->pstr++) = (char) (0x80 | (utf32 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } +yy175: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych <= '7') goto yy180; + if (yych <= '9') goto yy177; + goto yy157; + } else { + if (yych <= 'F') goto yy177; + if (yych <= '`') goto yy157; + if (yych <= 'f') goto yy177; + goto yy157; + } +yy176: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy177; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy177: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy178; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy178: + ++YYCURSOR; + { + int utf16 = php_json_ucs2_to_int(s, 3); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) (0xc0 | (utf16 >> 6)); + *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } +yy180: + yych = *++YYCURSOR; + if (yych <= '@') { + if (yych <= '/') goto yy157; + if (yych >= ':') goto yy157; + } else { + if (yych <= 'F') goto yy181; + if (yych <= '`') goto yy157; + if (yych >= 'g') goto yy157; + } +yy181: + ++YYCURSOR; + { + int utf16 = php_json_ucs2_to_int(s, 2); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) utf16; + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + } + + +} + diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re new file mode 100644 index 0000000000..267de96771 --- /dev/null +++ b/ext/json/json_scanner.re @@ -0,0 +1,359 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_json_scanner.h" +#include "php_json_scanner_defs.h" +#include "php_json_parser.h" +#include "json_parser.tab.h" + +#define YYCTYPE php_json_ctype +#define YYCURSOR s->cursor +#define YYLIMIT s->limit +#define YYMARKER s->marker +#define YYCTXMARKER s->ctxmarker + +#define YYGETCONDITION() s->state +#define YYSETCONDITION(yystate) s->state = yystate + +#define YYFILL(n) + +#define PHP_JSON_CONDITION_SET(condition) YYSETCONDITION(yyc##condition) +#define PHP_JSON_CONDITION_GOTO(condition) goto yyc_##condition + +#define PHP_JSON_SCANNER_COPY_ESC() php_json_scanner_copy_string(s, 0) +#define PHP_JSON_SCANNER_COPY_UTF() php_json_scanner_copy_string(s, 5) +#define PHP_JSON_SCANNER_COPY_UTF_SP() php_json_scanner_copy_string(s, 11) + +#define PHP_JSON_INT_MAX_LENGTH (MAX_LENGTH_OF_LONG - 1) + + +static void php_json_scanner_copy_string(php_json_scanner *s, int esc_size) +{ + size_t len = s->cursor - s->str_start - esc_size - 1; + if (len) { + memcpy(s->pstr, s->str_start, len); + s->pstr += len; + } +} + +static int php_json_hex_to_int(char code) +{ + if (code >= '0' && code <= '9') { + return code - '0'; + } else if (code >= 'A' && code <= 'F') { + return code - ('A' - 10); + } else if (code >= 'a' && code <= 'f') { + return code - ('a' - 10); + } else { + /* this should never happened (just to suppress compiler warning) */ + return -1; + } +} + +static int php_json_ucs2_to_int_ex(php_json_scanner *s, int size, int start) +{ + int i, code = 0; + php_json_ctype *pc = s->cursor - start; + for (i = 0; i < size; i++) { + code |= php_json_hex_to_int(*(pc--)) << (i * 4); + } + return code; +} + +static int php_json_ucs2_to_int(php_json_scanner *s, int size) +{ + return php_json_ucs2_to_int_ex(s, size, 1); +} + +void php_json_scanner_init(php_json_scanner *s, char *str, size_t str_len, int options) +{ + s->cursor = (php_json_ctype *) str; + s->limit = (php_json_ctype *) str + str_len; + s->options = options; + PHP_JSON_CONDITION_SET(JS); +} + +int php_json_scan(php_json_scanner *s) +{ + ZVAL_NULL(&s->value); + +std: + s->token = s->cursor; + +/*!re2c + re2c:indent:top = 1; + re2c:yyfill:enable = 0; + + DIGIT = [0-9] ; + DIGITNZ = [1-9] ; + UINT = "0" | ( DIGITNZ DIGIT* ) ; + INT = "-"? UINT ; + HEX = DIGIT | [a-fA-F] ; + HEXNZ = DIGITNZ | [a-fA-F] ; + HEX7 = [0-7] ; + HEXC = DIGIT | [a-cA-C] ; + FLOAT = INT "." DIGIT+ ; + EXP = ( INT | FLOAT ) [eE] [+-]? DIGIT+ ; + NL = "\r"? "\n" ; + WS = [ \t\r]+ ; + EOI = "\000"; + CTRL = [\x00-\x1F] ; + UTF8T = [\x80-\xBF] ; + UTF8_1 = [\x00-\x7F] ; + UTF8_2 = [\xC2-\xDF] UTF8T ; + UTF8_3A = "\xE0" [\xA0-\xBF] UTF8T ; + UTF8_3B = [\xE1-\xEC] UTF8T{2} ; + UTF8_3C = "\xED" [\x80-\x9F] UTF8T ; + UTF8_3D = [\xEE-\xEF] UTF8T{2} ; + UTF8_3 = UTF8_3A | UTF8_3B | UTF8_3C | UTF8_3D ; + UTF8_4A = "\xF0"[\x90-\xBF] UTF8T{2} ; + UTF8_4B = [\xF1-\xF3] UTF8T{3} ; + UTF8_4C = "\xF4" [\x80-\x8F] UTF8T{2} ; + UTF8_4 = UTF8_4A | UTF8_4B | UTF8_4C ; + UTF8 = UTF8_1 | UTF8_2 | UTF8_3 | UTF8_4 ; + ANY = [^] ; + ESCPREF = "\\" ; + ESCSYM = ( "\"" | "\\" | "/" | [bfnrt] ) ; + ESC = ESCPREF ESCSYM ; + UTFSYM = "u" ; + UTFPREF = ESCPREF UTFSYM ; + UCS2 = UTFPREF HEX{4} ; + UTF16_1 = UTFPREF "00" HEX7 HEX ; + UTF16_2 = UTFPREF "0" HEX7 HEX{2} ; + UTF16_3 = UTFPREF ( ( ( HEXC | [efEF] ) HEX ) | ( [dD] HEX7 ) ) HEX{2} ; + UTF16_4 = UTFPREF [dD] [89abAB] HEX{2} UTFPREF [dD] [c-fC-F] HEX{2} ; + + <JS>"{" { return '{'; } + <JS>"}" { return '}'; } + <JS>"[" { return '['; } + <JS>"]" { return ']'; } + <JS>":" { return ':'; } + <JS>"," { return ','; } + <JS>"null" { + ZVAL_NULL(&s->value); + return PHP_JSON_T_NUL; + } + <JS>"true" { + ZVAL_TRUE(&s->value); + return PHP_JSON_T_TRUE; + } + <JS>"false" { + ZVAL_FALSE(&s->value); + return PHP_JSON_T_FALSE; + } + <JS>INT { + zend_bool bigint = 0, negative = s->token[0] == '-'; + size_t digits = (size_t) (s->cursor - s->token - negative); + if (digits >= PHP_JSON_INT_MAX_LENGTH) { + if (digits == PHP_JSON_INT_MAX_LENGTH) { + int cmp = strncmp((char *) (s->token + negative), LONG_MIN_DIGITS, PHP_JSON_INT_MAX_LENGTH); + if (!(cmp < 0 || (cmp == 0 && negative))) { + bigint = 1; + } + } else { + bigint = 1; + } + } + if (!bigint) { + ZVAL_LONG(&s->value, ZEND_STRTOL((char *) s->token, NULL, 10)); + return PHP_JSON_T_INT; + } else if (s->options & PHP_JSON_BIGINT_AS_STRING) { + ZVAL_STRINGL(&s->value, (char *) s->token, s->cursor - s->token); + return PHP_JSON_T_STRING; + } else { + ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); + return PHP_JSON_T_DOUBLE; + } + } + <JS>FLOAT|EXP { + ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); + return PHP_JSON_T_DOUBLE; + } + <JS>NL|WS { goto std; } + <JS>EOI { + if (s->limit < s->cursor) { + return PHP_JSON_T_EOI; + } else { + s->errcode = PHP_JSON_ERROR_CTRL_CHAR; + return PHP_JSON_T_ERROR; + } + } + <JS>["] { + s->str_start = s->cursor; + s->str_esc = 0; + PHP_JSON_CONDITION_SET(STR_P1); + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <JS>CTRL { + s->errcode = PHP_JSON_ERROR_CTRL_CHAR; + return PHP_JSON_T_ERROR; + } + <JS>UTF8 { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } + <JS>ANY { + s->errcode = PHP_JSON_ERROR_UTF8; + return PHP_JSON_T_ERROR; + } + + <STR_P1>CTRL { + s->errcode = PHP_JSON_ERROR_CTRL_CHAR; + return PHP_JSON_T_ERROR; + } + <STR_P1>UTF16_1 { + s->str_esc += 5; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UTF16_2 { + s->str_esc += 4; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UTF16_3 { + s->str_esc += 3; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UTF16_4 { + s->str_esc += 8; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UCS2 { + s->errcode = PHP_JSON_ERROR_UTF16; + return PHP_JSON_T_ERROR; + } + <STR_P1>ESC { + s->str_esc++; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>ESCPREF { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } + <STR_P1>["] { + zend_string *str; + size_t len = s->cursor - s->str_start - s->str_esc - 1; + if (len == 0) { + PHP_JSON_CONDITION_SET(JS); + ZVAL_EMPTY_STRING(&s->value); + return PHP_JSON_T_ESTRING; + } + str = zend_string_alloc(len, 0); + ZSTR_VAL(str)[len] = '\0'; + ZVAL_STR(&s->value, str); + if (s->str_esc) { + s->pstr = (php_json_ctype *) Z_STRVAL(s->value); + s->cursor = s->str_start; + PHP_JSON_CONDITION_SET(STR_P2); + PHP_JSON_CONDITION_GOTO(STR_P2); + } else { + memcpy(Z_STRVAL(s->value), s->str_start, len); + PHP_JSON_CONDITION_SET(JS); + return PHP_JSON_T_STRING; + } + } + <STR_P1>UTF8 { PHP_JSON_CONDITION_GOTO(STR_P1); } + <STR_P1>ANY { + s->errcode = PHP_JSON_ERROR_UTF8; + return PHP_JSON_T_ERROR; + } + + <STR_P2>UTF16_1 { + int utf16 = php_json_ucs2_to_int(s, 2); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) utf16; + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>UTF16_2 { + int utf16 = php_json_ucs2_to_int(s, 3); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) (0xc0 | (utf16 >> 6)); + *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>UTF16_3 { + int utf16 = php_json_ucs2_to_int(s, 4); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) (0xe0 | (utf16 >> 12)); + *(s->pstr++) = (char) (0x80 | ((utf16 >> 6) & 0x3f)); + *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>UTF16_4 { + int utf32, utf16_hi, utf16_lo; + utf16_hi = php_json_ucs2_to_int(s, 4); + utf16_lo = php_json_ucs2_to_int_ex(s, 4, 7); + utf32 = ((utf16_lo & 0x3FF) << 10) + (utf16_hi & 0x3FF) + 0x10000; + PHP_JSON_SCANNER_COPY_UTF_SP(); + *(s->pstr++) = (char) (0xf0 | (utf32 >> 18)); + *(s->pstr++) = (char) (0x80 | ((utf32 >> 12) & 0x3f)); + *(s->pstr++) = (char) (0x80 | ((utf32 >> 6) & 0x3f)); + *(s->pstr++) = (char) (0x80 | (utf32 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>ESCPREF { + char esc; + PHP_JSON_SCANNER_COPY_ESC(); + switch (*s->cursor) { + case 'b': + esc = '\b'; + break; + case 'f': + esc = '\f'; + break; + case 'n': + esc = '\n'; + break; + case 'r': + esc = '\r'; + break; + case 't': + esc = '\t'; + break; + case '\\': + case '/': + case '"': + esc = *s->cursor; + break; + default: + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } + *(s->pstr++) = esc; + ++YYCURSOR; + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>["] => JS { + PHP_JSON_SCANNER_COPY_ESC(); + return PHP_JSON_T_STRING; + } + <STR_P2>ANY { PHP_JSON_CONDITION_GOTO(STR_P2); } + + <*>ANY { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } +*/ + +} + diff --git a/ext/json/package.xml b/ext/json/package.xml deleted file mode 100644 index b59e47cf0b..0000000000 --- a/ext/json/package.xml +++ /dev/null @@ -1,148 +0,0 @@ -<?xml version="1.0" encoding="ISO-8859-1" ?> -<!DOCTYPE package SYSTEM "../pear/package.dtd"> -<package> - <dep type="php" rel="ge" version="4.3.0" optional="no"/> - <name>json</name> - <summary>JavaScript Object Notation</summary> - <maintainers> - <maintainer> - <user>omar</user> - <name>Omar Kilani</name> - <email>omar@php.net</email> - <role>lead</role> - </maintainer> - </maintainers> - <description> - Support for JSON (JavaScript Object Notation) serialization. - </description> - <license>PHP 3.01</license> - <release> - <state>stable</state> - <version>1.2.1</version> - <date>2006-03-18</date> - <notes> - Fix PECL bug #7147 - rework handling of comma insertion while encoding. - Add tests to package.xml - </notes> - </release> - <configureoptions> - </configureoptions> - <filelist> - <file role="doc" name="README" /> - <file role="src" name="config.m4" /> - <file role="src" name="config.w32" /> - <file role="src" name="json.dsp" /> - <file role="src" name="json.c" /> - <file role="src" name="JSON_parser.c" /> - <file role="src" name="JSON_parser.h" /> - <file role="src" name="php_json.h" /> - <dir role="test" name="tests"> - <file role="test" name="fail001.phpt" /> - <file role="test" name="pass001.phpt" /> - <file role="test" name="pass001.1.phpt" /> - <file role="test" name="pass002.phpt" /> - <file role="test" name="pass003.phpt" /> - </dir> - </filelist> - <changelog> - <release> - <state>stable</state> - <version>1.0.0</version> - <date>2005-04-01</date> - <notes> - Initial release. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.1</version> - <date>2005-06-10</date> - <notes> - Fixed non-linear and mixed type array index issues, fixed issues with escaping \\, forked json-c and added Unicode support. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.2</version> - <date>2005-06-11</date> - <notes> - Fixed issues with object reference counts under PHP4. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.3</version> - <date>2005-06-15</date> - <notes> - Fixed json-c string corruption issues under Mac OS X and FreeBSD. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.4</version> - <date>2005-06-15</date> - <notes> - Changes in 1.0.4 released with 1.0.5. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.5</version> - <date>2005-06-16</date> - <notes> - Changed spacing in json-c encoding, added optional assoc (boolean) parameter to json_decode to decode as associative array instead of object, fixed issues with escaping /. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.6</version> - <date>2005-08-05</date> - <notes> - Fixed issues with exporting private and protected class members. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.7</version> - <date>2005-09-07</date> - <notes> - Fixed issues with negative array keys, modified json-c to return an error on unquoted object key names instead of going into an infinite loop. - </notes> - </release> - <release> - <state>stable</state> - <version>1.0.8</version> - <date>2005-12-01</date> - <notes> - Changed license to LGPL, modified build system to allow static compilation into PHP, added strndup check for json-c. - </notes> - </release> - <release> - <state>stable</state> - <version>1.1.0</version> - <date>2005-12-04</date> - <notes> - Port to Win32. - </notes> - </release> - <release> - <state>stable</state> - <version>1.1.1</version> - <date>2006-01-12</date> - <notes> - Cleanup and TSRM performance fixes by rasmus. - </notes> - </release> - <release> - <state>stable</state> - <version>1.2.0</version> - <date>2006-03-15</date> - <notes> - Complete rewrite using JSON_checker as the base for the parser. Implements the JSON specification. 3-8x faster on encodes and 1.2x-4x faster on decodes. - </notes> - </release> - </changelog> -</package> -<!-- -vim:et:ts=1:sw=1 ---> diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 148232e8d7..7bcca27335 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ @@ -13,6 +13,7 @@ | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Omar Kilani <omar@php.net> | + | Jakub Zelenka <bukka@php.net> | +----------------------------------------------------------------------+ */ @@ -21,8 +22,8 @@ #ifndef PHP_JSON_H #define PHP_JSON_H -#define PHP_JSON_VERSION "1.2.1" -#include "ext/standard/php_smart_str.h" +#define PHP_JSON_VERSION "1.4.0" +#include "zend_smart_str_public.h" extern zend_module_entry json_module_entry; #define phpext_json_ptr &json_module_entry @@ -37,47 +38,66 @@ extern zend_module_entry json_module_entry; #include "TSRM.h" #endif -ZEND_BEGIN_MODULE_GLOBALS(json) - int encoder_depth; - int error_code; - int encode_max_depth; -ZEND_END_MODULE_GLOBALS(json) - -#ifdef ZTS -# define JSON_G(v) TSRMG(json_globals_id, zend_json_globals *, v) -#else -# define JSON_G(v) (json_globals.v) -#endif - -PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC); -PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC); extern PHP_JSON_API zend_class_entry *php_json_serializable_ce; +/* error codes */ +typedef enum { + PHP_JSON_ERROR_NONE = 0, + PHP_JSON_ERROR_DEPTH, + PHP_JSON_ERROR_STATE_MISMATCH, + PHP_JSON_ERROR_CTRL_CHAR, + PHP_JSON_ERROR_SYNTAX, + PHP_JSON_ERROR_UTF8, + PHP_JSON_ERROR_RECURSION, + PHP_JSON_ERROR_INF_OR_NAN, + PHP_JSON_ERROR_UNSUPPORTED_TYPE, + PHP_JSON_ERROR_INVALID_PROPERTY_NAME, + PHP_JSON_ERROR_UTF16 +} php_json_error_code; /* json_encode() options */ -#define PHP_JSON_HEX_TAG (1<<0) -#define PHP_JSON_HEX_AMP (1<<1) -#define PHP_JSON_HEX_APOS (1<<2) -#define PHP_JSON_HEX_QUOT (1<<3) -#define PHP_JSON_FORCE_OBJECT (1<<4) -#define PHP_JSON_NUMERIC_CHECK (1<<5) -#define PHP_JSON_UNESCAPED_SLASHES (1<<6) -#define PHP_JSON_PRETTY_PRINT (1<<7) -#define PHP_JSON_UNESCAPED_UNICODE (1<<8) +#define PHP_JSON_HEX_TAG (1<<0) +#define PHP_JSON_HEX_AMP (1<<1) +#define PHP_JSON_HEX_APOS (1<<2) +#define PHP_JSON_HEX_QUOT (1<<3) +#define PHP_JSON_FORCE_OBJECT (1<<4) +#define PHP_JSON_NUMERIC_CHECK (1<<5) +#define PHP_JSON_UNESCAPED_SLASHES (1<<6) +#define PHP_JSON_PRETTY_PRINT (1<<7) +#define PHP_JSON_UNESCAPED_UNICODE (1<<8) #define PHP_JSON_PARTIAL_OUTPUT_ON_ERROR (1<<9) -#define PHP_JSON_PRESERVE_ZERO_FRACTION (1<<10) +#define PHP_JSON_PRESERVE_ZERO_FRACTION (1<<10) + +/* json_decode() options */ +#define PHP_JSON_OBJECT_AS_ARRAY (1<<0) +#define PHP_JSON_BIGINT_AS_STRING (1<<1) /* Internal flags */ #define PHP_JSON_OUTPUT_ARRAY 0 #define PHP_JSON_OUTPUT_OBJECT 1 -/* json_decode() options */ -#define PHP_JSON_OBJECT_AS_ARRAY (1<<0) -#define PHP_JSON_BIGINT_AS_STRING (1<<1) +/* default depth */ +#define PHP_JSON_PARSER_DEFAULT_DEPTH 512 + +ZEND_BEGIN_MODULE_GLOBALS(json) + int encoder_depth; + int encode_max_depth; + php_json_error_code error_code; +ZEND_END_MODULE_GLOBALS(json) + +PHP_JSON_API ZEND_EXTERN_MODULE_GLOBALS(json) +#define JSON_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(json, v) + +#if defined(ZTS) && defined(COMPILE_DL_JSON) +ZEND_TSRMLS_CACHE_EXTERN() +#endif + +PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options); +PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, size_t str_len, zend_long options, zend_long depth); -static inline void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC) +static inline void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, zend_long depth) { - php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth TSRMLS_CC); + php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth); } diff --git a/ext/json/php_json_encoder.h b/ext/json/php_json_encoder.h new file mode 100644 index 0000000000..b10f7a614a --- /dev/null +++ b/ext/json/php_json_encoder.h @@ -0,0 +1,27 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_JSON_ENCODER_H +#define PHP_JSON_ENCODER_H + +#include "php.h" +#include "zend_smart_str.h" + +void php_json_encode_zval(smart_str *buf, zval *val, int options); + +#endif /* PHP_JSON_ENCODER_H */ diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h new file mode 100644 index 0000000000..6964ef8e8e --- /dev/null +++ b/ext/json/php_json_parser.h @@ -0,0 +1,39 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_JSON_PARSER_H +#define PHP_JSON_PARSER_H + +#include "php.h" +#include "php_json_scanner.h" + +typedef struct _php_json_parser { + php_json_scanner scanner; + zval *return_value; + int depth; + int max_depth; +} php_json_parser; + +void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth); + +php_json_error_code php_json_parser_error_code(php_json_parser *parser); + +int php_json_yyparse(php_json_parser *parser); + +#endif /* PHP_JSON_PARSER_H */ + diff --git a/ext/json/php_json_scanner.h b/ext/json/php_json_scanner.h new file mode 100644 index 0000000000..0b73a1d4cd --- /dev/null +++ b/ext/json/php_json_scanner.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2016 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_JSON_SCANNER_H +#define PHP_JSON_SCANNER_H + +#include "php.h" +#include "php_json.h" + +typedef unsigned char php_json_ctype; + +typedef struct _php_json_scanner { + php_json_ctype *cursor; /* cursor position */ + php_json_ctype *token; /* token position */ + php_json_ctype *limit; /* the last read character + 1 position */ + php_json_ctype *marker; /* marker position for backtracking */ + php_json_ctype *ctxmarker; /* marker position for context backtracking */ + php_json_ctype *str_start; /* start position of the string */ + php_json_ctype *pstr; /* string pointer for escapes conversion */ + zval value; /* value */ + int str_esc; /* number of extra characters for escaping */ + int state; /* condition state */ + int options; /* options */ + php_json_error_code errcode; /* error type if there is an error */ +} php_json_scanner; + + +void php_json_scanner_init(php_json_scanner *scanner, char *str, size_t str_len, int options); +int php_json_scan(php_json_scanner *s); + +#endif /* PHP_JSON_SCANNER_H */ + diff --git a/ext/json/php_json_scanner_defs.h b/ext/json/php_json_scanner_defs.h new file mode 100644 index 0000000000..a75e766a65 --- /dev/null +++ b/ext/json/php_json_scanner_defs.h @@ -0,0 +1,7 @@ +/* Generated by re2c 0.14.3 */ + +enum YYCONDTYPE { + yycJS, + yycSTR_P1, + yycSTR_P2, +}; diff --git a/ext/json/tests/bug54484.phpt b/ext/json/tests/bug54484.phpt index 3a38475019..f70b96ee13 100644 --- a/ext/json/tests/bug54484.phpt +++ b/ext/json/tests/bug54484.phpt @@ -13,11 +13,15 @@ var_dump(json_last_error()); json_decode("invalid json"); var_dump(json_last_error()); +json_decode("\"\001 invalid json\""); +var_dump(json_last_error()); + json_decode(""); var_dump(json_last_error()); ?> --EXPECT-- int(0) -int(0) int(4) -int(0) +int(4) +int(3) +int(4) diff --git a/ext/json/tests/bug62010.phpt b/ext/json/tests/bug62010.phpt new file mode 100644 index 0000000000..ddac8963c3 --- /dev/null +++ b/ext/json/tests/bug62010.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #62010 (json_decode produces invalid byte-sequences) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php + +var_dump(json_decode('"\ud834"')); +var_dump(json_last_error() === JSON_ERROR_UTF16); +var_dump(json_last_error_msg()); +?> +--EXPECTF-- +NULL +bool(true) +string(50) "Single unpaired UTF-16 surrogate in unicode escape" diff --git a/ext/json/tests/bug68546.phpt b/ext/json/tests/bug68546.phpt new file mode 100644 index 0000000000..f8c8d135f3 --- /dev/null +++ b/ext/json/tests/bug68546.phpt @@ -0,0 +1,25 @@ +--TEST-- +Bug #68546 (json_decode() Fatal error: Cannot access property started with '\0') +--SKIPIF-- +<?php + +if (!extension_loaded('json')) die('skip'); +?> +--FILE-- +<?php + +var_dump(json_decode('{"key": {"\u0000": "aa"}}')); +var_dump(json_last_error() === JSON_ERROR_INVALID_PROPERTY_NAME); +var_dump(json_decode('[{"key1": 0, "\u0000": 1}]')); +var_dump(json_last_error() === JSON_ERROR_INVALID_PROPERTY_NAME); +var_dump(json_last_error_msg()); + +echo "Done\n"; +?> +--EXPECTF-- +NULL +bool(true) +NULL +bool(true) +string(36) "The decoded property name is invalid" +Done diff --git a/ext/json/tests/bug68817.phpt b/ext/json/tests/bug68817.phpt new file mode 100644 index 0000000000..aa9a63f93d --- /dev/null +++ b/ext/json/tests/bug68817.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #68817 (Null pointer deference) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php + +var_dump(json_decode('[""]')); + +?> +===DONE=== +--EXPECTF-- +array(1) { + [0]=> + string(0) "" +} +===DONE=== diff --git a/ext/json/tests/bug68938.phpt b/ext/json/tests/bug68938.phpt new file mode 100644 index 0000000000..f6291ffe62 --- /dev/null +++ b/ext/json/tests/bug68938.phpt @@ -0,0 +1,11 @@ +--TEST-- +Bug #68938 (json_decode() decodes empty string without indicating error) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php +json_decode(""); +var_dump(json_last_error()); +?> +--EXPECT-- +int(4) diff --git a/ext/json/tests/bug69187.phpt b/ext/json/tests/bug69187.phpt new file mode 100644 index 0000000000..d39dbe522d --- /dev/null +++ b/ext/json/tests/bug69187.phpt @@ -0,0 +1,49 @@ +--TEST-- +Bug #69187 json_last_error return BC in PHP7 +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php +var_dump(json_decode(NULL)); +var_dump(json_last_error()); +var_dump(json_decode(FALSE)); +var_dump(json_last_error()); +var_dump(json_decode("")); +var_dump(json_last_error()); + +var_dump(json_decode(0)); +var_dump(json_last_error()); +var_dump(json_decode(1)); +var_dump(json_last_error()); +var_dump(json_decode(TRUE)); +var_dump(json_last_error()); + +json_decode("\xED\xA0\xB4"); +var_dump(json_last_error()); + +json_decode("\x00"); +var_dump(json_last_error()); + +json_decode("\"\xED\xA0\xB4\""); +var_dump(json_last_error()); + +json_decode("\"\x00\""); +var_dump(json_last_error()); +?> +--EXPECT-- +NULL +int(4) +NULL +int(4) +NULL +int(4) +int(0) +int(0) +int(1) +int(0) +int(1) +int(0) +int(5) +int(3) +int(5) +int(3) diff --git a/ext/json/tests/bug71835.phpt b/ext/json/tests/bug71835.phpt new file mode 100644 index 0000000000..dbe313b70c --- /dev/null +++ b/ext/json/tests/bug71835.phpt @@ -0,0 +1,27 @@ +--TEST-- +Bug #71835 (json_encode sometimes incorrectly detects recursion with JsonSerializable) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php +class SomeClass implements JsonSerializable { + public function jsonSerialize() { + return [get_object_vars($this)]; + } +} +$class = new SomeClass; +$arr = [$class]; +var_dump(json_encode($arr)); + +class SomeClass2 implements JsonSerializable { + public function jsonSerialize() { + return [(array)$this]; + } +} +$class = new SomeClass2; +$arr = [$class]; +var_dump(json_encode($arr)); +?> +--EXPECT-- +string(6) "[[[]]]" +string(6) "[[[]]]" diff --git a/ext/json/tests/bug72069.phpt b/ext/json/tests/bug72069.phpt new file mode 100644 index 0000000000..0ff8c98621 --- /dev/null +++ b/ext/json/tests/bug72069.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #72069 (Behavior \JsonSerializable different from json_encode) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php + +$result = json_encode(['end' => json_decode(null, true)]); +var_dump($result); + +class A implements \JsonSerializable +{ + function jsonSerialize() + { + return ['end' => json_decode(null, true)]; + } +} +$a = new A(); +$toJsonData = $a->jsonSerialize(); +$result = json_encode($a); +var_dump($result); + +$result = json_encode($toJsonData); +var_dump($result); +?> +--EXPECT-- +string(12) "{"end":null}" +string(12) "{"end":null}" +string(12) "{"end":null}" diff --git a/ext/json/tests/pass003.phpt b/ext/json/tests/pass003.phpt index 5e8c1664d0..bdfbaf298c 100644 --- a/ext/json/tests/pass003.phpt +++ b/ext/json/tests/pass003.phpt @@ -37,7 +37,7 @@ $arr = json_decode($arr_enc, true); var_dump($arr); ?> ---EXPECT-- +--EXPECTF-- Testing: { "JSON Test Pattern pass3": { @@ -47,9 +47,9 @@ Testing: } DECODE: AS OBJECT -object(stdClass)#1 (1) { +object(stdClass)#%d (1) { ["JSON Test Pattern pass3"]=> - object(stdClass)#2 (2) { + object(stdClass)#%d (2) { ["The outermost value"]=> string(27) "must be an object or array." ["In this test"]=> @@ -71,9 +71,9 @@ ENCODE: FROM OBJECT ENCODE: FROM ARRAY {"JSON Test Pattern pass3":{"The outermost value":"must be an object or array.","In this test":"It is an object."}} DECODE AGAIN: AS OBJECT -object(stdClass)#3 (1) { +object(stdClass)#%d (1) { ["JSON Test Pattern pass3"]=> - object(stdClass)#4 (2) { + object(stdClass)#%d (2) { ["The outermost value"]=> string(27) "must be an object or array." ["In this test"]=> diff --git a/ext/json/tests/unsupported_type_error.phpt b/ext/json/tests/unsupported_type_error.phpt index 45a167a5ac..dd5a7963aa 100644 --- a/ext/json/tests/unsupported_type_error.phpt +++ b/ext/json/tests/unsupported_type_error.phpt @@ -17,7 +17,7 @@ var_dump(json_last_error(), json_last_error_msg()); ?> --EXPECTF-- -resource(5) of type (stream) +resource(%d) of type (stream) bool(false) int(8) string(21) "Type is not supported" |