summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/json/CREDITS2
-rw-r--r--ext/json/Makefile.frag5
-rw-r--r--ext/json/config.m47
-rw-r--r--ext/json/config.w326
-rw-r--r--ext/json/json_parser.y242
-rw-r--r--ext/json/json_scanner.re345
-rw-r--r--ext/json/php_json_parser.h42
-rw-r--r--ext/json/php_json_scanner.h47
-rw-r--r--ext/json/utf8_decode.c179
-rw-r--r--ext/json/utf8_decode.h18
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);