diff options
author | Stanley Sufficool <ssufficool@php.net> | 2014-10-20 21:33:32 -0700 |
---|---|---|
committer | Stanley Sufficool <ssufficool@php.net> | 2014-10-20 21:33:32 -0700 |
commit | 8defcb855ab01d9c8ab4759cb793d80149b55a8c (patch) | |
tree | ed51eb30a2cbc92b102557498fb3e4113da1bb07 /ext/json | |
parent | 9c7dbb0487f5991fde03873ea8f5e66d6688415f (diff) | |
parent | baddb1c73a170ef1d2c31bd54cddbc6e1ab596b9 (diff) | |
download | php-git-8defcb855ab01d9c8ab4759cb793d80149b55a8c.tar.gz |
Merge branch 'master' of https://git.php.net/push/php-src
* 'master' of https://git.php.net/push/php-src: (6215 commits)
Extra comma
Moved proxy object support in ASSIGN_ADD (and family) from VM to slow paths of corresponding operators
Simplification
zend_get_property_info_quick() cleanup and optimization
initialize lineno before calling compile file file in phar
Use ADDREF instead of DUP, it must be enough.
Removed old irrelevant comment
fixed compilation error
Fix bug #68262: Broken reference across cloned objects
export functions needed for phpdbg
Fixed compilation
Optimized property access handlers. Removed EG(std_property_info).
Fixed bug #68199 (PDO::pgsqlGetNotify doesn't support NOTIFY payloads)
Don't make difference between undefined and unaccessible properies when call __get() and family
Don't make useless CSE
array_pop/array_shift optimization
check for zlib headers as well as lib for mysqlnd
a realpath cache key can be int or float, catching this
News entry for new curl constants
News entry for new curl constants
...
Diffstat (limited to 'ext/json')
-rw-r--r-- | ext/json/JSON_parser.c | 174 | ||||
-rw-r--r-- | ext/json/JSON_parser.h | 6 | ||||
-rw-r--r-- | ext/json/json.c | 365 | ||||
-rw-r--r-- | ext/json/json.dsp | 135 | ||||
-rw-r--r-- | ext/json/php_json.h | 12 | ||||
-rw-r--r-- | ext/json/tests/bug64874_part1.phpt | 117 | ||||
-rw-r--r-- | ext/json/tests/bug64874_part2.phpt | 69 | ||||
-rw-r--r-- | ext/json/tests/bug66021.phpt | 20 | ||||
-rw-r--r-- | ext/json/tests/unsupported_type_error.phpt | 2 | ||||
-rw-r--r-- | ext/json/utf8_decode.h | 2 |
10 files changed, 489 insertions, 413 deletions
diff --git a/ext/json/JSON_parser.c b/ext/json/JSON_parser.c index dd832a7cbd..d78ec35a2e 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) { 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_LONG - 1) { + if (buf->s->len == MAX_LENGTH_OF_LONG - 1) { + int cmp = strcmp(buf->s->val + (buf->s->val[0] == '-'), long_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_LONG(z, ZEND_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; + zend_ulong 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; @@ -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..da47f4078f 100644 --- a/ext/json/JSON_parser.h +++ b/ext/json/JSON_parser.h @@ -4,8 +4,8 @@ #define JSON_PARSER_H #include "php.h" -#include "ext/standard/php_smart_str.h" #include "php_json.h" +#include "zend_smart_str.h" #define JSON_PARSER_DEFAULT_DEPTH 512 @@ -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 782375e371..8f4f281ef1 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -1,8 +1,8 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 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 | @@ -26,7 +26,7 @@ #include "php_ini.h" #include "ext/standard/info.h" #include "ext/standard/html.h" -#include "ext/standard/php_smart_str.h" +#include "zend_smart_str.h" #include "JSON_parser.h" #include "php_json.h" #include <zend_exceptions.h> @@ -39,7 +39,7 @@ static PHP_FUNCTION(json_last_error_msg); static const char digits[] = "0123456789abcdef"; -zend_class_entry *php_json_serializable_ce; +PHP_JSON_API zend_class_entry *php_json_serializable_ce; ZEND_DECLARE_MODULE_GLOBALS(json) @@ -167,37 +167,29 @@ static PHP_MINFO_FUNCTION(json) } /* }}} */ -static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC); +static void json_escape_string(smart_str *buf, char *s, size_t 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; + zend_ulong 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; + 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; @@ -253,102 +245,95 @@ static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) smart_str_appendc(buf, '{'); } - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); ++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; + if (i > 0) { + zend_string *key; + zval *data; + zend_ulong index; HashTable *tmp_ht; - int need_comma = 0; - 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, ','); - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); } 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, ','); - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - } else { - need_comma = 1; - } - json_pretty_print_indent(buf, options TSRMLS_CC); + json_escape_string(buf, key->val, key->len, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC); + smart_str_appendc(buf, ':'); - 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); - 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, ','); - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - } else { - need_comma = 1; - } + need_comma = 1; + } - 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_long(buf, (zend_long) 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)) { JSON_G(error_code) = PHP_JSON_ERROR_DEPTH; } --JSON_G(encoder_depth); - json_pretty_print_char(buf, options, '\n' TSRMLS_CC); - json_pretty_print_indent(buf, options TSRMLS_CC); + + /* 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, ']'); @@ -380,7 +365,7 @@ static int json_utf8_to_utf16(unsigned short *utf16, char utf8[], int len) /* {{ } } } else { - /* Only check if utf8 string is valid, and compute utf16 lenght */ + /* 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) { @@ -395,13 +380,11 @@ 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) /* {{{ */ +static void json_escape_string(smart_str *buf, char *s, size_t len, int options TSRMLS_DC) /* {{{ */ { - int pos = 0, ulen = 0; - unsigned short us; - unsigned short *utf16; - size_t newlen; + int status; + unsigned int us, next_us = 0; + size_t pos, checkpoint; if (len == 0) { smart_str_appendl(buf, "\"\"", 2); @@ -411,7 +394,7 @@ 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; + zend_long p; if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { if (type == IS_LONG) { @@ -432,34 +415,51 @@ static void json_escape_string(smart_str *buf, char *s, int len, int options TSR } - 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) { + if (options & PHP_JSON_UNESCAPED_UNICODE) { + /* validate UTF-8 string first */ + if (json_utf8_to_utf16(NULL, s, len) < 0) { JSON_G(error_code) = PHP_JSON_ERROR_UTF8; smart_str_appendl(buf, "null", 4); - } else { - smart_str_appendl(buf, "\"\"", 2); + return; } - return; - } - if (!(options & PHP_JSON_UNESCAPED_UNICODE)) { - len = ulen; } + pos = 0; + checkpoint = buf->s ? buf->s->len : 0; + /* 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++]; + do { + if (UNEXPECTED(next_us)) { + us = next_us; + next_us = 0; + } else { + us = (unsigned char)s[pos]; + if (!(options & PHP_JSON_UNESCAPED_UNICODE) && us >= 0x80) { + /* UTF-8 character */ + us = php_next_utf8_char((const unsigned char *)s, len, &pos, &status); + if (status != SUCCESS) { + if (buf->s) { + buf->s->len = 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) { + us -= 0x10000; + next_us = (unsigned short)((us & 0x3ff) | 0xdc00); + us = (unsigned short)((us >> 10) | 0xd800); + } + } else { + pos++; + } + } - switch (us) - { + switch (us) { case '"': if (options & PHP_JSON_HEX_QUOT) { smart_str_appendl(buf, "\\u0022", 6); @@ -544,20 +544,16 @@ static void json_escape_string(smart_str *buf, char *s, int len, int options TSR } break; } - } - + } while (pos < len || next_us); + 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; + zval retval, fname; HashTable* myht; if (Z_TYPE_P(val) == IS_ARRAY) { @@ -566,54 +562,57 @@ 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) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name); + 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->val); 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: @@ -648,9 +647,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); @@ -661,10 +664,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, size_t str_len, zend_long options, zend_long depth TSRMLS_DC) /* {{{ */ { - int utf16_len; - zval *z; + size_t utf16_len; unsigned short *utf16; JSON_parser jp; @@ -685,31 +687,42 @@ 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; + zend_long 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')) { + 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 (str_len == 4) { - if (!strcasecmp(str, "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 (!strcasecmp(str, "true")) { + } else if (!strncmp(trim, "true", trim_len)) { RETVAL_BOOL(1); } - } else if (str_len == 5 && !strcasecmp(str, "false")) { + } else if (trim_len == 5 && !strncmp(trim, "false", trim_len)) { RETVAL_BOOL(0); } - if ((type = is_numeric_string_ex(str, str_len, &p, &d, 0, &overflow_info)) != 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) { @@ -722,10 +735,10 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int i; zend_bool is_float = 0; - for (i = (str[0] == '-' ? 1 : 0); i < str_len; i++) { + 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 (str[i] < '0' || str[i] > '9') { + if (trim[i] < '0' || trim[i] > '9') { is_float = 1; break; } @@ -734,7 +747,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(str, str_len, 1); + RETVAL_STRINGL(trim, trim_len); } } else { RETVAL_DOUBLE(d); @@ -745,25 +758,21 @@ 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; + zend_long options = 0; + zend_long depth = JSON_PARSER_DEFAULT_DEPTH; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", ¶meter, &options, &depth) == FAILURE) { return; @@ -776,12 +785,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_NEW_STR(return_value, buf.s); } - - smart_str_free(&buf); } /* }}} */ @@ -790,10 +799,10 @@ 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 = 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) { return; @@ -838,25 +847,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/json.dsp b/ext/json/json.dsp deleted file mode 100644 index e5bb3767bf..0000000000 --- a/ext/json/json.dsp +++ /dev/null @@ -1,135 +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
-# Begin Source File
-
-SOURCE=.\utf8_decode.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\utf8_decode.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\utf8_to_utf16.c
-# End Source File
-# Begin Source File
-
-SOURCE=.\utf8_to_utf16.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/php_json.h b/ext/json/php_json.h index ec707ce346..5b2dc127dd 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -1,8 +1,8 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 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 | @@ -22,7 +22,7 @@ #define PHP_JSON_H #define PHP_JSON_VERSION "1.2.1" -#include "ext/standard/php_smart_str.h" +#include "zend_smart_str_public.h" extern zend_module_entry json_module_entry; #define phpext_json_ptr &json_module_entry @@ -50,8 +50,8 @@ 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); -extern zend_class_entry *php_json_serializable_ce; +PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, size_t str_len, zend_long options, zend_long depth TSRMLS_DC); +extern PHP_JSON_API zend_class_entry *php_json_serializable_ce; /* json_encode() options */ @@ -74,7 +74,7 @@ extern 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, zend_long 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/bug64874_part1.phpt b/ext/json/tests/bug64874_part1.phpt new file mode 100644 index 0000000000..6b79b8dc04 --- /dev/null +++ b/ext/json/tests/bug64874_part1.phpt @@ -0,0 +1,117 @@ +--TEST-- +Whitespace part of bug #64874 ("json_decode handles whitespace and case-sensitivity incorrectly") +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php +function decode($json) { + var_dump(json_decode($json)); + var_dump(json_last_error() !== 0); + echo "\n"; +} + +// Leading whitespace should be ignored +decode(" true"); +decode("\ttrue"); +decode("\ntrue"); +decode("\rtrue"); + +// So should trailing whitespace +decode("true "); +decode("true\t"); +decode("true\n"); +decode("true\r"); + +// And so should the combination of both +decode(" true "); +decode(" true\t"); +decode(" true\n"); +decode(" true\r"); +decode("\ttrue "); +decode("\ttrue\t"); +decode("\ttrue\n"); +decode("\ttrue\r"); +decode("\ntrue "); +decode("\ntrue\t"); +decode("\ntrue\n"); +decode("\ntrue\r"); +decode("\rtrue "); +decode("\rtrue\t"); +decode("\rtrue\n"); +decode("\rtrue\r"); + +echo "Done\n"; +--EXPECT-- +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +bool(true) +bool(false) + +Done diff --git a/ext/json/tests/bug64874_part2.phpt b/ext/json/tests/bug64874_part2.phpt new file mode 100644 index 0000000000..338fc1141a --- /dev/null +++ b/ext/json/tests/bug64874_part2.phpt @@ -0,0 +1,69 @@ +--TEST-- +Case-sensitivity part of bug #64874 ("json_decode handles whitespace and case-sensitivity incorrectly") +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php +function decode($json) { + var_dump(json_decode($json)); + echo ((json_last_error() !== 0) ? 'ERROR' : 'SUCCESS') . PHP_EOL; +} + +// Only lowercase should work +decode('true'); +decode('True'); +decode('[true]'); +decode('[True]'); +echo PHP_EOL; + +decode('false'); +decode('False'); +decode('[false]'); +decode('[False]'); +echo PHP_EOL; + +decode('null'); +decode('Null'); +decode('[null]'); +decode('[Null]'); +echo PHP_EOL; + +echo "Done\n"; +--EXPECT-- +bool(true) +SUCCESS +NULL +ERROR +array(1) { + [0]=> + bool(true) +} +SUCCESS +NULL +ERROR + +bool(false) +SUCCESS +NULL +ERROR +array(1) { + [0]=> + bool(false) +} +SUCCESS +NULL +ERROR + +NULL +SUCCESS +NULL +ERROR +array(1) { + [0]=> + NULL +} +SUCCESS +NULL +ERROR + +Done diff --git a/ext/json/tests/bug66021.phpt b/ext/json/tests/bug66021.phpt new file mode 100644 index 0000000000..cf52e0c6df --- /dev/null +++ b/ext/json/tests/bug66021.phpt @@ -0,0 +1,20 @@ +--TEST-- +Bug #66021 (Blank line inside empty array/object when JSON_PRETTY_PRINT is set) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php + +class Foo { + private $bar = 'baz'; +} + +echo json_encode([[], (object)[], new Foo], JSON_PRETTY_PRINT), "\n"; + +?> +--EXPECT-- +[ + [], + {}, + {} +] 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" diff --git a/ext/json/utf8_decode.h b/ext/json/utf8_decode.h index cc0fc79f6c..0908edd2d4 100644 --- a/ext/json/utf8_decode.h +++ b/ext/json/utf8_decode.h @@ -5,8 +5,8 @@ typedef struct json_utf8_decode { - int the_index; char *the_input; + int the_index; int the_length; int the_char; int the_byte; |