Update the JSON parser with that on json.org, biggest change here is code readability. Less magic numbers in the state table.

Add missing reflection information to json_encode()
Fixes bug #45791 with 0e0 not being supported as a value
Error values are stored when encountered during parsing
This commit is contained in:
Scott MacVicar 2008-12-17 14:39:56 +00:00
parent c7a56d604b
commit cae85c867a
3 changed files with 636 additions and 599 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,24 @@
/* JSON_checker.h */ /* JSON_parser.h */
#ifndef JSON_PARSER_H
#define JSON_PARSER_H
#include "php.h" #include "php.h"
#include "ext/standard/php_smart_str.h" #include "ext/standard/php_smart_str.h"
extern int JSON_parser(zval *z, unsigned short p[], int length, int assoc TSRMLS_DC); #define JSON_PARSER_MAX_DEPTH 512
typedef struct JSON_parser_struct {
int state;
int depth;
int top;
int error;
int* stack;
zval *the_zstack[JSON_PARSER_MAX_DEPTH];
} * JSON_parser;
extern JSON_parser new_JSON_parser(int depth);
extern int parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int assoc TSRMLS_DC);
extern int free_JSON_parser(JSON_parser jp);
#endif

View file

@ -475,7 +475,7 @@ static PHP_FUNCTION(json_encode)
} }
/* }}} */ /* }}} */
/* {{{ proto mixed json_decode(string json [, bool assoc]) U /* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]]) U
Decodes the JSON representation into a PHP value */ Decodes the JSON representation into a PHP value */
static PHP_FUNCTION(json_decode) static PHP_FUNCTION(json_decode)
{ {
@ -483,10 +483,12 @@ static PHP_FUNCTION(json_decode)
int str_len, utf16_len; int str_len, utf16_len;
zend_uchar str_type; zend_uchar str_type;
zend_bool assoc = 0; /* return JS objects as PHP objects by default */ zend_bool assoc = 0; /* return JS objects as PHP objects by default */
long depth = JSON_PARSER_MAX_DEPTH;
zval *z; zval *z;
unsigned short *utf16; unsigned short *utf16;
JSON_parser jp;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t|b", &str, &str_len, &str_type, &assoc) == FAILURE) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "t|bl", &str, &str_len, &str_type, &assoc, &depth) == FAILURE) {
return; return;
} }
@ -509,14 +511,15 @@ static PHP_FUNCTION(json_decode)
} }
} }
ALLOC_INIT_ZVAL(z); /* can be removed once we remove the max depth limit */
if (JSON_parser(z, utf16, utf16_len, assoc TSRMLS_CC)) { if (depth <= 0 || depth > JSON_PARSER_MAX_DEPTH) {
*return_value = *z; depth = JSON_PARSER_MAX_DEPTH;
FREE_ZVAL(z);
if (str_type == IS_STRING) {
efree(utf16);
} }
ALLOC_INIT_ZVAL(z);
jp = new_JSON_parser(depth);
if (parse_JSON(jp, z, utf16, utf16_len, assoc TSRMLS_CC)) {
*return_value = *z;
} }
else if (str_type == IS_STRING) else if (str_type == IS_STRING)
{ {
@ -525,26 +528,25 @@ static PHP_FUNCTION(json_decode)
long p; long p;
zval_dtor(z); zval_dtor(z);
FREE_ZVAL(z); RETVAL_NULL();
efree(utf16);
if (str_len == 4) { if (str_len == 4) {
if (!strcasecmp(str.s, "null")) { if (!strcasecmp(str.s, "null")) {
RETURN_NULL(); RETVAL_NULL();
} else if (!strcasecmp(str.s, "true")) { } else if (!strcasecmp(str.s, "true")) {
RETURN_BOOL(1); RETVAL_BOOL(1);
} }
} else if (str_len == 5 && !strcasecmp(str.s, "false")) { } else if (str_len == 5 && !strcasecmp(str.s, "false")) {
RETURN_BOOL(0); RETVAL_BOOL(0);
} }
if ((type = is_numeric_string(str.s, str_len, &p, &d, 0)) != 0) { if ((type = is_numeric_string(str.s, str_len, &p, &d, 0)) != 0) {
if (type == IS_LONG) { if (type == IS_LONG) {
RETURN_LONG(p); RETVAL_LONG(p);
} else if (type == IS_DOUBLE) { } else if (type == IS_DOUBLE) {
RETURN_DOUBLE(d); RETVAL_DOUBLE(d);
} }
} }
RETURN_NULL();
} }
else else
{ {
@ -553,26 +555,32 @@ static PHP_FUNCTION(json_decode)
long p; long p;
zval_dtor(z); zval_dtor(z);
FREE_ZVAL(z); RETVAL_NULL();
if (str_len == 4) { if (str_len == 4) {
if (ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "null", sizeof("null")-1)) { if (ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "null", sizeof("null")-1)) {
RETURN_NULL(); RETVAL_NULL();
} else if (ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "true", sizeof("true")-1)) { } else if (ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "true", sizeof("true")-1)) {
RETURN_BOOL(1); RETVAL_BOOL(1);
} }
} else if (str_len == 5 && ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "false", sizeof("false")-1)) { } else if (str_len == 5 && ZEND_U_CASE_EQUAL(IS_UNICODE, str, str_len, "false", sizeof("false")-1)) {
RETURN_BOOL(0); RETVAL_BOOL(0);
} }
if ((type = is_numeric_unicode(str.u, str_len, &p, &d, 0)) != 0) { if ((type = is_numeric_unicode(str.u, str_len, &p, &d, 0)) != 0) {
if (type == IS_LONG) { if (type == IS_LONG) {
RETURN_LONG(p); RETVAL_LONG(p);
} else if (type == IS_DOUBLE) { } else if (type == IS_DOUBLE) {
RETURN_DOUBLE(d); RETVAL_DOUBLE(d);
} }
} }
RETURN_NULL();
} }
FREE_ZVAL(z);
if (str_type == IS_STRING) {
efree(utf16);
}
free_JSON_parser(jp);
} }
/* }}} */ /* }}} */