diff options
Diffstat (limited to 'ext/json/json.c')
-rw-r--r-- | ext/json/json.c | 169 |
1 files changed, 91 insertions, 78 deletions
diff --git a/ext/json/json.c b/ext/json/json.c index 60893fe1ea..8f4f281ef1 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ @@ -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> @@ -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_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); + 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); return SUCCESS; } @@ -167,7 +167,7 @@ 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) /* {{{ */ { @@ -177,7 +177,7 @@ static int json_determine_array_type(zval *val TSRMLS_DC) /* {{{ */ i = myht ? zend_hash_num_elements(myht) : 0; if (i > 0) { zend_string *key; - php_uint_t index, idx; + zend_ulong index, idx; idx = 0; ZEND_HASH_FOREACH_KEY(myht, index, key) { @@ -252,7 +252,7 @@ static void json_encode_array(smart_str *buf, zval *val, int options TSRMLS_DC) if (i > 0) { zend_string *key; zval *data; - php_uint_t index; + zend_ulong index; HashTable *tmp_ht; ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) { @@ -308,7 +308,7 @@ static void json_encode_array(smart_str *buf, zval *val, int options TSRMLS_DC) json_pretty_print_indent(buf, options TSRMLS_CC); smart_str_appendc(buf, '"'); - smart_str_append_int(buf, (php_int_t) index); + smart_str_append_long(buf, (zend_long) index); smart_str_appendc(buf, '"'); smart_str_appendc(buf, ':'); @@ -380,12 +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); @@ -395,11 +394,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; - php_int_t p; + zend_long p; if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { - if (type == IS_INT) { - smart_str_append_int(buf, p); + if (type == IS_LONG) { + smart_str_append_long(buf, p); } else if (type == IS_DOUBLE) { if (!zend_isinf(d) && !zend_isnan(d)) { char *tmp; @@ -416,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); @@ -528,12 +544,9 @@ 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); - } } /* }}} */ @@ -558,7 +571,7 @@ static void json_encode_serializable_object(smart_str *buf, zval *val, int optio ZVAL_STRING(&fname, "jsonSerialize"); 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); + 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; @@ -602,8 +615,8 @@ again: smart_str_appendl(buf, "false", 5); break; - case IS_INT: - smart_str_append_int(buf, Z_IVAL_P(val)); + case IS_LONG: + smart_str_append_long(buf, Z_LVAL_P(val)); break; case IS_DOUBLE: @@ -624,7 +637,7 @@ again: break; case IS_STRING: - json_escape_string(buf, Z_STRVAL_P(val), Z_STRSIZE_P(val), options TSRMLS_CC); + json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC); break; case IS_OBJECT: @@ -651,9 +664,9 @@ again: } /* }}} */ -PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, php_int_t 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; + size_t utf16_len; unsigned short *utf16; JSON_parser jp; @@ -678,7 +691,7 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, if (!parse_JSON_ex(jp, return_value, utf16, utf16_len, options TSRMLS_CC)) { double d; int type, overflow_info; - php_int_t p; + zend_long p; char *trim = str; int trim_len = str_len; @@ -710,8 +723,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_INT) { - RETVAL_INT(p); + 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 @@ -758,10 +771,10 @@ static PHP_FUNCTION(json_encode) { zval *parameter; smart_str buf = {0}; - php_int_t options = 0; - php_int_t 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|ii", ¶meter, &options, &depth) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", ¶meter, &options, &depth) == FAILURE) { return; } @@ -776,7 +789,7 @@ static PHP_FUNCTION(json_encode) ZVAL_FALSE(return_value); } else { smart_str_0(&buf); /* copy? */ - ZVAL_STR(return_value, buf.s); + ZVAL_NEW_STR(return_value, buf.s); } } /* }}} */ @@ -786,12 +799,12 @@ 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 */ - php_int_t depth = JSON_PARSER_DEFAULT_DEPTH; - php_int_t options = 0; + zend_long depth = JSON_PARSER_DEFAULT_DEPTH; + zend_long options = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bii", &str, &str_len, &assoc, &depth, &options) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) { return; } @@ -820,7 +833,7 @@ static PHP_FUNCTION(json_last_error) return; } - RETURN_INT(JSON_G(error_code)); + RETURN_LONG(JSON_G(error_code)); } /* }}} */ |