diff options
Diffstat (limited to 'ext/json')
-rw-r--r-- | ext/json/JSON_parser.c | 182 | ||||
-rw-r--r-- | ext/json/JSON_parser.h | 4 | ||||
-rw-r--r-- | ext/json/json.c | 302 | ||||
-rw-r--r-- | ext/json/php_json.h | 4 | ||||
-rw-r--r-- | ext/json/tests/unsupported_type_error.phpt | 2 |
5 files changed, 235 insertions, 259 deletions
diff --git a/ext/json/JSON_parser.c b/ext/json/JSON_parser.c index dd832a7cbd..f2a1ee4dda 100644 --- a/ext/json/JSON_parser.c +++ b/ext/json/JSON_parser.c @@ -248,7 +248,7 @@ new_JSON_parser(int depth) 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); + jp->the_zstack = (zval *) safe_emalloc(depth, sizeof(zval), 0); } else { jp->the_zstack = &jp->the_static_zstack[0]; } @@ -291,23 +291,21 @@ static int dehexchar(char c) } -static void json_create_zval(zval **z, smart_str *buf, int type, int options) +static void json_create_zval(zval *z, smart_str *buf, int type, int options TSRMLS_DC) { - ALLOC_INIT_ZVAL(*z); - - if (type == IS_LONG) + if (type == IS_INT) { zend_bool bigint = 0; - if (buf->c[0] == '-') { - buf->len--; + if (buf->s->val[0] == '-') { + buf->s->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 (buf->s->len >= MAX_LENGTH_OF_ZEND_INT - 1) { + if (buf->s->len == MAX_LENGTH_OF_ZEND_INT - 1) { + int cmp = strcmp(buf->s->val + (buf->s->val[0] == '-'), int_min_digits); - if (!(cmp < 0 || (cmp == 0 && buf->c[0] == '-'))) { + if (!(cmp < 0 || (cmp == 0 && buf->s->val[0] == '-'))) { bigint = 1; } } else { @@ -318,9 +316,9 @@ static void json_create_zval(zval **z, smart_str *buf, int type, int options) if (bigint) { /* value too large to represent as a long */ if (options & PHP_JSON_BIGINT_AS_STRING) { - if (buf->c[0] == '-') { + if (buf->s->val[0] == '-') { /* Restore last char consumed above */ - buf->len++; + buf->s->len++; } goto use_string; } else { @@ -328,25 +326,31 @@ static void json_create_zval(zval **z, smart_str *buf, int type, int options) } } - ZVAL_LONG(*z, strtol(buf->c, NULL, 10)); + ZVAL_INT(z, strtol(buf->s->val, NULL, 10)); } else if (type == IS_DOUBLE) { use_double: - ZVAL_DOUBLE(*z, zend_strtod(buf->c, NULL)); + ZVAL_DOUBLE(z, zend_strtod(buf->s->val, NULL)); } else if (type == IS_STRING) { use_string: - ZVAL_STRINGL(*z, buf->c, buf->len, 1); + if (buf->s) { + ZVAL_STRINGL(z, buf->s->val, buf->s->len); + } else { + ZVAL_EMPTY_STRING(z); + } } - else if (type == IS_BOOL) - { - ZVAL_BOOL(*z, (*(buf->c) == 't')); + else if (type == IS_FALSE) { + ZVAL_FALSE(z); + } + else if (type == IS_TRUE) { + ZVAL_TRUE(z); } else /* type == IS_NULL) || type unknown */ { - ZVAL_NULL(*z); + ZVAL_NULL(z); } } @@ -363,18 +367,18 @@ static void utf16_to_utf8(smart_str *buf, unsigned short utf16) 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) + && buf->s->len >= 3 + && ((unsigned char) buf->s->val[buf->s->len - 3]) == 0xed + && ((unsigned char) buf->s->val[buf->s->len - 2] & 0xf0) == 0xa0 + && ((unsigned char) buf->s->val[buf->s->len - 1] & 0xc0) == 0x80) { /* found surrogate pair */ - unsigned long utf32; + php_uint_t utf32; - utf32 = (((buf->c[buf->len - 2] & 0xf) << 16) - | ((buf->c[buf->len - 1] & 0x3f) << 10) + utf32 = (((buf->s->val[buf->s->len - 2] & 0xf) << 16) + | ((buf->s->val[buf->s->len - 1] & 0x3f) << 10) | (utf16 & 0x3ff)) + 0x10000; - buf->len -= 3; + buf->s->len -= 3; smart_str_appendc(buf, (unsigned char) (0xf0 | (utf32 >> 18))); smart_str_appendc(buf, 0x80 | ((utf32 >> 12) & 0x3f)); @@ -389,10 +393,24 @@ static void utf16_to_utf8(smart_str *buf, unsigned short utf16) } } +static inline void add_assoc_or_property(int assoc, zval *target, smart_str *key, zval *zv TSRMLS_DC) +{ + zend_bool empty_key = !key->s || key->s->len == 0; + if (!assoc) { + add_property_zval_ex(target, empty_key ? "_empty_" : key->s->val, empty_key ? sizeof("_empty_")-1 : key->s->len, zv TSRMLS_CC); + if (Z_REFCOUNTED_P(zv)) Z_DELREF_P(zv); + } else { + add_assoc_zval_ex(target, empty_key ? "" : key->s->val, empty_key ? 0 : key->s->len, zv); + } + if (key->s) { + key->s->len = 0; + } +} + 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]; + zval *root = &jp->the_zstack[up]; + zval *child = &jp->the_zstack[cur]; int up_mode = jp->stack[up]; if (up_mode == MODE_ARRAY) @@ -401,30 +419,20 @@ static void attach_zval(JSON_parser jp, int up, int cur, smart_str *key, int ass } 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; + add_assoc_or_property(assoc, root, key, child TSRMLS_CC); } } #define FREE_BUFFERS() smart_str_free(&buf); smart_str_free(&key); #define SWAP_BUFFERS(from, to) do { \ - char *t1 = from.c; \ + zend_string *t1 = from.s; \ int t2 = from.a; \ - from.c = to.c; \ + from.s = to.s; \ from.a = to.a; \ - to.c = t1; \ + to.s = t1; \ to.a = t2; \ - to.len = from.len; \ - from.len = 0; \ + if (from.s) { from.s->len = 0; } \ } while(0); #define JSON_RESET_TYPE() type = -1; @@ -508,10 +516,10 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, 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; + } else if (type < IS_INT && (next_class == C_DIGIT || next_class == C_ZERO)) { + type = IS_INT; smart_str_appendc(&buf, next_char); - } else if (type == IS_LONG && next_state == E1) { + } else if (type == IS_INT && next_state == E1) { type = IS_DOUBLE; smart_str_appendc(&buf, next_char); } else if (type < IS_DOUBLE && next_class == C_POINT) { @@ -519,8 +527,10 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, 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_FALSE && (jp->state == F4 && next_state == OK)) { + type = IS_FALSE; + } else if (type < IS_TRUE && (jp->state == T3 && next_state == OK)) { + type = IS_TRUE; } else if (type < IS_NULL && jp->state == N3 && next_state == OK) { type = IS_NULL; } else if (type != IS_STRING && next_class > C_WHITE) { @@ -544,19 +554,14 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, case -8: if (type != -1 && jp->stack[jp->top] == MODE_OBJECT) { - zval *mval; + zval mval; smart_str_0(&buf); - json_create_zval(&mval, &buf, type, options); + json_create_zval(&mval, &buf, type, options TSRMLS_CC); - 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; + add_assoc_or_property(assoc, &jp->the_zstack[jp->top], &key, &mval TSRMLS_CC); + + if (buf.s) { buf.s->len = 0; } JSON_RESET_TYPE(); } @@ -572,12 +577,12 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, { if (type != -1 && jp->stack[jp->top] == MODE_ARRAY) { - zval *mval; + 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_create_zval(&mval, &buf, type, options TSRMLS_CC); + add_next_index_zval(&jp->the_zstack[jp->top], &mval); + buf.s->len = 0; JSON_RESET_TYPE(); } @@ -597,13 +602,7 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, jp->state = OB; if (jp->top > 0) { - zval *obj; - - if (jp->top == 1) { - obj = z; - } else { - ALLOC_INIT_ZVAL(obj); - } + zval *obj = &jp->the_zstack[jp->top]; if (!assoc) { object_init(obj); @@ -611,7 +610,9 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, array_init(obj); } - jp->the_zstack[jp->top] = obj; + if (jp->top == 1) { + ZVAL_COPY_VALUE(z, obj); + } if (jp->top > 1) { attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC); @@ -630,16 +631,13 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, jp->state = AR; if (jp->top > 0) { - zval *arr; - - if (jp->top == 1) { - arr = z; - } else { - ALLOC_INIT_ZVAL(arr); - } + zval *arr = &jp->the_zstack[jp->top]; array_init(arr); - jp->the_zstack[jp->top] = arr; + + if (jp->top == 1) { + ZVAL_COPY_VALUE(z, arr); + } if (jp->top > 1) { attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC); @@ -665,8 +663,12 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, break; case MODE_DONE: if (type == IS_STRING) { - smart_str_0(&buf); - ZVAL_STRINGL(z, buf.c, buf.len, 1); + if (buf.s) { + smart_str_0(&buf); + ZVAL_STRINGL(z, buf.s->val, buf.s->len); + } else { + ZVAL_EMPTY_STRING(z); + } jp->state = OK; break; } @@ -680,34 +682,28 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, /* , */ case -3: { - zval *mval; + 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); + json_create_zval(&mval, &buf, type, options TSRMLS_CC); } 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; + add_assoc_or_property(assoc, &jp->the_zstack[jp->top], &key, &mval TSRMLS_CC); } jp->state = KE; } break; case MODE_ARRAY: if (type != -1) { - add_next_index_zval(jp->the_zstack[jp->top], mval); + add_next_index_zval(&jp->the_zstack[jp->top], &mval); } jp->state = VA; break; @@ -716,7 +712,7 @@ parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, jp->error_code = PHP_JSON_ERROR_SYNTAX; return false; } - buf.len = 0; + if (buf.s) { buf.s->len = 0; } JSON_RESET_TYPE(); } break; diff --git a/ext/json/JSON_parser.h b/ext/json/JSON_parser.h index 8671765b4d..3df999c5f3 100644 --- a/ext/json/JSON_parser.h +++ b/ext/json/JSON_parser.h @@ -15,8 +15,8 @@ typedef struct JSON_parser_struct { int top; int error_code; int* stack; - zval **the_zstack; - zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH]; + zval *the_zstack; + zval the_static_zstack[JSON_PARSER_DEFAULT_DEPTH]; } * JSON_parser; enum error_codes { diff --git a/ext/json/json.c b/ext/json/json.c index f52215a484..60893fe1ea 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -93,29 +93,29 @@ static PHP_MINIT_FUNCTION(json) 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_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); + REGISTER_INT_CONSTANT("JSON_HEX_TAG", PHP_JSON_HEX_TAG, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_HEX_AMP", PHP_JSON_HEX_AMP, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_UNESCAPED_SLASHES", PHP_JSON_UNESCAPED_SLASHES, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_PRETTY_PRINT", PHP_JSON_PRETTY_PRINT, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_UNESCAPED_UNICODE", PHP_JSON_UNESCAPED_UNICODE, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_PARTIAL_OUTPUT_ON_ERROR", PHP_JSON_PARTIAL_OUTPUT_ON_ERROR, CONST_CS | CONST_PERSISTENT); + + REGISTER_INT_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_RECURSION", PHP_JSON_ERROR_RECURSION, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_INF_OR_NAN", PHP_JSON_ERROR_INF_OR_NAN, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_ERROR_UNSUPPORTED_TYPE", PHP_JSON_ERROR_UNSUPPORTED_TYPE, CONST_CS | CONST_PERSISTENT); + + REGISTER_INT_CONSTANT("JSON_OBJECT_AS_ARRAY", PHP_JSON_OBJECT_AS_ARRAY, CONST_CS | CONST_PERSISTENT); + REGISTER_INT_CONSTANT("JSON_BIGINT_AS_STRING", PHP_JSON_BIGINT_AS_STRING, CONST_CS | CONST_PERSISTENT); return SUCCESS; } @@ -169,35 +169,27 @@ 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) /* {{{ */ +static int json_determine_array_type(zval *val TSRMLS_DC) /* {{{ */ { int i; - HashTable *myht = HASH_OF(*val); + 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_string *key; + php_uint_t index, idx; - 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; + ZEND_HASH_FOREACH_KEY(myht, index, key) { + if (key) { + return PHP_JSON_OUTPUT_OBJECT; } else { if (index != idx) { - return 1; + return PHP_JSON_OUTPUT_OBJECT; } } idx++; - } + } ZEND_HASH_FOREACH_END(); } return PHP_JSON_OUTPUT_ARRAY; @@ -228,20 +220,20 @@ static inline void json_pretty_print_indent(smart_str *buf, int options TSRMLS_D /* }}} */ -static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */ +static void json_encode_array(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ { int i, r, need_comma = 0; HashTable *myht; - if (Z_TYPE_PP(val) == IS_ARRAY) { - myht = HASH_OF(*val); + if (Z_TYPE_P(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); + myht = Z_OBJPROP_P(val); r = PHP_JSON_OUTPUT_OBJECT; } - if (myht && myht->nApplyCount > 1) { + if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { JSON_G(error_code) = PHP_JSON_ERROR_RECURSION; smart_str_appendl(buf, "null", 4); return; @@ -257,28 +249,39 @@ static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) i = myht ? zend_hash_num_elements(myht) : 0; - if (i > 0) - { - char *key; - zval **data; - ulong index; - uint key_len; - HashPosition pos; + if (i > 0) { + zend_string *key; + zval *data; + php_uint_t index; 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; + 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 (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; } - if (r == PHP_JSON_OUTPUT_ARRAY) { + 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 (key) { + if (key->val[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 { @@ -287,58 +290,38 @@ static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) 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_escape_string(buf, key->val, key->len, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC); + smart_str_appendc(buf, ':'); - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - json_pretty_print_indent(buf, options TSRMLS_CC); + json_pretty_print_char(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); + php_json_encode(buf, data, options TSRMLS_CC); + } else { + if (need_comma) { + smart_str_appendc(buf, ','); } else { - if (need_comma) { - smart_str_appendc(buf, ','); - } else { - need_comma = 1; - } + need_comma = 1; + } - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - json_pretty_print_indent(buf, options TSRMLS_CC); + 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, ':'); + smart_str_appendc(buf, '"'); + smart_str_append_int(buf, (php_int_t) index); + smart_str_appendc(buf, '"'); + smart_str_appendc(buf, ':'); - json_pretty_print_char(buf, options, ' ' TSRMLS_CC); + json_pretty_print_char(buf, options, ' ' TSRMLS_CC); - php_json_encode(buf, *data, options TSRMLS_CC); - } + php_json_encode(buf, data, options TSRMLS_CC); } + } - if (tmp_ht) { - tmp_ht->nApplyCount--; - } + 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)) { @@ -397,7 +380,6 @@ static int json_utf8_to_utf16(unsigned short *utf16, char utf8[], int len) /* {{ } /* }}} */ - static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */ { int pos = 0, ulen = 0; @@ -413,11 +395,11 @@ static void json_escape_string(smart_str *buf, char *s, int len, int options TSR if (options & PHP_JSON_NUMERIC_CHECK) { double d; int type; - long p; + php_int_t p; if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { - if (type == IS_LONG) { - smart_str_append_long(buf, p); + if (type == IS_INT) { + smart_str_append_int(buf, p); } else if (type == IS_DOUBLE) { if (!zend_isinf(d) && !zend_isnan(d)) { char *tmp; @@ -555,11 +537,10 @@ static void json_escape_string(smart_str *buf, char *s, int len, int options TSR } /* }}} */ - 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; + zval retval, fname; HashTable* myht; if (Z_TYPE_P(val) == IS_ARRAY) { @@ -568,58 +549,61 @@ static void json_encode_serializable_object(smart_str *buf, zval *val, int optio myht = Z_OBJPROP_P(val); } - if (myht && myht->nApplyCount > 1) { + 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", 0); + ZVAL_STRING(&fname, "jsonSerialize"); - if (FAILURE == call_user_function_ex(EG(function_table), &val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || !retval) { + if (FAILURE == call_user_function_ex(EG(function_table), val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || Z_TYPE(retval) == IS_UNDEF) { zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name); smart_str_appendl(buf, "null", sizeof("null") - 1); + zval_ptr_dtor(&fname); return; } 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_P(retval) == IS_OBJECT) && - (Z_OBJ_HANDLE_P(retval) == Z_OBJ_HANDLE_P(val))) { + if ((Z_TYPE(retval) == IS_OBJECT) && + (Z_OBJ_HANDLE(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); + php_json_encode(buf, &retval, options TSRMLS_CC); } zval_ptr_dtor(&retval); + zval_ptr_dtor(&fname); } /* }}} */ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ { +again: 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); - } + 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)); + case IS_INT: + smart_str_append_int(buf, Z_IVAL_P(val)); break; case IS_DOUBLE: @@ -640,7 +624,7 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_ break; case IS_STRING: - json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC); + json_escape_string(buf, Z_STRVAL_P(val), Z_STRSIZE_P(val), options TSRMLS_CC); break; case IS_OBJECT: @@ -650,9 +634,13 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_ } /* fallthrough -- Non-serializable object */ case IS_ARRAY: - json_encode_array(buf, &val, options TSRMLS_CC); + json_encode_array(buf, val, options TSRMLS_CC); 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); @@ -663,10 +651,9 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_ } /* }}} */ -PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */ +PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, php_int_t depth TSRMLS_DC) /* {{{ */ { int utf16_len; - zval *z; unsigned short *utf16; JSON_parser jp; @@ -687,19 +674,16 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, 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 - { + if (!parse_JSON_ex(jp, return_value, utf16, utf16_len, options TSRMLS_CC)) { double d; int type, overflow_info; - long p; + php_int_t p; char *trim = str; int trim_len = str_len; + zval_dtor(return_value); + /* 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')) { @@ -726,8 +710,8 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, } if ((type = is_numeric_string_ex(trim, trim_len, &p, &d, 0, &overflow_info)) != 0) { - if (type == IS_LONG) { - RETVAL_LONG(p); + if (type == IS_INT) { + RETVAL_INT(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 @@ -750,7 +734,7 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, if (is_float) { RETVAL_DOUBLE(d); } else { - RETVAL_STRINGL(trim, trim_len, 1); + RETVAL_STRINGL(trim, trim_len); } } else { RETVAL_DOUBLE(d); @@ -761,27 +745,23 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, 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; + php_int_t options = 0; + php_int_t depth = 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() TSRMLS_CC, "z|ii", ¶meter, &options, &depth) == FAILURE) { return; } @@ -792,12 +772,12 @@ static PHP_FUNCTION(json_encode) php_json_encode(&buf, parameter, options TSRMLS_CC); 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_STR(return_value, buf.s); } - - smart_str_free(&buf); } /* }}} */ @@ -808,10 +788,10 @@ static PHP_FUNCTION(json_decode) char *str; int str_len; zend_bool assoc = 0; /* return JS objects as PHP objects by default */ - long depth = JSON_PARSER_DEFAULT_DEPTH; - long options = 0; + php_int_t depth = JSON_PARSER_DEFAULT_DEPTH; + php_int_t 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() TSRMLS_CC, "s|bii", &str, &str_len, &assoc, &depth, &options) == FAILURE) { return; } @@ -840,7 +820,7 @@ static PHP_FUNCTION(json_last_error) return; } - RETURN_LONG(JSON_G(error_code)); + RETURN_INT(JSON_G(error_code)); } /* }}} */ @@ -854,25 +834,25 @@ 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"); default: - RETURN_STRING("Unknown error", 1); + RETURN_STRING("Unknown error"); } } diff --git a/ext/json/php_json.h b/ext/json/php_json.h index e00de6a27b..b42aecba7d 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -50,7 +50,7 @@ ZEND_END_MODULE_GLOBALS(json) #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); +PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, php_int_t depth TSRMLS_DC); extern PHP_JSON_API zend_class_entry *php_json_serializable_ce; @@ -74,7 +74,7 @@ extern PHP_JSON_API zend_class_entry *php_json_serializable_ce; #define PHP_JSON_OBJECT_AS_ARRAY (1<<0) #define PHP_JSON_BIGINT_AS_STRING (1<<1) -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, php_int_t depth TSRMLS_DC) { php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth TSRMLS_CC); } 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" |