diff options
Diffstat (limited to 'ext/json')
| -rw-r--r-- | ext/json/config.m4 | 2 | ||||
| -rw-r--r-- | ext/json/config.w32 | 2 | ||||
| -rw-r--r-- | ext/json/json.c | 43 | ||||
| -rw-r--r-- | ext/json/json.dsp | 16 | ||||
| -rw-r--r-- | ext/json/package.xml | 4 | ||||
| -rw-r--r-- | ext/json/php_json.h | 1 | ||||
| -rw-r--r-- | ext/json/tests/bug50224.phpt | 60 | ||||
| -rw-r--r-- | ext/json/tests/bug64874_part2.phpt | 69 | ||||
| -rw-r--r-- | ext/json/utf8_decode.c | 179 | ||||
| -rw-r--r-- | ext/json/utf8_decode.h | 18 |
10 files changed, 164 insertions, 230 deletions
diff --git a/ext/json/config.m4 b/ext/json/config.m4 index 26c43a0e3f..51cc5087c8 100644 --- a/ext/json/config.m4 +++ b/ext/json/config.m4 @@ -9,7 +9,7 @@ if test "$PHP_JSON" != "no"; then AC_DEFINE([HAVE_JSON],1 ,[whether to enable JavaScript Object Serialization support]) AC_HEADER_STDC - PHP_NEW_EXTENSION(json, json.c utf8_decode.c JSON_parser.c, $ext_shared) + PHP_NEW_EXTENSION(json, json.c JSON_parser.c, $ext_shared) PHP_INSTALL_HEADERS([ext/json], [php_json.h]) PHP_SUBST(JSON_SHARED_LIBADD) fi diff --git a/ext/json/config.w32 b/ext/json/config.w32 index cedbf42829..6e318c5d0d 100644 --- a/ext/json/config.w32 +++ b/ext/json/config.w32 @@ -5,7 +5,7 @@ ARG_ENABLE("json", "JavaScript Object Serialization support", "yes"); if (PHP_JSON != "no") { EXTENSION('json', 'json.c', PHP_JSON_SHARED, ""); - ADD_SOURCES(configure_module_dirname, "JSON_parser.c utf8_decode.c", "json"); + ADD_SOURCES(configure_module_dirname, "JSON_parser.c", "json"); PHP_INSTALL_HEADERS("ext/json/", "php_json.h"); } diff --git a/ext/json/json.c b/ext/json/json.c index 16af796145..f016349668 100644 --- a/ext/json/json.c +++ b/ext/json/json.c @@ -31,6 +31,14 @@ #include "php_json.h" #include <zend_exceptions.h> +#include <float.h> +#if defined(DBL_MANT_DIG) && defined(DBL_MIN_EXP) +#define NUM_BUF_SIZE (3 + DBL_MANT_DIG - DBL_MIN_EXP) +#else +#define NUM_BUF_SIZE 1080 +#endif + + static PHP_MINFO_FUNCTION(json); static PHP_FUNCTION(json_encode); static PHP_FUNCTION(json_decode); @@ -103,6 +111,7 @@ static PHP_MINIT_FUNCTION(json) 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_PRESERVE_ZERO_FRACTION", PHP_JSON_PRESERVE_ZERO_FRACTION, 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); @@ -420,10 +429,17 @@ static void json_escape_string(smart_str *buf, char *s, int len, int options TSR smart_str_append_long(buf, p); return; } else if (type == IS_DOUBLE && !zend_isinf(d) && !zend_isnan(d)) { - char *tmp; - int l = spprintf(&tmp, 0, "%.*k", (int) EG(precision), d); - smart_str_appendl(buf, tmp, l); - efree(tmp); + char num[NUM_BUF_SIZE]; + int l; + + php_gcvt(d, EG(precision), '.', 'e', (char *)num); + l = strlen(num); + if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && l < NUM_BUF_SIZE - 2) { + num[l++] = '.'; + num[l++] = '0'; + num[l] = '\0'; + } + smart_str_appendl(buf, num, l); return; } } @@ -620,14 +636,19 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_ case IS_DOUBLE: { - char *d = NULL; + char num[NUM_BUF_SIZE]; int len; double dbl = Z_DVAL_P(val); if (!zend_isinf(dbl) && !zend_isnan(dbl)) { - len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl); - smart_str_appendl(buf, d, len); - efree(d); + php_gcvt(dbl, EG(precision), '.', 'e', (char *)num); + len = strlen(num); + if (options & PHP_JSON_PRESERVE_ZERO_FRACTION && strchr(num, '.') == NULL && len < NUM_BUF_SIZE - 2) { + num[len++] = '.'; + num[len++] = '0'; + num[len] = '\0'; + } + smart_str_appendl(buf, num, len); } else { JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN; smart_str_appendc(buf, '0'); @@ -710,14 +731,14 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, RETVAL_NULL(); if (trim_len == 4) { - if (!strncasecmp(trim, "null", trim_len)) { + 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 (!strncasecmp(trim, "true", trim_len)) { + } else if (!strncmp(trim, "true", trim_len)) { RETVAL_BOOL(1); } - } else if (trim_len == 5 && !strncasecmp(trim, "false", trim_len)) { + } else if (trim_len == 5 && !strncmp(trim, "false", trim_len)) { RETVAL_BOOL(0); } diff --git a/ext/json/json.dsp b/ext/json/json.dsp index e5bb3767bf..9ef97bb80e 100644 --- a/ext/json/json.dsp +++ b/ext/json/json.dsp @@ -102,22 +102,6 @@ SOURCE=.\JSON_parser.c 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"
diff --git a/ext/json/package.xml b/ext/json/package.xml index 0651de736f..b59e47cf0b 100644 --- a/ext/json/package.xml +++ b/ext/json/package.xml @@ -36,10 +36,6 @@ <file role="src" name="JSON_parser.c" /> <file role="src" name="JSON_parser.h" /> <file role="src" name="php_json.h" /> - <file role="src" name="utf8_decode.c" /> - <file role="src" name="utf8_decode.h" /> - <file role="src" name="utf8_to_utf16.c" /> - <file role="src" name="utf8_to_utf16.h" /> <dir role="test" name="tests"> <file role="test" name="fail001.phpt" /> <file role="test" name="pass001.phpt" /> diff --git a/ext/json/php_json.h b/ext/json/php_json.h index 7347ef7e06..efd872b5f4 100644 --- a/ext/json/php_json.h +++ b/ext/json/php_json.h @@ -65,6 +65,7 @@ extern PHP_JSON_API zend_class_entry *php_json_serializable_ce; #define PHP_JSON_PRETTY_PRINT (1<<7) #define PHP_JSON_UNESCAPED_UNICODE (1<<8) #define PHP_JSON_PARTIAL_OUTPUT_ON_ERROR (1<<9) +#define PHP_JSON_PRESERVE_ZERO_FRACTION (1<<10) /* Internal flags */ #define PHP_JSON_OUTPUT_ARRAY 0 diff --git a/ext/json/tests/bug50224.phpt b/ext/json/tests/bug50224.phpt new file mode 100644 index 0000000000..3408ac906f --- /dev/null +++ b/ext/json/tests/bug50224.phpt @@ -0,0 +1,60 @@ +--TEST-- +bug #50224 (json_encode() does not always encode a float as a float) +--SKIPIF-- +<?php if (!extension_loaded("json")) print "skip"; ?> +--FILE-- +<?php +echo "* Testing JSON output\n\n"; +var_dump(json_encode(12.3, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(12, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(12.0, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(0.0, JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode(array(12, 12.0, 12.3), JSON_PRESERVE_ZERO_FRACTION)); +var_dump(json_encode((object)array('float' => 12.0, 'integer' => 12), JSON_PRESERVE_ZERO_FRACTION)); + +echo "\n* Testing encode/decode symmetry\n\n"; + +var_dump(json_decode(json_encode(12.3, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(12, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(12.0, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(0.0, JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode(array(12, 12.0, 12.3), JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode((object)array('float' => 12.0, 'integer' => 12), JSON_PRESERVE_ZERO_FRACTION))); +var_dump(json_decode(json_encode((object)array('float' => 12.0, 'integer' => 12), JSON_PRESERVE_ZERO_FRACTION), true)); +?> +--EXPECTF-- +* Testing JSON output + +string(4) "12.3" +string(2) "12" +string(4) "12.0" +string(3) "0.0" +string(14) "[12,12.0,12.3]" +string(27) "{"float":12.0,"integer":12}" + +* Testing encode/decode symmetry + +float(12.3) +int(12) +float(12) +float(0) +array(3) { + [0]=> + int(12) + [1]=> + float(12) + [2]=> + float(12.3) +} +object(stdClass)#%d (2) { + ["float"]=> + float(12) + ["integer"]=> + int(12) +} +array(2) { + ["float"]=> + float(12) + ["integer"]=> + int(12) +}
\ No newline at end of file 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/utf8_decode.c b/ext/json/utf8_decode.c deleted file mode 100644 index 2d0422bedb..0000000000 --- a/ext/json/utf8_decode.c +++ /dev/null @@ -1,179 +0,0 @@ -/* utf8_decode.c */ - -/* 2005-12-25 */ - -/* -Copyright (c) 2005 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "utf8_decode.h" - -/* - Very Strict UTF-8 Decoder - - UTF-8 is a multibyte character encoding of Unicode. A character can be - represented by 1-4 bytes. The bit pattern of the first byte indicates the - number of continuation bytes. - - Most UTF-8 decoders tend to be lenient, attempting to recover as much - information as possible, even from badly encoded input. This UTF-8 - decoder is not lenient. It will reject input which does not include - proper continuation bytes. It will reject aliases (or suboptimal - codings). It will reject surrogates. (Surrogate encoding should only be - used with UTF-16.) - - Code Contination Minimum Maximum - 0xxxxxxx 0 0 127 - 10xxxxxx error - 110xxxxx 1 128 2047 - 1110xxxx 2 2048 65535 excluding 55296 - 57343 - 11110xxx 3 65536 1114111 - 11111xxx error -*/ - - -/* - Get the next byte. It returns UTF8_END if there are no more bytes. -*/ -static int -get(json_utf8_decode *utf8) -{ - int c; - if (utf8->the_index >= utf8->the_length) { - return UTF8_END; - } - c = utf8->the_input[utf8->the_index] & 0xFF; - utf8->the_index += 1; - return c; -} - - -/* - Get the 6-bit payload of the next continuation byte. - Return UTF8_ERROR if it is not a contination byte. -*/ -static int -cont(json_utf8_decode *utf8) -{ - int c = get(utf8); - return ((c & 0xC0) == 0x80) ? (c & 0x3F) : UTF8_ERROR; -} - - -/* - Initialize the UTF-8 decoder. The decoder is not reentrant, -*/ -void -utf8_decode_init(json_utf8_decode *utf8, char p[], int length) -{ - utf8->the_index = 0; - utf8->the_input = p; - utf8->the_length = length; - utf8->the_char = 0; - utf8->the_byte = 0; -} - - -/* - Get the current byte offset. This is generally used in error reporting. -*/ -int -utf8_decode_at_byte(json_utf8_decode *utf8) -{ - return utf8->the_byte; -} - - -/* - Get the current character offset. This is generally used in error reporting. - The character offset matches the byte offset if the text is strictly ASCII. -*/ -int -utf8_decode_at_character(json_utf8_decode *utf8) -{ - return utf8->the_char > 0 ? utf8->the_char - 1 : 0; -} - - -/* - Extract the next character. - Returns: the character (between 0 and 1114111) - or UTF8_END (the end) - or UTF8_ERROR (error) -*/ -int -utf8_decode_next(json_utf8_decode *utf8) -{ - int c; /* the first byte of the character */ - int r; /* the result */ - - if (utf8->the_index >= utf8->the_length) { - return utf8->the_index == utf8->the_length ? UTF8_END : UTF8_ERROR; - } - utf8->the_byte = utf8->the_index; - utf8->the_char += 1; - c = get(utf8); -/* - Zero continuation (0 to 127) -*/ - if ((c & 0x80) == 0) { - return c; - } -/* - One contination (128 to 2047) -*/ - if ((c & 0xE0) == 0xC0) { - int c1 = cont(utf8); - if (c1 < 0) { - return UTF8_ERROR; - } - r = ((c & 0x1F) << 6) | c1; - return r >= 128 ? r : UTF8_ERROR; - } -/* - Two continuation (2048 to 55295 and 57344 to 65535) -*/ - if ((c & 0xF0) == 0xE0) { - int c1 = cont(utf8); - int c2 = cont(utf8); - if (c1 < 0 || c2 < 0) { - return UTF8_ERROR; - } - r = ((c & 0x0F) << 12) | (c1 << 6) | c2; - return r >= 2048 && (r < 55296 || r > 57343) ? r : UTF8_ERROR; - } -/* - Three continuation (65536 to 1114111) -*/ - if ((c & 0xF8) == 0xF0) { - int c1 = cont(utf8); - int c2 = cont(utf8); - int c3 = cont(utf8); - if (c1 < 0 || c2 < 0 || c3 < 0) { - return UTF8_ERROR; - } - r = ((c & 0x0F) << 18) | (c1 << 12) | (c2 << 6) | c3; - return r >= 65536 && r <= 1114111 ? r : UTF8_ERROR; - } - return UTF8_ERROR; -} diff --git a/ext/json/utf8_decode.h b/ext/json/utf8_decode.h deleted file mode 100644 index cc0fc79f6c..0000000000 --- a/ext/json/utf8_decode.h +++ /dev/null @@ -1,18 +0,0 @@ -/* utf8_decode.h */ - -#define UTF8_END -1 -#define UTF8_ERROR -2 - -typedef struct json_utf8_decode -{ - int the_index; - char *the_input; - int the_length; - int the_char; - int the_byte; -} json_utf8_decode; - -extern int utf8_decode_at_byte(json_utf8_decode *utf8); -extern int utf8_decode_at_character(json_utf8_decode *utf8); -extern void utf8_decode_init(json_utf8_decode *utf8, char p[], int length); -extern int utf8_decode_next(json_utf8_decode *utf8); |
