diff options
Diffstat (limited to 'ext/json/json_encoder.c')
-rw-r--r-- | ext/json/json_encoder.c | 163 |
1 files changed, 77 insertions, 86 deletions
diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c index 952e546c6c..c0fcbe3282 100644 --- a/ext/json/json_encoder.c +++ b/ext/json/json_encoder.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 7 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2018 The PHP Group | + | Copyright (c) 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 | @@ -130,19 +130,21 @@ static inline void php_json_encode_double(smart_str *buf, double d, int options) static int php_json_encode_array(smart_str *buf, zval *val, int options, php_json_encoder *encoder) /* {{{ */ { int i, r, need_comma = 0; - HashTable *myht; + HashTable *myht, *prop_ht; if (Z_TYPE_P(val) == IS_ARRAY) { myht = Z_ARRVAL_P(val); + prop_ht = NULL; r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(val); } else { - myht = Z_OBJPROP_P(val); + prop_ht = myht = zend_get_properties_for(val, ZEND_PROP_PURPOSE_JSON); r = PHP_JSON_OUTPUT_OBJECT; } if (myht && GC_IS_RECURSIVE(myht)) { encoder->error_code = PHP_JSON_ERROR_RECURSION; smart_str_appendl(buf, "null", 4); + zend_release_properties(prop_ht); return FAILURE; } @@ -218,6 +220,7 @@ static int php_json_encode_array(smart_str *buf, zval *val, int options, php_jso if (php_json_encode_zval(buf, data, options, encoder) == FAILURE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { PHP_JSON_HASH_UNPROTECT_RECURSION(myht); + zend_release_properties(prop_ht); return FAILURE; } } ZEND_HASH_FOREACH_END(); @@ -228,6 +231,7 @@ static int php_json_encode_array(smart_str *buf, zval *val, int options, php_jso if (encoder->depth > encoder->max_depth) { encoder->error_code = PHP_JSON_ERROR_DEPTH; if (!(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) { + zend_release_properties(prop_ht); return FAILURE; } } @@ -245,6 +249,7 @@ static int php_json_encode_array(smart_str *buf, zval *val, int options, php_jso smart_str_appendc(buf, '}'); } + zend_release_properties(prop_ht); return SUCCESS; } /* }}} */ @@ -279,97 +284,94 @@ static int php_json_escape_string( } } - pos = 0; checkpoint = buf->s ? ZSTR_LEN(buf->s) : 0; /* pre-allocate for string length plus 2 quotes */ smart_str_alloc(buf, len+2, 0); smart_str_appendc(buf, '"'); + pos = 0; + do { + static const uint32_t charmap[8] = { + 0xffffffff, 0x500080c4, 0x10000000, 0x00000000, + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}; + us = (unsigned char)s[pos]; - if (UNEXPECTED(us >= 0x80)) { + if (EXPECTED(!ZEND_BIT_TEST(charmap, us))) { + pos++; + len--; + if (len == 0) { + smart_str_appendl(buf, s, pos); + break; + } + } else { if (pos) { smart_str_appendl(buf, s, pos); s += pos; pos = 0; } - us = php_next_utf8_char((unsigned char *)s, len, &pos, &status); - len -= pos; - - /* check whether UTF8 character is correct */ - if (UNEXPECTED(status != SUCCESS)) { - s += pos; - pos = 0; - if (options & PHP_JSON_INVALID_UTF8_IGNORE) { - /* ignore invalid UTF8 character */ - continue; - } else if (options & PHP_JSON_INVALID_UTF8_SUBSTITUTE) { - /* Use Unicode character 'REPLACEMENT CHARACTER' (U+FFFD) */ - if (options & PHP_JSON_UNESCAPED_UNICODE) { - smart_str_appendl(buf, "\xef\xbf\xbd", 3); + us = (unsigned char)s[0]; + if (UNEXPECTED(us >= 0x80)) { + + us = php_next_utf8_char((unsigned char *)s, len, &pos, &status); + + /* check whether UTF8 character is correct */ + if (UNEXPECTED(status != SUCCESS)) { + if (options & PHP_JSON_INVALID_UTF8_IGNORE) { + /* ignore invalid UTF8 character */ + } else if (options & PHP_JSON_INVALID_UTF8_SUBSTITUTE) { + /* Use Unicode character 'REPLACEMENT CHARACTER' (U+FFFD) */ + if (options & PHP_JSON_UNESCAPED_UNICODE) { + smart_str_appendl(buf, "\xef\xbf\xbd", 3); + } else { + smart_str_appendl(buf, "\\ufffd", 6); + } } else { - smart_str_appendl(buf, "\\ufffd", 6); + ZSTR_LEN(buf->s) = checkpoint; + encoder->error_code = PHP_JSON_ERROR_UTF8; + if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { + smart_str_appendl(buf, "null", 4); + } + return FAILURE; } - continue; + + /* Escape U+2028/U+2029 line terminators, UNLESS both + JSON_UNESCAPED_UNICODE and + JSON_UNESCAPED_LINE_TERMINATORS were provided */ + } else if ((options & PHP_JSON_UNESCAPED_UNICODE) + && ((options & PHP_JSON_UNESCAPED_LINE_TERMINATORS) + || us < 0x2028 || us > 0x2029)) { + smart_str_appendl(buf, s, pos); } else { - ZSTR_LEN(buf->s) = checkpoint; - encoder->error_code = PHP_JSON_ERROR_UTF8; - if (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) { - smart_str_appendl(buf, "null", 4); + /* From http://en.wikipedia.org/wiki/UTF16 */ + if (us >= 0x10000) { + unsigned int next_us; + + us -= 0x10000; + next_us = (unsigned short)((us & 0x3ff) | 0xdc00); + us = (unsigned short)((us >> 10) | 0xd800); + dst = smart_str_extend(buf, 6); + dst[0] = '\\'; + dst[1] = 'u'; + dst[2] = digits[(us >> 12) & 0xf]; + dst[3] = digits[(us >> 8) & 0xf]; + dst[4] = digits[(us >> 4) & 0xf]; + dst[5] = digits[us & 0xf]; + us = next_us; } - return FAILURE; + dst = smart_str_extend(buf, 6); + dst[0] = '\\'; + dst[1] = 'u'; + dst[2] = digits[(us >> 12) & 0xf]; + dst[3] = digits[(us >> 8) & 0xf]; + dst[4] = digits[(us >> 4) & 0xf]; + dst[5] = digits[us & 0xf]; } - - /* Escape U+2028/U+2029 line terminators, UNLESS both - JSON_UNESCAPED_UNICODE and - JSON_UNESCAPED_LINE_TERMINATORS were provided */ - } else if ((options & PHP_JSON_UNESCAPED_UNICODE) - && ((options & PHP_JSON_UNESCAPED_LINE_TERMINATORS) - || us < 0x2028 || us > 0x2029)) { - smart_str_appendl(buf, s, pos); s += pos; + len -= pos; pos = 0; - continue; - } - /* From http://en.wikipedia.org/wiki/UTF16 */ - if (us >= 0x10000) { - unsigned int next_us; - - us -= 0x10000; - next_us = (unsigned short)((us & 0x3ff) | 0xdc00); - us = (unsigned short)((us >> 10) | 0xd800); - dst = smart_str_extend(buf, 6); - dst[0] = '\\'; - dst[1] = 'u'; - dst[2] = digits[(us >> 12) & 0xf]; - dst[3] = digits[(us >> 8) & 0xf]; - dst[4] = digits[(us >> 4) & 0xf]; - dst[5] = digits[us & 0xf]; - us = next_us; - } - dst = smart_str_extend(buf, 6); - dst[0] = '\\'; - dst[1] = 'u'; - dst[2] = digits[(us >> 12) & 0xf]; - dst[3] = digits[(us >> 8) & 0xf]; - dst[4] = digits[(us >> 4) & 0xf]; - dst[5] = digits[us & 0xf]; - s += pos; - pos = 0; - } else { - static const uint32_t charmap[4] = { - 0xffffffff, 0x500080c4, 0x10000000, 0x00000000}; - - len--; - if (EXPECTED(!ZEND_BIT_TEST(charmap, us))) { - pos++; } else { - if (pos) { - smart_str_appendl(buf, s, pos); - s += pos; - pos = 0; - } s++; switch (us) { case '"': @@ -455,13 +457,11 @@ static int php_json_escape_string( dst[5] = digits[us & 0xf]; break; } + len--; } } } while (len); - if (EXPECTED(pos)) { - smart_str_appendl(buf, s, pos); - } smart_str_appendc(buf, '"'); return SUCCESS; @@ -487,7 +487,7 @@ static int php_json_encode_serializable_object(smart_str *buf, zval *val, int op ZVAL_STRING(&fname, "jsonSerialize"); - if (FAILURE == call_user_function(EG(function_table), val, &fname, &retval, 0, NULL) || Z_TYPE(retval) == IS_UNDEF) { + if (FAILURE == call_user_function(NULL, val, &fname, &retval, 0, NULL) || Z_TYPE(retval) == IS_UNDEF) { if (!EG(exception)) { zend_throw_exception_ex(NULL, 0, "Failed calling %s::jsonSerialize()", ZSTR_VAL(ce->name)); } @@ -593,12 +593,3 @@ again: return SUCCESS; } /* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ |