summaryrefslogtreecommitdiff
path: root/ext/json/json.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/json/json.c')
-rw-r--r--ext/json/json.c169
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", &parameter, &options, &depth) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &parameter, &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));
}
/* }}} */