diff --git a/jsonreader.c b/jsonreader.c index 77b402b..c827eb3 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. */ @@ -79,7 +43,7 @@ enum { 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); } /* }}} */ @@ -104,22 +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; } @@ -127,154 +88,98 @@ 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) +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.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_str_add_mem(&jsonreader_prop_handlers, name, strlen(name), &jph, sizeof(jsonreader_prop_handler)); } /* }}} */ /* {{{ jsonreader_read_property Property read handler */ -zval* jsonreader_read_property(zval *object, zval *member, int type TSRMLS_DC) +static zval *jsonreader_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) { - jsonreader_object *intern; - zval tmp_member; - zval *retval; + zval retval; jsonreader_prop_handler *jph; - zend_object_handlers *std_hnd; - int ret; + FETCH_JSON_OBJECT_FROM_ZV(object) 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) { - Z_SET_REFCOUNT_P(retval, 0); + 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_hnd = zend_get_std_object_handlers(); -#if PHP_VERSION_ID < 50399 - retval = std_hnd->read_property(object, member, type TSRMLS_CC); -#else - retval = std_hnd->read_property(object, member, type TSRMLS_CC, NULL); -#endif - +std_h: + ZVAL_COPY_VALUE(rv, std_object_handlers.read_property(object, member, type, cache_slot, rv)); + return rv; } - - if (member == &tmp_member) { - zval_dtor(member); - } - - return retval; } /* }}} */ /* {{{ jsonreader_write_property */ -void jsonreader_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +static void jsonreader_write_property(zval *object, zval *member, zval *value, void **cache_slot) { - jsonreader_object *intern; - zval tmp_member; + FETCH_JSON_OBJECT_FROM_ZV(object) 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) { - 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_hnd = zend_get_std_object_handlers(); -#if PHP_VERSION_ID < 50399 - std_hnd->write_property(object, member, value TSRMLS_CC); -#else - std_hnd->write_property(object, member, value TSRMLS_CC, NULL); -#endif +std_h: + std_object_handlers.write_property(object, member, value, cache_slot); } - if (member == &tmp_member) { - zval_dtor(member); - } } /* }}} */ /* {{{ 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); } } @@ -284,16 +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) { @@ -303,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: @@ -318,36 +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; } @@ -359,21 +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); } } @@ -383,117 +283,84 @@ 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; } /* }}} */ -/* }}} */ - /* {{{ 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); } - if (intern->stream && intern->close_stream) { + 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->max_depth = JSONREADER_G(max_depth); + 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 + intern->errmode = ERRMODE_PHPERR; - 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); + zend_object_std_init(&intern->std, ce); - retval.handlers = &jsonreader_obj_handlers; - - return retval; -} -/* }}} */ + object_properties_init(&intern->std, ce); -/* {{{ 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); + intern->std.handlers = &jsonreader_obj_handlers; - if (obj->stream) { - php_stream_close(obj->stream); - } + 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; 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"); + php_error_docref(NULL, 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); + jsonreader_handle_error(err, obj); return FAILURE; } @@ -503,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; @@ -522,12 +389,11 @@ static int jsonreader_read(jsonreader_object *obj TSRMLS_DC) break; case VKTOR_ERROR: - jsonreader_handle_error(err, obj TSRMLS_CC); - retval = FAILURE; - break; + 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; } @@ -535,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; } @@ -548,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; } @@ -563,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; } @@ -578,8 +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; @@ -590,29 +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 != NULL) { - jsonreader_object *intern; - zval **attr_value; - char *str_key; - ulong long_key; - - 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)); - } + if (options) { + 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(); } } /* }}} */ @@ -624,39 +485,34 @@ PHP_METHOD(jsonreader, __construct) 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) { + 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", 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; + 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_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, 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; } @@ -667,15 +523,12 @@ 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) { + if (intern->stream && !intern->stream->abstract) { php_stream_close(intern->stream); - intern->stream = NULL; + intern->stream = NULL; } /* Free parser, if created */ @@ -694,22 +547,16 @@ 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) { - 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, 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 +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} + PHP_FE_END }; /* }}} */ @@ -748,44 +595,43 @@ 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; } /* }}} */ +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, json_prop_handlers_dtor, 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; + jsonreader_obj_handlers.offset = XtOffsetOf(struct _jsonreader_object, std); + jsonreader_obj_handlers.free_obj = jsonreader_object_free_storage; - /* 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); + jsonreader_ce = zend_register_internal_class(&ce); - /* 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 +657,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); + 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); - /** - * 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()); - /** - * Set libvktor to use PHP memory allocation functions - */ vktor_set_memory_handlers(jsr_malloc, jsr_realloc, jsr_free); return SUCCESS; @@ -837,7 +675,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..72949ea 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,78 @@ 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 { + 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, strlen(name), (long) value) + +#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); +typedef int (*jsonreader_write_t) (jsonreader_object *obj, zval *newval); + +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)