From 260f7f41e764e5c81a2e97e8826430f6e3ae6fa7 Mon Sep 17 00:00:00 2001 From: Julien Pauli Date: Mon, 2 Nov 2015 18:03:05 +0100 Subject: [PATCH 1/2] Many PHP5 improvements --- jsonreader.c | 262 +++++++++++++---------------------------------- php_jsonreader.h | 72 ++++++++++--- tests/011.phpt | 2 +- tests/012.phpt | 2 +- 4 files changed, 134 insertions(+), 204 deletions(-) diff --git a/jsonreader.c b/jsonreader.c index 77b402b..0eafb53 100644 --- a/jsonreader.c +++ b/jsonreader.c @@ -33,45 +33,9 @@ ZEND_DECLARE_MODULE_GLOBALS(jsonreader) static zend_object_handlers jsonreader_obj_handlers; -static zend_class_entry *jsonreader_ce; +zend_class_entry *jsonreader_ce; static zend_class_entry *jsonreader_exception_ce; - -const HashTable jsonreader_prop_handlers; - -typedef struct _jsonreader_object { - zend_object std; - php_stream *stream; - vktor_parser *parser; - zend_bool close_stream; - long max_depth; - long read_buffer; - int errmode; -} jsonreader_object; - -#define JSONREADER_REG_CLASS_CONST_L(name, value) \ - zend_declare_class_constant_long(jsonreader_ce, name, sizeof(name) - 1, \ - (long) value TSRMLS_CC) - -#define JSONREADER_VALUE_TOKEN VKTOR_T_NULL | \ - VKTOR_T_TRUE | \ - VKTOR_T_FALSE | \ - VKTOR_T_INT | \ - VKTOR_T_FLOAT | \ - VKTOR_T_STRING - -/* {{{ attribute keys and possible values */ -enum { - ATTR_MAX_DEPTH = 1, - ATTR_READ_BUFF, - ATTR_ERRMODE, - - ERRMODE_PHPERR, - ERRMODE_EXCEPT, - ERRMODE_INTERN -}; -/* }}} */ - -/* }}} */ +static HashTable jsonreader_prop_handlers; /* {{{ Memory management functions wrapping emalloc etc. */ @@ -108,18 +72,15 @@ static void jsonreader_handle_error(vktor_error *err, jsonreader_object *obj TSR { switch(obj->errmode) { case ERRMODE_PHPERR: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "parser error [#%d]: %s", - err->code, err->message); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "parser error [#%d]: %s", err->code, err->message); break; case ERRMODE_EXCEPT: - zend_throw_exception_ex(jsonreader_exception_ce, err->code TSRMLS_CC, - err->message); + zend_throw_exception_ex(jsonreader_exception_ce, err->code TSRMLS_CC, err->message); break; default: // For now emit a PHP WARNING - php_error_docref(NULL TSRMLS_CC, E_WARNING, "parser error [#%d]: %s", - err->code, err->message); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "parser error [#%d]: %s", err->code, err->message); break; } @@ -127,16 +88,6 @@ static void jsonreader_handle_error(vktor_error *err, jsonreader_object *obj TSR } /* }}} */ -/* {{{ Property access related functions and type definitions */ - -typedef int (*jsonreader_read_t) (jsonreader_object *obj, zval **retval TSRMLS_DC); -typedef int (*jsonreader_write_t) (jsonreader_object *obj, zval *newval TSRMLS_DC); - -typedef struct _jsonreader_prop_handler { - jsonreader_read_t read_func; - jsonreader_write_t write_func; -} jsonreader_prop_handler; - /* {{{ jsonreader_read_na Called when a user tries to read a write-only property of a JSONReader object */ static int jsonreader_read_na(jsonreader_object *obj, zval **retval TSRMLS_DC) @@ -162,57 +113,45 @@ static void jsonreader_register_prop_handler(char *name, jsonreader_read_t read_ { jsonreader_prop_handler jph; - jph.read_func = read_func ? read_func : jsonreader_read_na; + jph.read_func = read_func ? read_func : jsonreader_read_na; jph.write_func = write_func ? write_func : jsonreader_write_na; - zend_hash_add((HashTable *) &jsonreader_prop_handlers, name, strlen(name) + 1, &jph, - sizeof(jsonreader_prop_handler), NULL); + zend_hash_add(&jsonreader_prop_handlers, name, strlen(name) + 1, &jph, sizeof(jsonreader_prop_handler), NULL); } /* }}} */ /* {{{ jsonreader_read_property Property read handler */ -zval* jsonreader_read_property(zval *object, zval *member, int type TSRMLS_DC) +#if PHP_VERSION_ID < 50400 +static zval* jsonreader_read_property(zval *object, zval *member, int type TSRMLS_DC) +#else +static zval* jsonreader_read_property(zval *object, zval *member, int type, const struct _zend_literal *key TSRMLS_DC) +#endif { jsonreader_object *intern; - zval tmp_member; zval *retval; jsonreader_prop_handler *jph; - zend_object_handlers *std_hnd; - int ret; if (Z_TYPE_P(member) != IS_STRING) { - tmp_member = *member; - zval_copy_ctor(&tmp_member); - convert_to_string(&tmp_member); - member = &tmp_member; + goto std_h; } - ret = FAILURE; intern = (jsonreader_object *) zend_objects_get_address(object TSRMLS_CC); - ret = zend_hash_find(&jsonreader_prop_handlers, Z_STRVAL_P(member), - Z_STRLEN_P(member) + 1, (void **) &jph); - - if (ret == SUCCESS) { - ret = jph->read_func(intern, &retval TSRMLS_CC); - if (ret == SUCCESS) { + if (zend_hash_find(&jsonreader_prop_handlers, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &jph) == SUCCESS) { + if (jph->read_func(intern, &retval TSRMLS_CC) == SUCCESS) { Z_SET_REFCOUNT_P(retval, 0); + Z_UNSET_ISREF_P(retval); } else { retval = EG(uninitialized_zval_ptr); } } else { - std_hnd = zend_get_std_object_handlers(); -#if PHP_VERSION_ID < 50399 - retval = std_hnd->read_property(object, member, type TSRMLS_CC); +std_h: +#if PHP_VERSION_ID < 50400 + retval = std_object_handlers.read_property(object, member, type TSRMLS_CC); #else - retval = std_hnd->read_property(object, member, type TSRMLS_CC, NULL); + retval = std_object_handlers.read_property(object, member, type, key TSRMLS_CC); #endif - - } - - if (member == &tmp_member) { - zval_dtor(member); } return retval; @@ -220,41 +159,32 @@ zval* jsonreader_read_property(zval *object, zval *member, int type TSRMLS_DC) /* }}} */ /* {{{ jsonreader_write_property */ -void jsonreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +#if PHP_VERSION_ID < 50400 +static void jsonreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +#else +static void jsonreader_write_property(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC) +#endif { jsonreader_object *intern; - zval tmp_member; jsonreader_prop_handler *jph; - zend_object_handlers *std_hnd; - int ret; if (Z_TYPE_P(member) != IS_STRING) { - tmp_member = *member; - zval_copy_ctor(&tmp_member); - convert_to_string(&tmp_member); - member = &tmp_member; + goto std_h; } - ret = FAILURE; intern = (jsonreader_object *) zend_objects_get_address(object TSRMLS_CC); - ret = zend_hash_find(&jsonreader_prop_handlers, Z_STRVAL_P(member), - Z_STRLEN_P(member) + 1, (void **) &jph); - - if (ret == SUCCESS) { + if (zend_hash_find(&jsonreader_prop_handlers, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &jph) == SUCCESS) { jph->write_func(intern, value TSRMLS_CC); } else { - std_hnd = zend_get_std_object_handlers(); -#if PHP_VERSION_ID < 50399 - std_hnd->write_property(object, member, value TSRMLS_CC); +std_h: +#if PHP_VERSION_ID < 50400 + std_object_handlers.write_property(object, member, value TSRMLS_CC); #else - std_hnd->write_property(object, member, value TSRMLS_CC, NULL); + std_object_handlers.write_property(object, member, value, key TSRMLS_CC); #endif } - if (member == &tmp_member) { - zval_dtor(member); - } } /* }}} */ @@ -268,7 +198,6 @@ static int jsonreader_get_token_type(jsonreader_object *obj, zval **retval TSRML if (! obj->parser) { ZVAL_NULL(*retval); - } else { token = vktor_get_token_type(obj->parser); if (token == VKTOR_T_NONE) { @@ -293,7 +222,6 @@ static int jsonreader_get_token_value(jsonreader_object *obj, zval **retval TSRM if (! obj->parser) { ZVAL_NULL(*retval); - } else { t_type = vktor_get_token_type(obj->parser); switch(t_type) { @@ -346,8 +274,7 @@ static int jsonreader_get_token_value(jsonreader_object *obj, zval **retval TSRM break; default: /* should not happen */ - php_error_docref(NULL TSRMLS_CC, E_ERROR, - "internal error: unkown token type %d", t_type); + php_error_docref(NULL TSRMLS_CC, E_ERROR, "internal error: unkown token type %d", t_type); return FAILURE; break; } @@ -367,7 +294,6 @@ static int jsonreader_get_current_struct(jsonreader_object *obj, zval **retval T if (! obj->parser) { ZVAL_NULL(*retval); - } else { cs = vktor_get_current_struct(obj->parser); if (cs == VKTOR_STRUCT_NONE) { @@ -391,7 +317,6 @@ static int jsonreader_get_current_depth(jsonreader_object *obj, zval **retval TS if (! obj->parser) { ZVAL_NULL(*retval); - } else { depth = vktor_get_depth(obj->parser); ZVAL_LONG(*retval, depth); @@ -401,8 +326,6 @@ static int jsonreader_get_current_depth(jsonreader_object *obj, zval **retval TS } /* }}} */ -/* }}} */ - /* {{{ jsonreader_object_free_storage C-level object destructor for JSONReader objects */ static void jsonreader_object_free_storage(void *object TSRMLS_DC) @@ -415,7 +338,7 @@ static void jsonreader_object_free_storage(void *object TSRMLS_DC) vktor_parser_free(intern->parser); } - if (intern->stream && intern->close_stream) { + if (intern->stream && !intern->internal_stream) { php_stream_close(intern->stream); } @@ -432,17 +355,16 @@ static zend_object_value jsonreader_object_new(zend_class_entry *ce TSRMLS_DC) jsonreader_object *intern; intern = ecalloc(1, sizeof(jsonreader_object)); - intern->max_depth = JSONREADER_G(max_depth); + intern->max_depth = JSONREADER_G(max_depth); intern->read_buffer = JSONREADER_G(read_buffer); - intern->errmode = ERRMODE_PHPERR; + intern->errmode = ERRMODE_PHPERR; zend_object_std_init(&(intern->std), ce TSRMLS_CC); - + #if PHP_VERSION_ID < 50399 - zend_hash_copy(intern->std.properties, &ce->default_properties, - (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); + zend_hash_copy(intern->std.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); #else - object_properties_init(&(intern->std), ce); + object_properties_init(&(intern->std), ce); #endif retval.handle = zend_objects_store_put(intern, @@ -456,23 +378,6 @@ static zend_object_value jsonreader_object_new(zend_class_entry *ce TSRMLS_DC) } /* }}} */ -/* {{{ jsonreader_init - Initialize or reset an internal jsonreader object struct. Will close & free - any stream opened by the reader, and initialize the associated vktor parser - (and free the old parser, if exists) */ -static void jsonreader_init(jsonreader_object *obj TSRMLS_DC) -{ - if (obj->parser) { - vktor_parser_free(obj->parser); - } - obj->parser = vktor_parser_init(obj->max_depth); - - if (obj->stream) { - php_stream_close(obj->stream); - } -} -/* }}} */ - /* {{{ jsonreader_read_more_data Read more data from the stream and pass it to the parser */ static int jsonreader_read_more_data(jsonreader_object *obj TSRMLS_DC) @@ -482,16 +387,18 @@ static int jsonreader_read_more_data(jsonreader_object *obj TSRMLS_DC) vktor_status status; vktor_error *err; - buffer = emalloc(sizeof(char) * obj->read_buffer); + buffer = ecalloc(1, obj->read_buffer); read = php_stream_read(obj->stream, buffer, obj->read_buffer); if (read <= 0) { /* done reading or error */ php_error_docref(NULL TSRMLS_CC, E_WARNING, "JSON stream ended while expecting more data"); + efree(buffer); return FAILURE; } status = vktor_feed(obj->parser, buffer, read, 1, &err); + if (status == VKTOR_ERROR) { jsonreader_handle_error(err, obj TSRMLS_CC); return FAILURE; @@ -523,8 +430,7 @@ static int jsonreader_read(jsonreader_object *obj TSRMLS_DC) case VKTOR_ERROR: jsonreader_handle_error(err, obj TSRMLS_CC); - retval = FAILURE; - break; + return FAILURE; case VKTOR_MORE_DATA: if (jsonreader_read_more_data(obj TSRMLS_CC) == FAILURE) { @@ -578,8 +484,7 @@ static void jsonreader_set_attribute(jsonreader_object *obj, ulong attr_key, zva break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "invalid error handler attribute value: %ld", lval); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid error handler attribute value: %ld", lval); break; } break; @@ -599,19 +504,21 @@ PHP_METHOD(jsonreader, __construct) } /* got attributes - set them */ - if (options != NULL) { + if (options) { jsonreader_object *intern; zval **attr_value; char *str_key; ulong long_key; + HashPosition pos; intern = (jsonreader_object *) zend_object_store_get_object(object TSRMLS_CC); - zend_hash_internal_pointer_reset(Z_ARRVAL_P(options)); - while (zend_hash_get_current_data(Z_ARRVAL_P(options), (void **) &attr_value) == SUCCESS && - zend_hash_get_current_key(Z_ARRVAL_P(options), &str_key, &long_key, 0) == HASH_KEY_IS_LONG) { - jsonreader_set_attribute(intern, long_key, *attr_value TSRMLS_CC); - zend_hash_move_forward(Z_ARRVAL_P(options)); + for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(options), &pos); + (zend_hash_get_current_data_ex(Z_ARRVAL_P(options), (void **)&attr_value, &pos) == SUCCESS) && + (zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &str_key, NULL, &long_key, 0, &pos) == HASH_KEY_IS_LONG) && + (Z_TYPE_PP(attr_value) == IS_LONG); + zend_hash_move_forward_ex(Z_ARRVAL_P(options), &pos)) { + jsonreader_set_attribute(intern, long_key, *attr_value TSRMLS_CC); } } } @@ -626,7 +533,6 @@ PHP_METHOD(jsonreader, open) zval *object, *arg; jsonreader_object *intern; php_stream *tmp_stream; - int options = ENFORCE_SAFE_MODE | REPORT_ERRORS; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) { return; @@ -637,26 +543,24 @@ PHP_METHOD(jsonreader, open) switch(Z_TYPE_P(arg)) { case IS_STRING: - tmp_stream = php_stream_open_wrapper(Z_STRVAL_P(arg), "r", options, NULL); - intern->close_stream = 1; + tmp_stream = php_stream_open_wrapper(Z_STRVAL_P(arg), "r", REPORT_ERRORS, NULL); + if (tmp_stream) { + intern->stream = tmp_stream; + } break; case IS_RESOURCE: php_stream_from_zval(tmp_stream, &arg); - intern->close_stream = 0; + intern->internal_stream = tmp_stream->abstract; + intern->stream = tmp_stream; break; default: - php_error_docref(NULL TSRMLS_CC, E_ERROR, - "argument is expected to be a resource of type stream or a string, %s given", - zend_zval_type_name(arg)); + php_error_docref(NULL TSRMLS_CC, E_WARNING, "argument is expected to be a resource of type stream or a string, %s given", zend_zval_type_name(arg)); RETURN_FALSE; - break; - } - jsonreader_init(intern TSRMLS_CC); - intern->stream = tmp_stream; + intern->parser = vktor_parser_init(intern->max_depth); RETURN_TRUE; } @@ -673,9 +577,9 @@ PHP_METHOD(jsonreader, close) intern = (jsonreader_object *) zend_object_store_get_object(object TSRMLS_CC); /* Close stream, if open */ - if (intern->stream) { + if (intern->stream && !intern->stream->abstract) { php_stream_close(intern->stream); - intern->stream = NULL; + intern->stream = NULL; } /* Free parser, if created */ @@ -701,15 +605,11 @@ PHP_METHOD(jsonreader, read) object = getThis(); intern = (jsonreader_object *) zend_object_store_get_object(object TSRMLS_CC); - if (! intern->stream) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, - "trying to read but no stream was opened"); + if (!intern->stream || (intern->internal_stream && intern->stream->abstract != intern->internal_stream)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to read but no stream was opened or stream was closed"); RETURN_FALSE; } - /* TODO: replace assertion with an if(!) and init parser (?) */ - assert(intern->parser != NULL); - if (jsonreader_read(intern TSRMLS_CC) != SUCCESS) { RETVAL_FALSE; } @@ -738,7 +638,7 @@ static const zend_function_entry jsonreader_class_methods[] = { PHP_ME(jsonreader, open, arginfo_jsonreader_open, ZEND_ACC_PUBLIC) PHP_ME(jsonreader, close, arginfo_jsonreader_close, ZEND_ACC_PUBLIC) PHP_ME(jsonreader, read, arginfo_jsonreader_read, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} + {NULL, NULL, NULL, 0, 0} }; /* }}} */ @@ -748,16 +648,16 @@ ZEND_GET_MODULE(jsonreader) /* {{{ PHP_INI */ PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("jsonreader.max_depth", "64", PHP_INI_ALL, OnUpdateLong, max_depth, zend_jsonreader_globals, jsonreader_globals) - STD_PHP_INI_ENTRY("jsonreader.read_buffer", "4096", PHP_INI_ALL, OnUpdateLong, read_buffer, zend_jsonreader_globals, jsonreader_globals) + STD_PHP_INI_ENTRY("jsonreader.max_depth", XSTRINGIFY(JSONREADER_DEFAULT_MAX_DEPTH), PHP_INI_ALL, OnUpdateLongGEZero, max_depth, zend_jsonreader_globals, jsonreader_globals) + STD_PHP_INI_ENTRY("jsonreader.read_buffer", XSTRINGIFY(JSONREADER_DEFAULT_MAX_READ_BUFFER), PHP_INI_ALL, OnUpdateLongGEZero, read_buffer, zend_jsonreader_globals, jsonreader_globals) PHP_INI_END() /* }}} */ /* {{{ PHP_GINIT_FUNCTION */ PHP_GINIT_FUNCTION(jsonreader) { - jsonreader_globals->max_depth = 64; - jsonreader_globals->read_buffer = 4096; + jsonreader_globals->max_depth = JSONREADER_DEFAULT_MAX_DEPTH; + jsonreader_globals->read_buffer= JSONREADER_DEFAULT_MAX_READ_BUFFER; } /* }}} */ @@ -767,25 +667,17 @@ PHP_MINIT_FUNCTION(jsonreader) zend_class_entry ce; REGISTER_INI_ENTRIES(); + zend_hash_init(&jsonreader_prop_handlers, 8, NULL, NULL, 1); - /** - * Declare the JSONReader class - */ - - /* Set object handlers */ - zend_hash_init((HashTable *) &jsonreader_prop_handlers, 0, NULL, NULL, 1); - memcpy(&jsonreader_obj_handlers, zend_get_std_object_handlers(), - sizeof(zend_object_handlers)); - jsonreader_obj_handlers.read_property = jsonreader_read_property; + memcpy(&jsonreader_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + jsonreader_obj_handlers.read_property = jsonreader_read_property; jsonreader_obj_handlers.write_property = jsonreader_write_property; - /* Initalize the class entry */ INIT_CLASS_ENTRY(ce, "JSONReader", jsonreader_class_methods); ce.create_object = jsonreader_object_new; jsonreader_ce = zend_register_internal_class(&ce TSRMLS_CC); - /* Register class constants */ JSONREADER_REG_CLASS_CONST_L("ATTR_MAX_DEPTH", ATTR_MAX_DEPTH); JSONREADER_REG_CLASS_CONST_L("ATTR_READ_BUFF", ATTR_READ_BUFF); JSONREADER_REG_CLASS_CONST_L("ATTR_ERRMODE", ATTR_ERRMODE); @@ -811,22 +703,14 @@ PHP_MINIT_FUNCTION(jsonreader) JSONREADER_REG_CLASS_CONST_L("ARRAY", VKTOR_STRUCT_ARRAY); JSONREADER_REG_CLASS_CONST_L("OBJECT", VKTOR_STRUCT_OBJECT); - /* Register property handlers */ jsonreader_register_prop_handler("tokenType", jsonreader_get_token_type, NULL TSRMLS_CC); jsonreader_register_prop_handler("value", jsonreader_get_token_value, NULL TSRMLS_CC); jsonreader_register_prop_handler("currentStruct", jsonreader_get_current_struct, NULL TSRMLS_CC); jsonreader_register_prop_handler("currentDepth", jsonreader_get_current_depth, NULL TSRMLS_CC); - /** - * Declare the JSONReaderException class - */ INIT_CLASS_ENTRY(ce, "JSONReaderException", NULL); - jsonreader_exception_ce = zend_register_internal_class_ex(&ce, - zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); + jsonreader_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); - /** - * Set libvktor to use PHP memory allocation functions - */ vktor_set_memory_handlers(jsr_malloc, jsr_realloc, jsr_free); return SUCCESS; @@ -837,7 +721,7 @@ PHP_MINIT_FUNCTION(jsonreader) PHP_MSHUTDOWN_FUNCTION(jsonreader) { UNREGISTER_INI_ENTRIES(); - zend_hash_destroy((HashTable *) &jsonreader_prop_handlers); + zend_hash_destroy(&jsonreader_prop_handlers); return SUCCESS; } /* }}} */ diff --git a/php_jsonreader.h b/php_jsonreader.h index e5705b4..aca26b7 100644 --- a/php_jsonreader.h +++ b/php_jsonreader.h @@ -21,6 +21,8 @@ #ifndef PHP_JSONREADER_H #define PHP_JSONREADER_H +#include "libvktor/vktor.h" + extern zend_module_entry jsonreader_module_entry; #define phpext_jsonreader_ptr &jsonreader_module_entry @@ -29,31 +31,75 @@ extern zend_module_entry jsonreader_module_entry; #elif defined(__GNUC__) && __GNUC__ >= 4 # define PHP_JSONREADER_API __attribute__ ((visibility("default"))) #else -# define PHP_JSONREADER_API +#define PHP_JSONREADER_API +zend_module_entry *get_module(void); #endif #ifdef ZTS #include "TSRM.h" #endif -PHP_MINIT_FUNCTION(jsonreader); -PHP_MSHUTDOWN_FUNCTION(jsonreader); -PHP_MINFO_FUNCTION(jsonreader); +#define JSONREADER_DEFAULT_MAX_DEPTH 64 +#define JSONREADER_DEFAULT_MAX_READ_BUFFER 4096 +#define STRINGIFY(x) #x +#define XSTRINGIFY(a) STRINGIFY(a) ZEND_BEGIN_MODULE_GLOBALS(jsonreader) long max_depth; long read_buffer; ZEND_END_MODULE_GLOBALS(jsonreader) -/* In every utility function you add that needs to use variables - in php_jsonreader_globals, call TSRMLS_FETCH(); after declaring other - variables used by that function, or better yet, pass in TSRMLS_CC - after the last function argument and declare your utility function - with TSRMLS_DC after the last declared argument. Always refer to - the globals in your function as JSONREADER_G(variable). You are - encouraged to rename these macros something shorter, see - examples in any other php module directory. -*/ +PHP_MINIT_FUNCTION(jsonreader); +PHP_GINIT_FUNCTION(jsonreader); +PHP_MSHUTDOWN_FUNCTION(jsonreader); +PHP_MINFO_FUNCTION(jsonreader); + +extern zend_class_entry *jsonreader_ce; + +PHP_METHOD(jsonreader, read); +PHP_METHOD(jsonreader, close); +PHP_METHOD(jsonreader, open); +PHP_METHOD(jsonreader, __construct); + +typedef struct _jsonreader_object { + zend_object std; + php_stream *stream; + void *internal_stream; + vktor_parser *parser; + long max_depth; + long read_buffer; + int errmode; +} jsonreader_object; + +#define JSONREADER_REG_CLASS_CONST_L(name, value) \ + zend_declare_class_constant_long(jsonreader_ce, name, sizeof(name) - 1, \ + (long) value TSRMLS_CC) + +#define JSONREADER_VALUE_TOKEN VKTOR_T_NULL | \ + VKTOR_T_TRUE | \ + VKTOR_T_FALSE | \ + VKTOR_T_INT | \ + VKTOR_T_FLOAT | \ + VKTOR_T_STRING + +/* {{{ attribute keys and possible values */ +enum { + ATTR_MAX_DEPTH = 1, + ATTR_READ_BUFF, + ATTR_ERRMODE, + + ERRMODE_PHPERR, + ERRMODE_EXCEPT, + ERRMODE_INTERN +}; + +typedef int (*jsonreader_read_t) (jsonreader_object *obj, zval **retval TSRMLS_DC); +typedef int (*jsonreader_write_t) (jsonreader_object *obj, zval *newval TSRMLS_DC); + +typedef struct _jsonreader_prop_handler { + jsonreader_read_t read_func; + jsonreader_write_t write_func; +} jsonreader_prop_handler; #ifdef ZTS #define JSONREADER_G(v) TSRMG(jsonreader_globals_id, zend_jsonreader_globals *, v) diff --git a/tests/011.phpt b/tests/011.phpt index 79a77ac..c14b1d9 100644 --- a/tests/011.phpt +++ b/tests/011.phpt @@ -16,5 +16,5 @@ $rdr->close(); --EXPECTF-- - %d -Warning: JSONReader::read(): parser error [#%d]: Unexpected character in input: '1' (0x31) in %s on line %d +Warning: JSONReader::read(): parser error [#%d]: [%s] Unexpected character in input: '1' (0x31) in %s on line %d diff --git a/tests/012.phpt b/tests/012.phpt index 569c9c6..f330a04 100644 --- a/tests/012.phpt +++ b/tests/012.phpt @@ -21,5 +21,5 @@ $rdr->close(); ?> --EXPECTF-- - %d -EX: %d Unexpected character in input: '1' (0x31) +EX: %d [%s] Unexpected character in input: '1' (0x31) From d638e72c3ecfea5576eecfe345db2212330174e3 Mon Sep 17 00:00:00 2001 From: Julien Pauli Date: Tue, 3 Nov 2015 16:59:58 +0100 Subject: [PATCH 2/2] PHP 7 port --- jsonreader.c | 264 +++++++++++++++++++---------------------------- php_jsonreader.h | 13 ++- 2 files changed, 117 insertions(+), 160 deletions(-) diff --git a/jsonreader.c b/jsonreader.c index 0eafb53..c827eb3 100644 --- a/jsonreader.c +++ b/jsonreader.c @@ -43,7 +43,7 @@ static HashTable jsonreader_prop_handlers; Wrapper for PHP's emalloc, passed to libvktor as malloc alternative */ static void *jsr_malloc(size_t size) { - return emalloc(size); + return ecalloc(1, size); } /* }}} */ @@ -68,19 +68,19 @@ static void jsr_free(void *ptr) /* {{{ jsonreader_handle_error Handle a parser error - for now generate an E_WARNING, in the future this might also do things like throw an exception or use an internal error handler */ -static void jsonreader_handle_error(vktor_error *err, jsonreader_object *obj TSRMLS_DC) +static void jsonreader_handle_error(vktor_error *err, jsonreader_object *obj) { switch(obj->errmode) { case ERRMODE_PHPERR: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "parser error [#%d]: %s", err->code, err->message); + php_error_docref(NULL, E_WARNING, "parser error [#%d]: %s", err->code, err->message); break; case ERRMODE_EXCEPT: - zend_throw_exception_ex(jsonreader_exception_ce, err->code TSRMLS_CC, err->message); + zend_throw_exception_ex(jsonreader_exception_ce, err->code, "%s", err->message); break; default: // For now emit a PHP WARNING - php_error_docref(NULL TSRMLS_CC, E_WARNING, "parser error [#%d]: %s", err->code, err->message); + php_error_docref(NULL, E_WARNING, "parser error [#%d]: %s", err->code, err->message); break; } @@ -90,99 +90,77 @@ static void jsonreader_handle_error(vktor_error *err, jsonreader_object *obj TSR /* {{{ jsonreader_read_na Called when a user tries to read a write-only property of a JSONReader object */ -static int jsonreader_read_na(jsonreader_object *obj, zval **retval TSRMLS_DC) +static int jsonreader_read_na(jsonreader_object *obj, zval *retval) { - *retval = NULL; - php_error_docref(NULL TSRMLS_CC, E_ERROR, "trying to read a write-only property"); + php_error_docref(NULL, E_ERROR, "trying to read a write-only property"); return FAILURE; } /* }}} */ /* {{{ jsonreader_write_na Called when a user tries to write to a read-only property of a JSONReader object */ -static int jsonreader_write_na(jsonreader_object *obj, zval *newval TSRMLS_DC) +static int jsonreader_write_na(jsonreader_object *obj, zval *newval) { - php_error_docref(NULL TSRMLS_CC, E_ERROR, "trying to modify a read-only property"); + php_error_docref(NULL, E_ERROR, "trying to modify a read-only property"); return FAILURE; } /* }}} */ /* {{{ jsonreader_register_prop_handler Register a read/write handler for a specific property of JSONReader objects */ -static void jsonreader_register_prop_handler(char *name, jsonreader_read_t read_func, jsonreader_write_t write_func TSRMLS_DC) +static void jsonreader_register_prop_handler(char *name, jsonreader_read_t read_func, jsonreader_write_t write_func) { jsonreader_prop_handler jph; jph.read_func = read_func ? read_func : jsonreader_read_na; jph.write_func = write_func ? write_func : jsonreader_write_na; - zend_hash_add(&jsonreader_prop_handlers, name, strlen(name) + 1, &jph, sizeof(jsonreader_prop_handler), NULL); + zend_hash_str_add_mem(&jsonreader_prop_handlers, name, strlen(name), &jph, sizeof(jsonreader_prop_handler)); } /* }}} */ /* {{{ jsonreader_read_property Property read handler */ -#if PHP_VERSION_ID < 50400 -static zval* jsonreader_read_property(zval *object, zval *member, int type TSRMLS_DC) -#else -static zval* jsonreader_read_property(zval *object, zval *member, int type, const struct _zend_literal *key TSRMLS_DC) -#endif +static zval *jsonreader_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) { - jsonreader_object *intern; - zval *retval; + zval retval; jsonreader_prop_handler *jph; + FETCH_JSON_OBJECT_FROM_ZV(object) if (Z_TYPE_P(member) != IS_STRING) { goto std_h; } - intern = (jsonreader_object *) zend_objects_get_address(object TSRMLS_CC); - - if (zend_hash_find(&jsonreader_prop_handlers, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &jph) == SUCCESS) { - if (jph->read_func(intern, &retval TSRMLS_CC) == SUCCESS) { - Z_SET_REFCOUNT_P(retval, 0); - Z_UNSET_ISREF_P(retval); + if ((jph = (jsonreader_prop_handler *)zend_hash_find_ptr(&jsonreader_prop_handlers, Z_STR_P(member))) != NULL) { + if (jph->read_func(intern, &retval) == SUCCESS) { + ZVAL_COPY_VALUE(rv, &retval); + return rv; } else { - retval = EG(uninitialized_zval_ptr); + return &EG(uninitialized_zval); } } else { std_h: -#if PHP_VERSION_ID < 50400 - retval = std_object_handlers.read_property(object, member, type TSRMLS_CC); -#else - retval = std_object_handlers.read_property(object, member, type, key TSRMLS_CC); -#endif + ZVAL_COPY_VALUE(rv, std_object_handlers.read_property(object, member, type, cache_slot, rv)); + return rv; } - - return retval; } /* }}} */ /* {{{ jsonreader_write_property */ -#if PHP_VERSION_ID < 50400 -static void jsonreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC) -#else -static void jsonreader_write_property(zval *object, zval *member, zval *value, const struct _zend_literal *key TSRMLS_DC) -#endif +static void jsonreader_write_property(zval *object, zval *member, zval *value, void **cache_slot) { - jsonreader_object *intern; + FETCH_JSON_OBJECT_FROM_ZV(object) jsonreader_prop_handler *jph; if (Z_TYPE_P(member) != IS_STRING) { goto std_h; } - intern = (jsonreader_object *) zend_objects_get_address(object TSRMLS_CC); - - if (zend_hash_find(&jsonreader_prop_handlers, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, (void **) &jph) == SUCCESS) { - jph->write_func(intern, value TSRMLS_CC); + if ((jph = (jsonreader_prop_handler *)zend_hash_find_ptr(&jsonreader_prop_handlers, Z_STR_P(member))) != NULL) { + jph->write_func(intern, value); } else { std_h: -#if PHP_VERSION_ID < 50400 - std_object_handlers.write_property(object, member, value TSRMLS_CC); -#else - std_object_handlers.write_property(object, member, value, key TSRMLS_CC); -#endif + std_object_handlers.write_property(object, member, value, cache_slot); } } @@ -190,20 +168,18 @@ static void jsonreader_write_property(zval *object, zval *member, zval *value, c /* {{{ jsonreader_get_token_type Get the type of the current token */ -static int jsonreader_get_token_type(jsonreader_object *obj, zval **retval TSRMLS_DC) +static int jsonreader_get_token_type(jsonreader_object *obj, zval *retval) { vktor_token token; - ALLOC_ZVAL(*retval); - if (! obj->parser) { - ZVAL_NULL(*retval); + ZVAL_NULL(retval); } else { token = vktor_get_token_type(obj->parser); if (token == VKTOR_T_NONE) { - ZVAL_NULL(*retval); + ZVAL_NULL(retval); } else { - ZVAL_LONG(*retval, token); + ZVAL_LONG(retval, token); } } @@ -213,15 +189,13 @@ static int jsonreader_get_token_type(jsonreader_object *obj, zval **retval TSRML /* {{{ jsonreader_get_token_value Get the value of the current token */ -static int jsonreader_get_token_value(jsonreader_object *obj, zval **retval TSRMLS_DC) +static int jsonreader_get_token_value(jsonreader_object *obj, zval *retval) { vktor_token t_type; vktor_error *err = NULL; - ALLOC_ZVAL(*retval); - if (! obj->parser) { - ZVAL_NULL(*retval); + ZVAL_NULL(retval); } else { t_type = vktor_get_token_type(obj->parser); switch(t_type) { @@ -231,12 +205,14 @@ static int jsonreader_get_token_value(jsonreader_object *obj, zval **retval TSRM case VKTOR_T_ARRAY_END: case VKTOR_T_OBJECT_START: case VKTOR_T_OBJECT_END: - ZVAL_NULL(*retval); + ZVAL_NULL(retval); break; case VKTOR_T_FALSE: + ZVAL_FALSE(retval); + break; case VKTOR_T_TRUE: - ZVAL_BOOL(*retval, (t_type == VKTOR_T_TRUE)); + ZVAL_TRUE(retval); break; case VKTOR_T_OBJECT_KEY: @@ -246,35 +222,35 @@ static int jsonreader_get_token_value(jsonreader_object *obj, zval **retval TSRM strlen = vktor_get_value_str(obj->parser, &strval, &err); if (err != NULL) { - ZVAL_NULL(*retval); - jsonreader_handle_error(err, obj TSRMLS_CC); + ZVAL_NULL(retval); + jsonreader_handle_error(err, obj); return FAILURE; } - ZVAL_STRINGL(*retval, strval, strlen, 1); + ZVAL_STRINGL(retval, strval, strlen); break; } case VKTOR_T_INT: - ZVAL_LONG(*retval, vktor_get_value_long(obj->parser, &err)); + ZVAL_LONG(retval, vktor_get_value_long(obj->parser, &err)); if (err != NULL) { - ZVAL_NULL(*retval); - jsonreader_handle_error(err, obj TSRMLS_CC); + ZVAL_NULL(retval); + jsonreader_handle_error(err, obj); return FAILURE; } break; case VKTOR_T_FLOAT: - ZVAL_DOUBLE(*retval, vktor_get_value_double(obj->parser, &err)); + ZVAL_DOUBLE(retval, vktor_get_value_double(obj->parser, &err)); if (err != NULL) { - ZVAL_NULL(*retval); - jsonreader_handle_error(err, obj TSRMLS_CC); + ZVAL_NULL(retval); + jsonreader_handle_error(err, obj); return FAILURE; } break; default: /* should not happen */ - php_error_docref(NULL TSRMLS_CC, E_ERROR, "internal error: unkown token type %d", t_type); + php_error_docref(NULL, E_ERROR, "internal error: unkown token type %d", t_type); return FAILURE; break; } @@ -286,20 +262,18 @@ static int jsonreader_get_token_value(jsonreader_object *obj, zval **retval TSRM /* {{{ jsonreader_get_current_struct Get the type of the current JSON struct we are in (object, array or none) */ -static int jsonreader_get_current_struct(jsonreader_object *obj, zval **retval TSRMLS_DC) +static int jsonreader_get_current_struct(jsonreader_object *obj, zval *retval) { vktor_struct cs; - ALLOC_ZVAL(*retval); - if (! obj->parser) { - ZVAL_NULL(*retval); + ZVAL_NULL(retval); } else { cs = vktor_get_current_struct(obj->parser); if (cs == VKTOR_STRUCT_NONE) { - ZVAL_NULL(*retval); + ZVAL_NULL(retval); } else { - ZVAL_LONG(*retval, cs); + ZVAL_LONG(retval, cs); } } @@ -309,17 +283,15 @@ static int jsonreader_get_current_struct(jsonreader_object *obj, zval **retval T /* {{{ jsonreader_get_current_depth Get the current nesting level */ -static int jsonreader_get_current_depth(jsonreader_object *obj, zval **retval TSRMLS_DC) +static int jsonreader_get_current_depth(jsonreader_object *obj, zval *retval) { int depth; - ALLOC_ZVAL(*retval); - - if (! obj->parser) { - ZVAL_NULL(*retval); + if (!obj->parser) { + ZVAL_NULL(retval); } else { depth = vktor_get_depth(obj->parser); - ZVAL_LONG(*retval, depth); + ZVAL_LONG(retval, depth); } return SUCCESS; @@ -328,11 +300,11 @@ static int jsonreader_get_current_depth(jsonreader_object *obj, zval **retval TS /* {{{ jsonreader_object_free_storage C-level object destructor for JSONReader objects */ -static void jsonreader_object_free_storage(void *object TSRMLS_DC) +static void jsonreader_object_free_storage(zend_object *object) { - jsonreader_object *intern = (jsonreader_object *) object; + FETCH_JSON_OBJECT_FROM_OBJ(object) - zend_object_std_dtor(&intern->std TSRMLS_CC); + zend_object_std_dtor(&intern->std); if (intern->parser) { vktor_parser_free(intern->parser); @@ -341,46 +313,34 @@ static void jsonreader_object_free_storage(void *object TSRMLS_DC) if (intern->stream && !intern->internal_stream) { php_stream_close(intern->stream); } - - efree(object); } /* }}} */ /* {{{ jsonreader_object_new C-level constructor of JSONReader objects. Does not initialize the vktor parser - this will be initialized when needed, by calling jsonreader_init() */ -static zend_object_value jsonreader_object_new(zend_class_entry *ce TSRMLS_DC) +static zend_object *jsonreader_object_new(zend_class_entry *ce) { - zend_object_value retval; jsonreader_object *intern; - intern = ecalloc(1, sizeof(jsonreader_object)); + intern = ecalloc(1, sizeof(jsonreader_object) + zend_object_properties_size(ce)); intern->max_depth = JSONREADER_G(max_depth); intern->read_buffer = JSONREADER_G(read_buffer); intern->errmode = ERRMODE_PHPERR; - zend_object_std_init(&(intern->std), ce TSRMLS_CC); - -#if PHP_VERSION_ID < 50399 - zend_hash_copy(intern->std.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); -#else - object_properties_init(&(intern->std), ce); -#endif + zend_object_std_init(&intern->std, ce); - retval.handle = zend_objects_store_put(intern, - (zend_objects_store_dtor_t) zend_objects_destroy_object, - (zend_objects_free_object_storage_t) jsonreader_object_free_storage, - NULL TSRMLS_CC); + object_properties_init(&intern->std, ce); - retval.handlers = &jsonreader_obj_handlers; + intern->std.handlers = &jsonreader_obj_handlers; - return retval; + return &intern->std; } /* }}} */ /* {{{ jsonreader_read_more_data Read more data from the stream and pass it to the parser */ -static int jsonreader_read_more_data(jsonreader_object *obj TSRMLS_DC) +static int jsonreader_read_more_data(jsonreader_object *obj) { char *buffer; int read; @@ -392,7 +352,7 @@ static int jsonreader_read_more_data(jsonreader_object *obj TSRMLS_DC) read = php_stream_read(obj->stream, buffer, obj->read_buffer); if (read <= 0) { /* done reading or error */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "JSON stream ended while expecting more data"); + php_error_docref(NULL, E_WARNING, "JSON stream ended while expecting more data"); efree(buffer); return FAILURE; } @@ -400,7 +360,7 @@ static int jsonreader_read_more_data(jsonreader_object *obj TSRMLS_DC) status = vktor_feed(obj->parser, buffer, read, 1, &err); if (status == VKTOR_ERROR) { - jsonreader_handle_error(err, obj TSRMLS_CC); + jsonreader_handle_error(err, obj); return FAILURE; } @@ -410,7 +370,7 @@ static int jsonreader_read_more_data(jsonreader_object *obj TSRMLS_DC) /* {{{ jsonreader_read Read the next token from the JSON stream */ -static int jsonreader_read(jsonreader_object *obj TSRMLS_DC) +static int jsonreader_read(jsonreader_object *obj) { vktor_status status = VKTOR_OK; vktor_error *err; @@ -429,11 +389,11 @@ static int jsonreader_read(jsonreader_object *obj TSRMLS_DC) break; case VKTOR_ERROR: - jsonreader_handle_error(err, obj TSRMLS_CC); + jsonreader_handle_error(err, obj); return FAILURE; case VKTOR_MORE_DATA: - if (jsonreader_read_more_data(obj TSRMLS_CC) == FAILURE) { + if (jsonreader_read_more_data(obj) == FAILURE) { retval = FAILURE; status = VKTOR_ERROR; } @@ -441,7 +401,7 @@ static int jsonreader_read(jsonreader_object *obj TSRMLS_DC) default: /* should not happen! */ - php_error_docref(NULL TSRMLS_CC, E_ERROR, "invalid status from internal JSON parser"); + php_error_docref(NULL, E_ERROR, "invalid status from internal JSON parser"); retval = FAILURE; break; } @@ -454,14 +414,14 @@ static int jsonreader_read(jsonreader_object *obj TSRMLS_DC) /* {{{ jsonreader_set_attribute set an attribute of the JSONReader object */ -static void jsonreader_set_attribute(jsonreader_object *obj, ulong attr_key, zval *attr_value TSRMLS_DC) +static void jsonreader_set_attribute(jsonreader_object *obj, zend_ulong attr_key, zval *attr_value) { long lval = Z_LVAL_P(attr_value); switch(attr_key) { case ATTR_MAX_DEPTH: if (lval < 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "maximal nesting level must be more than 0, %ld given", lval); + php_error_docref(NULL, E_WARNING, "maximal nesting level must be more than 0, %ld given", lval); } else { obj->max_depth = lval; } @@ -469,7 +429,7 @@ static void jsonreader_set_attribute(jsonreader_object *obj, ulong attr_key, zva case ATTR_READ_BUFF: if (lval < 1) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "read buffer size must be more than 0, %ld given", lval); + php_error_docref(NULL, E_WARNING, "read buffer size must be more than 0, %ld given", lval); } else { obj->read_buffer = lval; } @@ -484,7 +444,7 @@ static void jsonreader_set_attribute(jsonreader_object *obj, ulong attr_key, zva break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid error handler attribute value: %ld", lval); + php_error_docref(NULL, E_WARNING, "invalid error handler attribute value: %ld", lval); break; } break; @@ -495,31 +455,25 @@ static void jsonreader_set_attribute(jsonreader_object *obj, ulong attr_key, zva Create a new JSONReader object, potentially setting some local attributes */ PHP_METHOD(jsonreader, __construct) { - zval *object = getThis(); zval *options = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a", &options) == FAILURE) { - ZVAL_NULL(object); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a", &options) == FAILURE) { + //ZVAL_NULL(getThis()); return; } /* got attributes - set them */ if (options) { - jsonreader_object *intern; - zval **attr_value; - char *str_key; - ulong long_key; - HashPosition pos; - - intern = (jsonreader_object *) zend_object_store_get_object(object TSRMLS_CC); - - for(zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(options), &pos); - (zend_hash_get_current_data_ex(Z_ARRVAL_P(options), (void **)&attr_value, &pos) == SUCCESS) && - (zend_hash_get_current_key_ex(Z_ARRVAL_P(options), &str_key, NULL, &long_key, 0, &pos) == HASH_KEY_IS_LONG) && - (Z_TYPE_PP(attr_value) == IS_LONG); - zend_hash_move_forward_ex(Z_ARRVAL_P(options), &pos)) { - jsonreader_set_attribute(intern, long_key, *attr_value TSRMLS_CC); - } + zval *val; + zend_ulong h; + zend_string *key; + FETCH_JSON_OBJECT + + ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), h, key, val) + if (!key) { + jsonreader_set_attribute(intern, h, val); + } + ZEND_HASH_FOREACH_END(); } } /* }}} */ @@ -531,16 +485,14 @@ PHP_METHOD(jsonreader, __construct) PHP_METHOD(jsonreader, open) { zval *object, *arg; - jsonreader_object *intern; php_stream *tmp_stream; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) { + FETCH_JSON_OBJECT + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) { return; } - object = getThis(); - intern = (jsonreader_object *) zend_object_store_get_object(object TSRMLS_CC); - switch(Z_TYPE_P(arg)) { case IS_STRING: tmp_stream = php_stream_open_wrapper(Z_STRVAL_P(arg), "r", REPORT_ERRORS, NULL); @@ -550,13 +502,13 @@ PHP_METHOD(jsonreader, open) break; case IS_RESOURCE: - php_stream_from_zval(tmp_stream, &arg); + php_stream_from_zval(tmp_stream, arg); intern->internal_stream = tmp_stream->abstract; intern->stream = tmp_stream; break; default: - php_error_docref(NULL TSRMLS_CC, E_WARNING, "argument is expected to be a resource of type stream or a string, %s given", zend_zval_type_name(arg)); + php_error_docref(NULL, E_WARNING, "argument is expected to be a resource of type stream or a string, %s given", zend_zval_type_name(arg)); RETURN_FALSE; } @@ -571,10 +523,7 @@ PHP_METHOD(jsonreader, open) PHP_METHOD(jsonreader, close) { zval *object; - jsonreader_object *intern; - - object = getThis(); - intern = (jsonreader_object *) zend_object_store_get_object(object TSRMLS_CC); + FETCH_JSON_OBJECT /* Close stream, if open */ if (intern->stream && !intern->stream->abstract) { @@ -598,15 +547,13 @@ PHP_METHOD(jsonreader, close) PHP_METHOD(jsonreader, read) { zval *object; - jsonreader_object *intern; RETVAL_TRUE; - object = getThis(); - intern = (jsonreader_object *) zend_object_store_get_object(object TSRMLS_CC); + FETCH_JSON_OBJECT if (!intern->stream || (intern->internal_stream && intern->stream->abstract != intern->internal_stream)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "trying to read but no stream was opened or stream was closed"); + php_error_docref(NULL, E_WARNING, "trying to read but no stream was opened or stream was closed"); RETURN_FALSE; } @@ -638,7 +585,7 @@ static const zend_function_entry jsonreader_class_methods[] = { PHP_ME(jsonreader, open, arginfo_jsonreader_open, ZEND_ACC_PUBLIC) PHP_ME(jsonreader, close, arginfo_jsonreader_close, ZEND_ACC_PUBLIC) PHP_ME(jsonreader, read, arginfo_jsonreader_read, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL, 0, 0} + PHP_FE_END }; /* }}} */ @@ -661,22 +608,29 @@ PHP_GINIT_FUNCTION(jsonreader) } /* }}} */ +static void json_prop_handlers_dtor(zval *el) +{ + pefree(Z_PTR_P(el), 1); +} + /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(jsonreader) { zend_class_entry ce; REGISTER_INI_ENTRIES(); - zend_hash_init(&jsonreader_prop_handlers, 8, NULL, NULL, 1); + zend_hash_init(&jsonreader_prop_handlers, 8, NULL, json_prop_handlers_dtor, 1); memcpy(&jsonreader_obj_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); jsonreader_obj_handlers.read_property = jsonreader_read_property; jsonreader_obj_handlers.write_property = jsonreader_write_property; + jsonreader_obj_handlers.offset = XtOffsetOf(struct _jsonreader_object, std); + jsonreader_obj_handlers.free_obj = jsonreader_object_free_storage; INIT_CLASS_ENTRY(ce, "JSONReader", jsonreader_class_methods); ce.create_object = jsonreader_object_new; - jsonreader_ce = zend_register_internal_class(&ce TSRMLS_CC); + jsonreader_ce = zend_register_internal_class(&ce); JSONREADER_REG_CLASS_CONST_L("ATTR_MAX_DEPTH", ATTR_MAX_DEPTH); JSONREADER_REG_CLASS_CONST_L("ATTR_READ_BUFF", ATTR_READ_BUFF); @@ -703,13 +657,13 @@ PHP_MINIT_FUNCTION(jsonreader) JSONREADER_REG_CLASS_CONST_L("ARRAY", VKTOR_STRUCT_ARRAY); JSONREADER_REG_CLASS_CONST_L("OBJECT", VKTOR_STRUCT_OBJECT); - jsonreader_register_prop_handler("tokenType", jsonreader_get_token_type, NULL TSRMLS_CC); - jsonreader_register_prop_handler("value", jsonreader_get_token_value, NULL TSRMLS_CC); - jsonreader_register_prop_handler("currentStruct", jsonreader_get_current_struct, NULL TSRMLS_CC); - jsonreader_register_prop_handler("currentDepth", jsonreader_get_current_depth, NULL TSRMLS_CC); + jsonreader_register_prop_handler("tokenType", jsonreader_get_token_type, NULL); + jsonreader_register_prop_handler("value", jsonreader_get_token_value, NULL); + jsonreader_register_prop_handler("currentStruct", jsonreader_get_current_struct, NULL); + jsonreader_register_prop_handler("currentDepth", jsonreader_get_current_depth, NULL); INIT_CLASS_ENTRY(ce, "JSONReaderException", NULL); - jsonreader_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(TSRMLS_C), NULL TSRMLS_CC); + jsonreader_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default()); vktor_set_memory_handlers(jsr_malloc, jsr_realloc, jsr_free); diff --git a/php_jsonreader.h b/php_jsonreader.h index aca26b7..72949ea 100644 --- a/php_jsonreader.h +++ b/php_jsonreader.h @@ -62,18 +62,21 @@ PHP_METHOD(jsonreader, open); PHP_METHOD(jsonreader, __construct); typedef struct _jsonreader_object { - zend_object std; php_stream *stream; void *internal_stream; vktor_parser *parser; long max_depth; long read_buffer; int errmode; + zend_object std; } jsonreader_object; +#define FETCH_JSON_OBJECT_FROM_OBJ(obj) jsonreader_object *intern = (jsonreader_object *)((char *)(obj) - XtOffsetOf(struct _jsonreader_object, std)); +#define FETCH_JSON_OBJECT_FROM_ZV(obj) FETCH_JSON_OBJECT_FROM_OBJ(Z_OBJ_P(obj)) +#define FETCH_JSON_OBJECT FETCH_JSON_OBJECT_FROM_ZV(getThis()) + #define JSONREADER_REG_CLASS_CONST_L(name, value) \ - zend_declare_class_constant_long(jsonreader_ce, name, sizeof(name) - 1, \ - (long) value TSRMLS_CC) + zend_declare_class_constant_long(jsonreader_ce, name, strlen(name), (long) value) #define JSONREADER_VALUE_TOKEN VKTOR_T_NULL | \ VKTOR_T_TRUE | \ @@ -93,8 +96,8 @@ enum { ERRMODE_INTERN }; -typedef int (*jsonreader_read_t) (jsonreader_object *obj, zval **retval TSRMLS_DC); -typedef int (*jsonreader_write_t) (jsonreader_object *obj, zval *newval TSRMLS_DC); +typedef int (*jsonreader_read_t) (jsonreader_object *obj, zval *retval); +typedef int (*jsonreader_write_t) (jsonreader_object *obj, zval *newval); typedef struct _jsonreader_prop_handler { jsonreader_read_t read_func;