]> granicus.if.org Git - php/commitdiff
Add method hooking support to json parser
authorJakub Zelenka <bukka@php.net>
Sun, 28 Feb 2016 17:45:53 +0000 (17:45 +0000)
committerJakub Zelenka <bukka@php.net>
Sun, 10 Apr 2016 14:35:41 +0000 (15:35 +0100)
This commit is just a slight modification (renaming and some small
changes) of the patch that has been provided by Andrey Hristov.
It adds support for hooking of the json parser operations and
allows re-using of modified JSON parsing outside of json ext.

ext/json/json_parser.tab.c
ext/json/json_parser.y
ext/json/php_json_parser.h

index b01d031f144c61eb33b54347be12bc149d441136..7ad54e3b77817bb9e71bafd15399461d0bc52358 100644 (file)
@@ -201,20 +201,9 @@ int php_json_yyparse (php_json_parser *parser);
 /* Unqualified %code blocks.  */
 
 
-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_init(php_json_parser *parser, zval *object);
-int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
-void php_json_parser_array_init(zval *object);
-void php_json_parser_array_append(zval *array, zval *zvalue);
+static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
+static void php_json_yyerror(php_json_parser *parser, char const *msg);
 
-#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
 
 
 
@@ -514,10 +503,10 @@ static const yytype_uint8 yytranslate[] =
   /* YYRLINE[YYN] -- Source line where rule number YYN was defined.  */
 static const yytype_uint8 yyrline[] =
 {
-       0,    92,    92,    98,   105,   105,   113,   114,   123,   126,
-     130,   136,   142,   149,   154,   161,   161,   169,   170,   179,
-     182,   186,   191,   196,   203,   204,   208,   209,   210,   211,
-     212,   213,   214,   215,   216,   217,   221
+       0,    81,    81,    87,    94,    94,   104,   105,   114,   117,
+     121,   127,   133,   140,   145,   152,   152,   162,   163,   172,
+     175,   179,   184,   189,   196,   197,   201,   202,   203,   204,
+     205,   206,   207,   208,   209,   210,   214
 };
 #endif
 
@@ -1465,15 +1454,17 @@ yyreduce:
 
   case 4:
 
-    { PHP_JSON_DEPTH_INC; }
+    { if (FAILURE == parser->methods->object_start(parser)) YYERROR; }
 
     break;
 
   case 5:
 
     {
-                               PHP_JSON_DEPTH_DEC;
                                (yyval.value) = (yyvsp[-1].value);
+                               if (FAILURE == parser->methods->object_end(parser, &(yyval.value))) {
+                                       YYERROR;
+                               }
                        }
 
     break;
@@ -1490,7 +1481,7 @@ yyreduce:
   case 8:
 
     {
-                               php_json_parser_object_init(parser, &(yyval.value));
+                               parser->methods->object_create(parser, &(yyval.value));
                        }
 
     break;
@@ -1498,8 +1489,8 @@ yyreduce:
   case 10:
 
     {
-                               php_json_parser_object_init(parser, &(yyval.value));
-                               if (php_json_parser_object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE)
+                               parser->methods->object_create(parser, &(yyval.value));
+                               if (parser->methods->object_update(parser, &(yyval.value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE)
                                        YYERROR;
                        }
 
@@ -1508,7 +1499,7 @@ yyreduce:
   case 11:
 
     {
-                               if (php_json_parser_object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE)
+                               if (parser->methods->object_update(parser, &(yyvsp[-2].value), (yyvsp[0].pair).key, &(yyvsp[0].pair).val) == FAILURE)
                                        YYERROR;
                                ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value));
                        }
@@ -1542,15 +1533,17 @@ yyreduce:
 
   case 15:
 
-    { PHP_JSON_DEPTH_INC; }
+    { if (FAILURE == parser->methods->array_start(parser)) YYERROR; }
 
     break;
 
   case 16:
 
     {
-                               PHP_JSON_DEPTH_DEC;
                                ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-1].value));
+                               if (FAILURE == parser->methods->array_end(parser, &(yyval.value))) {
+                                       YYERROR;
+                               }
                        }
 
     break;
@@ -1567,7 +1560,7 @@ yyreduce:
   case 19:
 
     {
-                               php_json_parser_array_init(&(yyval.value));
+                               parser->methods->array_create(parser, &(yyval.value));
                        }
 
     break;
@@ -1575,8 +1568,8 @@ yyreduce:
   case 21:
 
     {
-                               php_json_parser_array_init(&(yyval.value));
-                               php_json_parser_array_append(&(yyval.value), &(yyvsp[0].value));
+                               parser->methods->array_create(parser, &(yyval.value));
+                               parser->methods->array_append(parser, &(yyval.value), &(yyvsp[0].value));
                        }
 
     break;
@@ -1584,7 +1577,7 @@ yyreduce:
   case 22:
 
     {
-                               php_json_parser_array_append(&(yyvsp[-2].value), &(yyvsp[0].value));
+                               parser->methods->array_append(parser, &(yyvsp[-2].value), &(yyvsp[0].value));
                                ZVAL_COPY_VALUE(&(yyval.value), &(yyvsp[-2].value));
                        }
 
@@ -1839,30 +1832,37 @@ yyreturn:
 
  /* Functions */
 
-void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth)
+static int php_json_parser_array_create(php_json_parser *parser, zval *array)
 {
-       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;
+       return array_init(array);
 }
 
-php_json_error_code php_json_parser_error_code(php_json_parser *parser)
+static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue)
 {
-       return parser->scanner.errcode;
+       zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
+       return SUCCESS;
 }
 
-void php_json_parser_object_init(php_json_parser *parser, zval *object)
+static int php_json_parser_array_start(php_json_parser *parser)
+{
+       return parser->methods->depth_increase(parser);
+}
+
+static int php_json_parser_array_end(php_json_parser *parser, zval *object)
+{
+       return parser->methods->depth_decrease(parser);
+}
+
+static int php_json_parser_object_create(php_json_parser *parser, zval *object)
 {
        if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
-               array_init(object);
+               return array_init(object);
        } else {
-               object_init(object);
+               return object_init(object);
        }
 }
 
-int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
+static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
 {
        /* if JSON_OBJECT_AS_ARRAY is set */
        if (Z_TYPE_P(object) == IS_ARRAY) {
@@ -1891,26 +1891,94 @@ int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_st
        return SUCCESS;
 }
 
-void php_json_parser_array_init(zval *array)
+static int php_json_parser_object_start(php_json_parser *parser)
 {
-       array_init(array);
+       return parser->methods->depth_increase(parser);
 }
 
-void php_json_parser_array_append(zval *array, zval *zvalue)
+static int php_json_parser_object_end(php_json_parser *parser, zval *object)
 {
-       zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
+       return parser->methods->depth_decrease(parser);
 }
-       
-int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
+
+static int php_json_parser_depth_increase(php_json_parser *parser)
+{
+       if (parser->max_depth && parser->depth >= parser->max_depth) {
+               parser->scanner.errcode = PHP_JSON_ERROR_DEPTH;
+               return FAILURE;
+       }
+       ++parser->depth;
+       return SUCCESS;
+}
+
+static int php_json_parser_depth_decrease(php_json_parser *parser)
+{
+       --parser->depth;
+       return SUCCESS;
+}
+
+static 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)
+static void php_json_yyerror(php_json_parser *parser, char const *msg)
 {
        if (!parser->scanner.errcode) {
                parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
        }
 }
+
+php_json_error_code php_json_parser_error_code(const php_json_parser *parser)
+{
+       return parser->scanner.errcode;
+}
+
+static const php_json_parser_methods default_parser_methods =
+{
+       php_json_parser_array_create,
+       php_json_parser_array_append,
+       php_json_parser_array_start,
+       php_json_parser_array_end,
+       php_json_parser_object_create,
+       php_json_parser_object_update,
+       php_json_parser_object_start,
+       php_json_parser_object_end,
+       php_json_parser_depth_increase,
+       php_json_parser_depth_decrease
+};
+
+void php_json_parser_init_ex(php_json_parser *parser,
+               zval *return_value,
+               char *str,
+               size_t str_len,
+               int options,
+               int max_depth,
+               const php_json_parser_methods *parser_methods)
+{
+       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;
+       parser->methods = parser_methods;
+}
+
+void php_json_parser_init(php_json_parser *parser,
+               zval *return_value,
+               char *str,
+               size_t str_len,
+               int options,
+               int max_depth)
+{
+       php_json_parser_init_ex(
+                       parser,
+                       return_value,
+                       str,
+                       str_len,
+                       options,
+                       max_depth,
+                       &default_parser_methods);
+}
index 2f37641c0c5ab0026627c1d808b3faa19cdcb1fe..f359c608d2ee9a74802acd4f9646beb657b94e6d 100644 (file)
@@ -70,20 +70,9 @@ int json_yydebug = 1;
 %destructor { zend_string_release($$.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_init(php_json_parser *parser, zval *object);
-int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
-void php_json_parser_array_init(zval *object);
-void php_json_parser_array_append(zval *array, 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
+static int php_json_yylex(union YYSTYPE *value, php_json_parser *parser);
+static void php_json_yyerror(php_json_parser *parser, char const *msg);
+
 }
 
 %% /* Rules */
@@ -102,10 +91,12 @@ start:
 ;
 
 object:
-               '{' { PHP_JSON_DEPTH_INC; } members object_end
+               '{' { if (FAILURE == parser->methods->object_start(parser)) YYERROR; } members object_end
                        {
-                               PHP_JSON_DEPTH_DEC;
                                $$ = $3;
+                               if (FAILURE == parser->methods->object_end(parser, &$$)) {
+                                       YYERROR;
+                               }
                        }
 ;
 
@@ -121,7 +112,7 @@ object_end:
 members:
                /* empty */
                        {
-                               php_json_parser_object_init(parser, &$$);
+                               parser->methods->object_create(parser, &$$);
                        }
        |       member
 ;
@@ -129,13 +120,13 @@ members:
 member:
                pair
                        {
-                               php_json_parser_object_init(parser, &$$);
-                               if (php_json_parser_object_update(parser, &$$, $1.key, &$1.val) == FAILURE)
+                               parser->methods->object_create(parser, &$$);
+                               if (parser->methods->object_update(parser, &$$, $1.key, &$1.val) == FAILURE)
                                        YYERROR;
                        }
        |       member ',' pair
                        {
-                               if (php_json_parser_object_update(parser, &$1, $3.key, &$3.val) == FAILURE)
+                               if (parser->methods->object_update(parser, &$1, $3.key, &$3.val) == FAILURE)
                                        YYERROR;
                                ZVAL_COPY_VALUE(&$$, &$1);
                        }
@@ -158,10 +149,12 @@ pair:
 ;
 
 array:
-               '[' { PHP_JSON_DEPTH_INC; } elements array_end
+               '[' { if (FAILURE == parser->methods->array_start(parser)) YYERROR; } elements array_end
                        {
-                               PHP_JSON_DEPTH_DEC;
                                ZVAL_COPY_VALUE(&$$, &$3);
+                               if (FAILURE == parser->methods->array_end(parser, &$$)) {
+                                       YYERROR;
+                               }
                        }
 ;
 
@@ -177,7 +170,7 @@ array_end:
 elements:
                /* empty */
                        {
-                               php_json_parser_array_init(&$$);
+                               parser->methods->array_create(parser, &$$);
                        }
        |       element
 ;
@@ -185,12 +178,12 @@ elements:
 element:
                value
                        {
-                               php_json_parser_array_init(&$$);
-                               php_json_parser_array_append(&$$, &$1);
+                               parser->methods->array_create(parser, &$$);
+                               parser->methods->array_append(parser, &$$, &$1);
                        }
        |       element ',' value
                        {
-                               php_json_parser_array_append(&$1, &$3);
+                               parser->methods->array_append(parser, &$1, &$3);
                                ZVAL_COPY_VALUE(&$$, &$1);
                        }
        |       element errlex
@@ -227,30 +220,37 @@ errlex:
        
 %% /* Functions */
 
-void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth)
+static int php_json_parser_array_create(php_json_parser *parser, zval *array)
 {
-       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;
+       return array_init(array);
 }
 
-php_json_error_code php_json_parser_error_code(php_json_parser *parser)
+static int php_json_parser_array_append(php_json_parser *parser, zval *array, zval *zvalue)
 {
-       return parser->scanner.errcode;
+       zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
+       return SUCCESS;
 }
 
-void php_json_parser_object_init(php_json_parser *parser, zval *object)
+static int php_json_parser_array_start(php_json_parser *parser)
+{
+       return parser->methods->depth_increase(parser);
+}
+
+static int php_json_parser_array_end(php_json_parser *parser, zval *object)
+{
+       return parser->methods->depth_decrease(parser);
+}
+
+static int php_json_parser_object_create(php_json_parser *parser, zval *object)
 {
        if (parser->scanner.options & PHP_JSON_OBJECT_AS_ARRAY) {
-               array_init(object);
+               return array_init(object);
        } else {
-               object_init(object);
+               return object_init(object);
        }
 }
 
-int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
+static int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_string *key, zval *zvalue)
 {
        /* if JSON_OBJECT_AS_ARRAY is set */
        if (Z_TYPE_P(object) == IS_ARRAY) {
@@ -279,26 +279,94 @@ int php_json_parser_object_update(php_json_parser *parser, zval *object, zend_st
        return SUCCESS;
 }
 
-void php_json_parser_array_init(zval *array)
+static int php_json_parser_object_start(php_json_parser *parser)
 {
-       array_init(array);
+       return parser->methods->depth_increase(parser);
 }
 
-void php_json_parser_array_append(zval *array, zval *zvalue)
+static int php_json_parser_object_end(php_json_parser *parser, zval *object)
 {
-       zend_hash_next_index_insert(Z_ARRVAL_P(array), zvalue);
+       return parser->methods->depth_decrease(parser);
 }
-       
-int php_json_yylex(union YYSTYPE *value, php_json_parser *parser)
+
+static int php_json_parser_depth_increase(php_json_parser *parser)
+{
+       if (parser->max_depth && parser->depth >= parser->max_depth) {
+               parser->scanner.errcode = PHP_JSON_ERROR_DEPTH;
+               return FAILURE;
+       }
+       ++parser->depth;
+       return SUCCESS;
+}
+
+static int php_json_parser_depth_decrease(php_json_parser *parser)
+{
+       --parser->depth;
+       return SUCCESS;
+}
+
+static 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)
+static void php_json_yyerror(php_json_parser *parser, char const *msg)
 {
        if (!parser->scanner.errcode) {
                parser->scanner.errcode = PHP_JSON_ERROR_SYNTAX;
        }
 }
+
+php_json_error_code php_json_parser_error_code(const php_json_parser *parser)
+{
+       return parser->scanner.errcode;
+}
+
+static const php_json_parser_methods default_parser_methods =
+{
+       php_json_parser_array_create,
+       php_json_parser_array_append,
+       php_json_parser_array_start,
+       php_json_parser_array_end,
+       php_json_parser_object_create,
+       php_json_parser_object_update,
+       php_json_parser_object_start,
+       php_json_parser_object_end,
+       php_json_parser_depth_increase,
+       php_json_parser_depth_decrease
+};
+
+void php_json_parser_init_ex(php_json_parser *parser,
+               zval *return_value,
+               char *str,
+               size_t str_len,
+               int options,
+               int max_depth,
+               const php_json_parser_methods *parser_methods)
+{
+       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;
+       parser->methods = parser_methods;
+}
+
+void php_json_parser_init(php_json_parser *parser,
+               zval *return_value,
+               char *str,
+               size_t str_len,
+               int options,
+               int max_depth)
+{
+       php_json_parser_init_ex(
+                       parser,
+                       return_value,
+                       str,
+                       str_len,
+                       options,
+                       max_depth,
+                       &default_parser_methods);
+}
index 6964ef8e8e066044a26812a4b6ad50d9e9c41b1d..9a3f206667662433d80f985ae3d611be6fa0e59b 100644 (file)
 #include "php.h"
 #include "php_json_scanner.h"
 
-typedef struct _php_json_parser {
+typedef struct _php_json_parser php_json_parser;
+
+typedef int (*php_json_parser_func_array_create_t)(
+               php_json_parser *parser, zval *array);
+typedef int (*php_json_parser_func_array_append_t)(
+               php_json_parser *parser, zval *array, zval *zvalue);
+typedef int (*php_json_parser_func_array_start_t)(
+               php_json_parser *parser);
+typedef int (*php_json_parser_func_array_end_t)(
+               php_json_parser *parser, zval *object);
+typedef int (*php_json_parser_func_object_create_t)(
+               php_json_parser *parser, zval *object);
+typedef int (*php_json_parser_func_object_update_t)(
+               php_json_parser *parser, zval *object, zend_string *key, zval *zvalue);
+typedef int (*php_json_parser_func_object_start_t)(
+               php_json_parser *parser);
+typedef int (*php_json_parser_func_object_end_t)(
+               php_json_parser *parser, zval *object);
+typedef int (*php_json_parser_func_depth_increase_t)(
+               php_json_parser *parser);
+typedef int (*php_json_parser_func_depth_decrease_t)(
+               php_json_parser *parser);
+
+typedef struct _php_json_parser_methods {
+       php_json_parser_func_array_create_t array_create;
+       php_json_parser_func_array_append_t array_append;
+       php_json_parser_func_array_start_t array_start;
+       php_json_parser_func_array_end_t array_end;
+       php_json_parser_func_object_create_t object_create;
+       php_json_parser_func_object_update_t object_update;
+       php_json_parser_func_object_start_t object_start;
+       php_json_parser_func_object_end_t object_end;
+       php_json_parser_func_depth_increase_t depth_increase;
+       php_json_parser_func_depth_decrease_t depth_decrease;
+} php_json_parser_methods;
+
+struct _php_json_parser {
        php_json_scanner scanner;
        zval *return_value;
-       int depth;
+       unsigned int depth;
        int max_depth;
-} php_json_parser;
+       const php_json_parser_methods *methods;
+};
+
+PHP_JSON_API void php_json_parser_init_ex(
+               php_json_parser *parser,
+               zval *return_value,
+               char *str,
+               size_t str_len,
+               int options,
+               int max_depth,
+               const php_json_parser_methods *methods);
 
-void php_json_parser_init(php_json_parser *parser, zval *return_value, char *str, size_t str_len, int options, int max_depth);
+PHP_JSON_API void php_json_parser_init(
+               php_json_parser *parser,
+               zval *return_value,
+               char *str,
+               size_t str_len,
+               int options,
+               int max_depth);
 
-php_json_error_code php_json_parser_error_code(php_json_parser *parser);
+PHP_JSON_API php_json_error_code php_json_parser_error_code(const php_json_parser *parser);
 
-int php_json_yyparse(php_json_parser *parser);
+PHP_JSON_API int php_json_yyparse(php_json_parser *parser);
 
 #endif /* PHP_JSON_PARSER_H */