diff options
-rw-r--r-- | ext/json/CREDITS | 2 | ||||
-rw-r--r-- | ext/json/Makefile.frag | 5 | ||||
-rw-r--r-- | ext/json/config.m4 | 7 | ||||
-rw-r--r-- | ext/json/config.w32 | 6 | ||||
-rw-r--r-- | ext/json/json_parser.y | 242 | ||||
-rw-r--r-- | ext/json/json_scanner.re | 345 | ||||
-rw-r--r-- | ext/json/php_json_parser.h | 42 | ||||
-rw-r--r-- | ext/json/php_json_scanner.h | 47 | ||||
-rw-r--r-- | ext/json/utf8_decode.c | 179 | ||||
-rw-r--r-- | ext/json/utf8_decode.h | 18 |
10 files changed, 693 insertions, 200 deletions
diff --git a/ext/json/CREDITS b/ext/json/CREDITS index 9bd7f44f21..a9a0dc70c4 100644 --- a/ext/json/CREDITS +++ b/ext/json/CREDITS @@ -1,2 +1,2 @@ JSON -Omar Kilani, Scott MacVicar +Jakub Zelenka, Omar Kilani, Scott MacVicar diff --git a/ext/json/Makefile.frag b/ext/json/Makefile.frag new file mode 100644 index 0000000000..1632b448fe --- /dev/null +++ b/ext/json/Makefile.frag @@ -0,0 +1,5 @@ +$(srcdir)/json_scanner.c: $(srcdir)/json_scanner.re + $(RE2C) -t php_json_scanner_defs.h --no-generation-date -bci -o $@ json_scanner.re + +$(srcdir)/json_parser.tab.c: $(srcdir)/json_parser.y + $(YACC) --defines -l $(srcdir)/json_parser.y -o $@ diff --git a/ext/json/config.m4 b/ext/json/config.m4 index 26c43a0e3f..1d787f40f3 100644 --- a/ext/json/config.m4 +++ b/ext/json/config.m4 @@ -9,7 +9,12 @@ 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.tab.c \ + json_scanner.c, + $ext_shared) PHP_INSTALL_HEADERS([ext/json], [php_json.h]) + PHP_ADD_MAKEFILE_FRAGMENT() PHP_SUBST(JSON_SHARED_LIBADD) fi diff --git a/ext/json/config.w32 b/ext/json/config.w32 index cedbf42829..790c86d5ea 100644 --- a/ext/json/config.w32 +++ b/ext/json/config.w32 @@ -5,7 +5,11 @@ 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"); + PHP_NEW_EXTENSION(json, + json.c \ + json_parser.tab.c \ + json_scanner.c, + $ext_shared) PHP_INSTALL_HEADERS("ext/json/", "php_json.h"); } diff --git a/ext/json/json_parser.y b/ext/json/json_parser.y new file mode 100644 index 0000000000..158bf1be80 --- /dev/null +++ b/ext/json/json_parser.y @@ -0,0 +1,242 @@ +%code top { +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_json.h" +#include "php_json_parser.h" + +#define YYDEBUG 0 + +#if YYDEBUG +int json_yydebug = 1; +#endif + +#define PHP_JSON_USE(uv) ((void) (uv)) +#define PHP_JSON_USE_1(uvr, uv1) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1) +#define PHP_JSON_USE_2(uvr, uv1, uv2) PHP_JSON_USE(uvr); PHP_JSON_USE(uv1); PHP_JSON_USE(uv2) + +} + +%pure-parser +%name-prefix "php_json_yy" +%lex-param { php_json_parser *parser } +%parse-param { php_json_parser *parser } + +%union { + zval value; + struct { + zval key; + zval val; + } pair; + HashTable *ht; +} + + +%token <value> PHP_JSON_T_NUL +%token <value> PHP_JSON_T_TRUE +%token <value> PHP_JSON_T_FALSE +%token <value> PHP_JSON_T_INT +%token <value> PHP_JSON_T_DOUBLE +%token <value> PHP_JSON_T_STRING +%token <value> PHP_JSON_T_ESTRING +%token <value> PHP_JSON_T_EOI +%token <value> PHP_JSON_T_ERROR + +%type <value> start object key value array errlex +%type <ht> members member elements element +%type <pair> pair + +%destructor { zval_dtor(&$$); } <value> +%destructor { zend_hash_destroy($$); FREE_HASHTABLE($$); } <ht> +%destructor { zval_dtor(&$$.key); zval_dtor(&$$.val); } <pair> + +%code { +int php_json_yylex(union YYSTYPE *value, php_json_parser *parser); +void php_json_yyerror(php_json_parser *parser, char const *msg); +void php_json_parser_object_to_zval(php_json_parser *parser, zval *zv, HashTable *ht); +void php_json_parser_array_to_zval(zval *zv, HashTable *ht); +void php_json_parser_ht_init(HashTable **ht, uint nSize); +void php_json_parser_ht_update(php_json_parser *parser, HashTable *ht, zval *zkey, zval *zvalue); +void php_json_parser_ht_append(HashTable *ht, zval *zvalue); + +#define PHP_JSON_DEPTH_DEC --parser->depth +#define PHP_JSON_DEPTH_INC \ + if (parser->max_depth && parser->depth >= parser->max_depth) { \ + parser->scanner.errcode = PHP_JSON_ERROR_DEPTH; \ + YYERROR; \ + } \ + ++parser->depth +} + +%% /* Rules */ + +start: + value PHP_JSON_T_EOI { $$ = $1; INIT_PZVAL_COPY(parser->return_value, &$1); PHP_JSON_USE($2); YYACCEPT; } + | value errlex { PHP_JSON_USE_2($$, $1, $2); } +; + +object: + '{' { PHP_JSON_DEPTH_INC; } members object_end { PHP_JSON_DEPTH_DEC; php_json_parser_object_to_zval(parser, &$$, $3); } +; + +object_end: + '}' + | ']' { parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH; YYERROR; } +; + +members: + /* empty */ { php_json_parser_ht_init(&$$, 0); } + | member +; + +member: + pair { php_json_parser_ht_init(&$$, 4); php_json_parser_ht_update(parser, $$, &$1.key, &$1.val); } + | member ',' pair { php_json_parser_ht_update(parser, $1, &$3.key, &$3.val); $$ = $1; } + | member errlex { PHP_JSON_USE_2($$, $1, $2); } +; + +pair: + key ':' value { $$.key = $1; $$.val = $3; } + | key errlex { PHP_JSON_USE_2($$, $1, $2); } +; + +array: + '[' { PHP_JSON_DEPTH_INC; } elements array_end { PHP_JSON_DEPTH_DEC; php_json_parser_array_to_zval(&$$, $3); } +; + +array_end: + ']' + | '}' { parser->scanner.errcode = PHP_JSON_ERROR_STATE_MISMATCH; YYERROR; } +; + +elements: + /* empty */ { php_json_parser_ht_init(&$$, 0); } + | element +; + +element: + value { php_json_parser_ht_init(&$$, 4); php_json_parser_ht_append($$, &$1); } + | element ',' value { php_json_parser_ht_append($1, &$3); $$ = $1; } + | element errlex { PHP_JSON_USE_2($$, $1, $2); } +; + +key: + PHP_JSON_T_STRING + | PHP_JSON_T_ESTRING +; + +value: + object + | array + | PHP_JSON_T_STRING + | PHP_JSON_T_ESTRING + | PHP_JSON_T_INT + | PHP_JSON_T_DOUBLE + | PHP_JSON_T_NUL + | PHP_JSON_T_TRUE + | PHP_JSON_T_FALSE + | errlex +; + +errlex: + PHP_JSON_T_ERROR { PHP_JSON_USE_1($$, $1); YYERROR; } +; + +%% /* Functions */ + +void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, int str_len, long options, long max_depth TSRMLS_DC) +{ + memset(parser, 0, sizeof(php_json_parser)); + php_json_scanner_init(&parser->scanner, str, str_len, options); + parser->depth = 1; + parser->max_depth = max_depth; + parser->return_value = return_value; + TSRMLS_SET_CTX(parser->zts_ctx); +} + +php_json_error_code php_json_parser_error_code(php_json_parser *parser) +{ + return parser->scanner.errcode; +} + +void php_json_parser_object_to_zval(php_json_parser *parser, zval *zv, HashTable *ht) +{ + TSRMLS_FETCH_FROM_CTX(parser->zts_ctx); + + if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { + php_json_parser_array_to_zval(zv, ht); + } else { + object_and_properties_init(zv, zend_standard_class_def, ht); + } +} + +void php_json_parser_array_to_zval(zval *zv, HashTable *ht) +{ + Z_TYPE_P(zv) = IS_ARRAY; + Z_ARRVAL_P(zv) = ht; +} + +void php_json_parser_ht_init(HashTable **ht, uint nSize) +{ + ALLOC_HASHTABLE(*ht); + zend_hash_init(*ht, nSize, NULL, ZVAL_PTR_DTOR, 0); +} + +void php_json_parser_ht_update(php_json_parser *parser, HashTable *ht, zval *zkey, zval *zvalue) +{ + zval *data; + char *key = Z_STRVAL_P(zkey); + int key_len = Z_STRLEN_P(zkey)+1; + MAKE_STD_ZVAL(data); + ZVAL_ZVAL(data, zvalue, 0, 0); + + if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) { + zend_symtable_update(ht, key, key_len, &data, sizeof(zval *), NULL); + } else { + if (key_len == 1) { + key = "_empty_"; + key_len = sizeof("_empty_"); + } + zend_hash_update(ht, key, key_len, &data, sizeof(zval *), NULL); + } + + zval_dtor(zkey); +} + +void php_json_parser_ht_append(HashTable *ht, zval *zvalue) +{ + zval *data; + MAKE_STD_ZVAL(data); + ZVAL_ZVAL(data, zvalue, 0, 0); + zend_hash_next_index_insert(ht, &data, sizeof(zval *), NULL); +} + +int php_json_yylex(union YYSTYPE *value, php_json_parser *parser) +{ + int token = php_json_scan(&parser->scanner); + value->value = parser->scanner.value; + return token; +} + +void php_json_yyerror(php_json_parser *parser, char const *msg) +{ + if (!parser->scanner.errcode) { + parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX; + } +} diff --git a/ext/json/json_scanner.re b/ext/json/json_scanner.re new file mode 100644 index 0000000000..7fa9352c09 --- /dev/null +++ b/ext/json/json_scanner.re @@ -0,0 +1,345 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "php.h" +#include "php_json_scanner.h" +#include "php_json_scanner_defs.h" +#include "php_json_parser.h" +#include "json_parser.tab.h" + +#define YYCTYPE php_json_ctype +#define YYCURSOR s->cursor +#define YYLIMIT s->limit +#define YYMARKER s->marker +#define YYCTXMARKER s->ctxmarker + +#define YYGETCONDITION() s->state +#define YYSETCONDITION(yystate) s->state = yystate + +#define YYFILL(n) + +#define PHP_JSON_CONDITION_SET(condition) YYSETCONDITION(yyc##condition) +#define PHP_JSON_CONDITION_GOTO(condition) goto yyc_##condition + +#define PHP_JSON_SCANNER_COPY_ESC() php_json_scanner_copy_string(s, 0) +#define PHP_JSON_SCANNER_COPY_UTF() php_json_scanner_copy_string(s, 5) +#define PHP_JSON_SCANNER_COPY_UTF_SP() php_json_scanner_copy_string(s, 11) + + +static void php_json_scanner_copy_string(php_json_scanner *s, int esc_size) +{ + size_t len = s->cursor - s->str_start - esc_size - 1; + if (len) { + memcpy(s->pstr, s->str_start, len); + s->pstr += len; + } +} + +static int php_json_hex_to_int(char code) +{ + if (code >= '0' && code <= '9') { + return code - '0'; + } else if (code >= 'A' && code <= 'F') { + return code - ('A' - 10); + } else if (code >= 'a' && code <= 'f') { + return code - ('a' - 10); + } else { + /* this should never happened (just to suppress compiler warning) */ + return -1; + } +} + +static int php_json_ucs2_to_int_ex(php_json_scanner *s, int size, int start) +{ + int i, code = 0; + php_json_ctype *pc = s->cursor - start; + for (i = 0; i < size; i++) { + code |= php_json_hex_to_int(*(pc--)) << (i * 4); + } + return code; +} + +static int php_json_ucs2_to_int(php_json_scanner *s, int size) +{ + return php_json_ucs2_to_int_ex(s, size, 1); +} + +void php_json_scanner_init(php_json_scanner *s, char *str, int str_len, long options) +{ + s->cursor = (php_json_ctype *) str; + s->limit = (php_json_ctype *) str + str_len; + s->options = options; + PHP_JSON_CONDITION_SET(JS); +} + +int php_json_scan(php_json_scanner *s) +{ + ZVAL_NULL(&s->value); + +std: + s->token = s->cursor; + +/*!re2c + re2c:indent:top = 1; + re2c:yyfill:enable = 0; + + DIGIT = [0-9] ; + DIGITNZ = [1-9] ; + UINT = "0" | ( DIGITNZ DIGIT* ) ; + INT = "-"? UINT ; + HEX = DIGIT | [a-fA-F] ; + HEXNZ = DIGITNZ | [a-fA-F] ; + HEX7 = [0-7] ; + HEXC = DIGIT | [a-cA-C] ; + FLOAT = INT "." DIGIT+ ; + EXP = ( INT | FLOAT ) [eE] [+-]? DIGIT+ ; + NL = "\r"? "\n" ; + WS = [ \t\r]+ ; + EOI = "\000"; + CTRL = [\x00-\x1F] ; + UTF8T = [\x80-\xBF] ; + UTF8_1 = [\x00-\x7F] ; + UTF8_2 = [\xC2-\xDF] UTF8T ; + UTF8_3A = "\xE0" [\xA0-\xBF] UTF8T ; + UTF8_3B = [\xE1-\xEC] UTF8T{2} ; + UTF8_3C = "\xED" [\x80-\x9F] UTF8T ; + UTF8_3D = [\xEE-\xEF] UTF8T{2} ; + UTF8_3 = UTF8_3A | UTF8_3B | UTF8_3C | UTF8_3D ; + UTF8_4A = "\xF0"[\x90-\xBF] UTF8T{2} ; + UTF8_4B = [\xF1-\xF3] UTF8T{3} ; + UTF8_4C = "\xF4" [\x80-\x8F] UTF8T{2} ; + UTF8_4 = UTF8_4A | UTF8_4B | UTF8_4C ; + UTF8 = UTF8_1 | UTF8_2 | UTF8_3 | UTF8_4 ; + ANY = [^] ; + ESCPREF = "\\" ; + ESCSYM = ( "\"" | "\\" | "/" | [bfnrt] ) ; + ESC = ESCPREF ESCSYM ; + UTFSYM = "u" ; + UTFPREF = ESCPREF UTFSYM ; + UCS2 = UTFPREF HEX{4} ; + UTF16_1 = UTFPREF "00" HEX7 HEX ; + UTF16_2 = UTFPREF "0" HEX7 HEX{2} ; + UTF16_3 = UTFPREF ( ( ( HEXC | [efEF] ) HEX ) | ( [dD] HEX7 ) ) HEX{2} ; + UTF16_4 = UTFPREF [dD] [89abAB] HEX{2} UTFPREF [dD] [c-fC-F] HEX{2} ; + + <JS>"{" { return '{'; } + <JS>"}" { return '}'; } + <JS>"[" { return '['; } + <JS>"]" { return ']'; } + <JS>":" { return ':'; } + <JS>"," { return ','; } + <JS>"null" { + ZVAL_NULL(&s->value); + return PHP_JSON_T_NUL; + } + <JS>"true" { + ZVAL_TRUE(&s->value); + return PHP_JSON_T_TRUE; + } + <JS>"false" { + ZVAL_FALSE(&s->value); + return PHP_JSON_T_FALSE; + } + <JS>INT { + zend_bool bigint = 0, negative = s->token[0] == '-'; + size_t digits = (size_t) (s->cursor - s->token - negative); + if (digits >= PHP_JSON_INT_MAX_LENGTH) { + if (digits == PHP_JSON_INT_MAX_LENGTH) { + int cmp = strncmp((char *) (s->token + negative), PHP_JSON_INT_MAX_DIGITS, PHP_JSON_INT_MAX_LENGTH); + if (!(cmp < 0 || (cmp == 0 && negative))) { + bigint = 1; + } + } else { + bigint = 1; + } + } + if (!bigint) { + ZVAL_LONG(&s->value, strtol((char *) s->token, NULL, 10)); + return PHP_JSON_T_INT; + } else if (s->options & PHP_JSON_BIGINT_AS_STRING) { + ZVAL_STRINGL(&s->value, (char *) s->token, s->cursor - s->token, 1); + return PHP_JSON_T_STRING; + } else { + ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); + return PHP_JSON_T_DOUBLE; + } + } + <JS>FLOAT|EXP { + ZVAL_DOUBLE(&s->value, zend_strtod((char *) s->token, NULL)); + return PHP_JSON_T_DOUBLE; + } + <JS>NL|WS { goto std; } + <JS>EOI { + if (s->limit < s->cursor) { + return PHP_JSON_T_EOI; + } else { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } + } + <JS>["] { + s->str_start = s->cursor; + s->str_esc = 0; + PHP_JSON_CONDITION_SET(STR_P1); + PHP_JSON_CONDITION_GOTO(STR_P1); + } + + <STR_P1>CTRL { + s->errcode = PHP_JSON_ERROR_CTRL_CHAR; + return PHP_JSON_T_ERROR; + } + <STR_P1>UTF16_1 { + s->str_esc += 5; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UTF16_2 { + s->str_esc += 4; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UTF16_3 { + s->str_esc += 3; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UTF16_4 { + s->str_esc += 8; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>UCS2 { + s->errcode = PHP_JSON_ERROR_UTF16; + return PHP_JSON_T_ERROR; + } + <STR_P1>ESC { + s->str_esc++; + PHP_JSON_CONDITION_GOTO(STR_P1); + } + <STR_P1>ESCPREF { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } + <STR_P1>["] { + char *str; + size_t len = s->cursor - s->str_start - s->str_esc - 1; + if (len == 0) { + PHP_JSON_CONDITION_SET(JS); + ZVAL_EMPTY_STRING(&s->value); + return PHP_JSON_T_ESTRING; + } + str = emalloc(len + 1); + str[len] = 0; + ZVAL_STRINGL(&s->value, str, len, 0); + if (s->str_esc) { + s->pstr = (php_json_ctype *) Z_STRVAL(s->value); + s->cursor = s->str_start; + PHP_JSON_CONDITION_SET(STR_P2); + PHP_JSON_CONDITION_GOTO(STR_P2); + } else { + memcpy(Z_STRVAL(s->value), s->str_start, len); + PHP_JSON_CONDITION_SET(JS); + return PHP_JSON_T_STRING; + } + } + <STR_P1>UTF8 { PHP_JSON_CONDITION_GOTO(STR_P1); } + <STR_P1>ANY { + s->errcode = PHP_JSON_ERROR_UTF8; + return PHP_JSON_T_ERROR; + } + + <STR_P2>UTF16_1 { + int utf16 = php_json_ucs2_to_int(s, 2); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) utf16; + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>UTF16_2 { + int utf16 = php_json_ucs2_to_int(s, 3); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) (0xc0 | (utf16 >> 6)); + *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>UTF16_3 { + int utf16 = php_json_ucs2_to_int(s, 4); + PHP_JSON_SCANNER_COPY_UTF(); + *(s->pstr++) = (char) (0xe0 | (utf16 >> 12)); + *(s->pstr++) = (char) (0x80 | ((utf16 >> 6) & 0x3f)); + *(s->pstr++) = (char) (0x80 | (utf16 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>UTF16_4 { + int utf32, utf16_hi, utf16_lo; + utf16_hi = php_json_ucs2_to_int(s, 4); + utf16_lo = php_json_ucs2_to_int_ex(s, 4, 7); + utf32 = ((utf16_lo & 0x3FF) << 10) + (utf16_hi & 0x3FF) + 0x10000; + PHP_JSON_SCANNER_COPY_UTF_SP(); + *(s->pstr++) = (char) (0xf0 | (utf32 >> 18)); + *(s->pstr++) = (char) (0x80 | ((utf32 >> 12) & 0x3f)); + *(s->pstr++) = (char) (0x80 | ((utf32 >> 6) & 0x3f)); + *(s->pstr++) = (char) (0x80 | (utf32 & 0x3f)); + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>ESCPREF { + char esc; + PHP_JSON_SCANNER_COPY_ESC(); + switch (*s->cursor) { + case 'b': + esc = '\b'; + break; + case 'f': + esc = '\f'; + break; + case 'n': + esc = '\n'; + break; + case 'r': + esc = '\r'; + break; + case 't': + esc = '\t'; + break; + case '\\': + case '/': + case '"': + esc = *s->cursor; + break; + default: + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } + *(s->pstr++) = esc; + ++YYCURSOR; + s->str_start = s->cursor; + PHP_JSON_CONDITION_GOTO(STR_P2); + } + <STR_P2>["] => JS { + PHP_JSON_SCANNER_COPY_ESC(); + return PHP_JSON_T_STRING; + } + <STR_P2>ANY { PHP_JSON_CONDITION_GOTO(STR_P2); } + + <*>ANY { + s->errcode = PHP_JSON_ERROR_SYNTAX; + return PHP_JSON_T_ERROR; + } +*/ + +} + diff --git a/ext/json/php_json_parser.h b/ext/json/php_json_parser.h new file mode 100644 index 0000000000..3e3836248c --- /dev/null +++ b/ext/json/php_json_parser.h @@ -0,0 +1,42 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_JSOND_PARSER_H +#define PHP_JSOND_PARSER_H + +#include "php.h" +#include "php_json_scanner.h" + +typedef struct _php_json_parser { + php_json_scanner scanner; + zval *return_value; + long depth; + long max_depth; +#if ZTS + void *zts_ctx; +#endif +} php_json_parser; + +void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, int str_len, long options, long max_depth TSRMLS_DC); + +php_json_error_code php_json_parser_error_code(php_json_parser *parser); + +int php_json_yyparse(php_json_parser *parser); + +#endif /* PHP_JSOND_PARSER_H */ + diff --git a/ext/json/php_json_scanner.h b/ext/json/php_json_scanner.h new file mode 100644 index 0000000000..69d21cfc5c --- /dev/null +++ b/ext/json/php_json_scanner.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 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 | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Jakub Zelenka <bukka@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHP_JSOND_SCANNER_H +#define PHP_JSOND_SCANNER_H + +#include "php.h" +#include "php_json.h" + +typedef unsigned char php_json_ctype; + +typedef struct _php_json_scanner { + php_json_ctype *cursor; /* cursor position */ + php_json_ctype *token; /* token position */ + php_json_ctype *limit; /* the last read character + 1 position */ + php_json_ctype *marker; /* marker position for backtracking */ + php_json_ctype *ctxmarker; /* marker position for context backtracking */ + php_json_ctype *str_start; /* start position of the string */ + php_json_ctype *pstr; /* string pointer for escapes conversion */ + int str_esc; /* number of extra characters for escaping */ + int state; /* condition state */ + zval value; /* value */ + long options; /* options */ + php_json_error_code errcode; /* error type if there is an error */ +} php_json_scanner; + + +void php_json_scanner_init(php_json_scanner *scanner, char *str, int str_len, long options); +int php_json_scan(php_json_scanner *s); + +#endif /* PHP_JSOND_SCANNER_H */ + 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 0908edd2d4..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 -{ - char *the_input; - int the_index; - 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); |