mirror of
https://github.com/php/php-src.git
synced 2024-11-23 18:04:36 +08:00
Initial import of jsond
This commit is contained in:
parent
12cf41ca35
commit
d07bf91328
@ -1,2 +1,2 @@
|
||||
JSON
|
||||
Omar Kilani, Scott MacVicar
|
||||
Jakub Zelenka, Omar Kilani, Scott MacVicar
|
||||
|
5
ext/json/Makefile.frag
Normal file
5
ext/json/Makefile.frag
Normal file
@ -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 $@
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
242
ext/json/json_parser.y
Normal file
242
ext/json/json_parser.y
Normal file
@ -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;
|
||||
}
|
||||
}
|
345
ext/json/json_scanner.re
Normal file
345
ext/json/json_scanner.re
Normal file
@ -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;
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
42
ext/json/php_json_parser.h
Normal file
42
ext/json/php_json_parser.h
Normal file
@ -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 */
|
||||
|
47
ext/json/php_json_scanner.h
Normal file
47
ext/json/php_json_scanner.h
Normal file
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
Loading…
Reference in New Issue
Block a user