From 14a010b784f6228a293c90502c46a7143d89afbf Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 6 Dec 2021 21:27:40 +0100 Subject: [PATCH] initial ci --- .editorconfig | 27 + .gitignore | 41 ++ AUTHORS | 1 + CONTRIBUTING.md | 39 ++ CREDITS | 2 + EXPERIMENTAL | 0 LICENSE | 22 + config.m4 | 56 ++ gen_stub.php.diff | 90 +++ ion.c | 1536 ++++++++++++++++++++++++++++++++++++++++++++ ion.stub.php | 446 +++++++++++++ ion_arginfo.h | 1548 +++++++++++++++++++++++++++++++++++++++++++++ ion_private.h | 1486 +++++++++++++++++++++++++++++++++++++++++++ php_ion.h | 27 + 14 files changed, 5321 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 CONTRIBUTING.md create mode 100644 CREDITS create mode 100644 EXPERIMENTAL create mode 100644 LICENSE create mode 100644 config.m4 create mode 100644 gen_stub.php.diff create mode 100644 ion.c create mode 100644 ion.stub.php create mode 100644 ion_arginfo.h create mode 100644 ion_private.h create mode 100644 php_ion.h diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7105c46 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,27 @@ +; see http://editorconfig.org +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = tab +charset = utf-8 +trim_trailing_whitespace = true + +[*.php] +indent_style = space +indent_size = 4 + +[*.md] +trim_trailing_whitespace = false + +[*.json] +indent_style = space +indent_size = 4 + +[package.xml] +indent_style = space +indent_size = 1 + +[config.w32] +end_of_line = crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ae434fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +*.lo +*.la +.libs +acinclude.m4 +aclocal.m4 +autom4te.cache +build +config.guess +config.h +config.h.in +config.log +config.nice +config.status +config.sub +configure +configure.ac +configure.in +include +install-sh +libtool +ltmain.sh +Makefile +Makefile.fragments +Makefile.global +Makefile.objects +missing +mkinstalldirs +modules +php_test_results_*.txt +phpt.* +run-test-info.php +run-tests.php +tests/**/*.diff +tests/**/*.out +tests/**/*.php +tests/**/*.exp +tests/**/*.log +tests/**/*.sh +tests/**/*.db +tests/**/*.mem +tmp-php.ini diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..67bbd91 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Michael Wallner diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..968bd44 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,39 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of +fostering an open and welcoming community, we pledge to respect all people who +contribute through reporting issues, posting feature requests, updating +documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free +experience for everyone, regardless of level of experience, gender, gender +identity and expression, sexual orientation, disability, personal appearance, +body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission +* Other unethical or unprofessional conduct. + +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct. By adopting this Code of Conduct, project +maintainers commit themselves to fairly and consistently applying these +principles to every aspect of managing this project. Project maintainers who do +not follow or enforce the Code of Conduct may be permanently removed from the +project team. + +This code of conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by opening an issue or contacting one or more of the project maintainers. + +This Code of Conduct is adapted from the +[Contributor Covenant](http://contributor-covenant.org), version 1.2.0, +available at http://contributor-covenant.org/version/1/2/0/. diff --git a/CREDITS b/CREDITS new file mode 100644 index 0000000..e0f497d --- /dev/null +++ b/CREDITS @@ -0,0 +1,2 @@ +ion +Michael Wallner \ No newline at end of file diff --git a/EXPERIMENTAL b/EXPERIMENTAL new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2cb49b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2021, Michael Wallner . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/config.m4 b/config.m4 new file mode 100644 index 0000000..4d85c67 --- /dev/null +++ b/config.m4 @@ -0,0 +1,56 @@ + +PHP_ARG_WITH([ion], + [for ion support], + [AS_HELP_STRING([--with-ion], + [path to libion])], + [no]) + +if test "$PHP_ION" != "no"; then + + SEARCH_PATH="/usr/local /usr" # you might want to change this + SEARCH_FOR="/include/ionc/ion.h" # you most likely want to change this + if test -r $PHP_ION/$SEARCH_FOR; then # path given as parameter + ION_DIR=$PHP_ION + else # search default path list + AC_MSG_CHECKING([for ion files in default path]) + for i in $SEARCH_PATH ; do + if test -r $i/$SEARCH_FOR; then + ION_DIR=$i + AC_MSG_RESULT(found in $i) + fi + done + fi + dnl + if test -z "$ION_DIR"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Please reinstall the ion distribution]) + fi + + PHP_ADD_INCLUDE($ION_DIR/include) + + LIBNAME=ionc + LIBSYMBOL=ion_error_to_str + PHP_CHECK_LIBRARY($LIBNAME, $LIBSYMBOL, + [ + PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $ION_DIR/$PHP_LIBDIR, ION_SHARED_LIBADD) + ],[ + AC_MSG_ERROR([could not link with ionc library.]) + ],[ + -L$ION_DIR/$PHP_LIBDIR -lm + ]) + LIBNAME=decNumber + LIBSYMBOL=decQuadFromInt32 + PHP_CHECK_LIBRARY($LIBNAME, $LIBSYMBOL, + [ + PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $ION_DIR/$PHP_LIBDIR, ION_SHARED_LIBADD) + ],[ + AC_MSG_ERROR([could not link with ionc library.]) + ],[ + -L$ION_DIR/$PHP_LIBDIR -lm + ]) + + PHP_SUBST(ION_SHARED_LIBADD) + AC_DEFINE(HAVE_ION, 1, [ Have ion support ]) + + PHP_NEW_EXTENSION(ion, ion.c, $ext_shared) +fi diff --git a/gen_stub.php.diff b/gen_stub.php.diff new file mode 100644 index 0000000..d01ec3d --- /dev/null +++ b/gen_stub.php.diff @@ -0,0 +1,90 @@ +diff --git a/build/gen_stub.php b/build/gen_stub.php +index 5f74d26dbc3..01a19988161 100755 +--- a/build/gen_stub.php ++++ b/build/gen_stub.php +@@ -793,7 +793,7 @@ class FunctionName implements FunctionOrMethodName { + } + + public function getDeclarationName(): string { +- return $this->name->getLast(); ++ return strtr($this->name->toString(), "\\", "_"); + } + + public function getDeclaration(): string { +@@ -1152,8 +1152,8 @@ class FuncInfo { + if ($namespace) { + // Render A\B as "A\\B" in C strings for namespaces + return sprintf( +- "\tZEND_NS_FE(\"%s\", %s, %s)\n", +- addslashes($namespace), $declarationName, $this->getArgInfoName()); ++ "\tZEND_NS_RAW_FENTRY(\"%s\", \"%s\", ZEND_FN(%s), %s, 0)\n", ++ addslashes($namespace), substr((string)$this->name, strlen($namespace)+1), $declarationName, $this->getArgInfoName()); + } else { + return sprintf("\tZEND_FE(%s, %s)\n", $declarationName, $this->getArgInfoName()); + } +@@ -1608,7 +1608,7 @@ class EnumCaseInfo { + public function getDeclaration(): string { + $escapedName = addslashes($this->name); + if ($this->value === null) { +- $code = "\n\tzend_enum_add_case_cstr(class_entry, \"$escapedName\", NULL);\n"; ++ $code = "\tzend_enum_add_case_cstr(class_entry, \"$escapedName\", NULL);\n"; + } else { + $evaluator = new ConstExprEvaluator(function (Expr $expr) { + throw new Exception("Enum case $this->name has an unsupported value"); +@@ -2369,7 +2369,7 @@ function parseFunctionLike( + function parseProperty( + Name $class, + int $flags, +- Stmt\PropertyProperty $property, ++ Stmt\PropertyProperty|Node\Param $property, + ?Node $type, + ?DocComment $comment, + PrettyPrinterAbstract $prettyPrinter +@@ -2404,13 +2404,23 @@ function parseProperty( + } + } + ++ $default = $property->default; ++ if ($property instanceof Node\Param) { ++ $name = $property->var->name; ++ if ($property->flags & Stmt\Class_::MODIFIER_READONLY) { ++ $default = null; ++ } ++ } else { ++ $name = $property->name; ++ } ++ + return new PropertyInfo( +- new PropertyName($class, $property->name->__toString()), ++ new PropertyName($class, (string) $name), + $flags, + $propertyType, + $phpDocType ? Type::fromString($phpDocType) : null, +- $property->default, +- $property->default ? $prettyPrinter->prettyPrintExpr($property->default) : null, ++ $default, ++ $default ? $prettyPrinter->prettyPrintExpr($default) : null, + $isDocReadonly + ); + } +@@ -2594,6 +2604,20 @@ function handleStatements(FileInfo $fileInfo, array $stmts, PrettyPrinterAbstrac + $classStmt, + $cond + ); ++ if ($classStmt->name->toString() === "__construct") { ++ foreach ($classStmt->params as $param) { ++ if ($param->flags) { ++ $propertyInfos[] = parseProperty( ++ $className, ++ $param->flags, ++ $param, ++ $param->type, ++ $param->getDocComment(), ++ $prettyPrinter ++ ); ++ } ++ } ++ } + } else if ($classStmt instanceof Stmt\EnumCase) { + $enumCaseInfos[] = new EnumCaseInfo( + $classStmt->name->toString(), $classStmt->expr); diff --git a/ion.c b/ion.c new file mode 100644 index 0000000..a4915e3 --- /dev/null +++ b/ion.c @@ -0,0 +1,1536 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: ion | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2021, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "php.h" +#include "ext/standard/info.h" + +#include "Zend/zend_enum.h" +#include "Zend/zend_exceptions.h" +#include "Zend/zend_closures.h" +#include "Zend/zend_interfaces.h" +#include "Zend/zend_smart_str.h" + +#include "ext/date/php_date.h" +#include "ext/spl/spl_exceptions.h" +#include "ext/spl/spl_iterators.h" + +#define DECNUMDIGITS 34 /* DECQUAD_Pmax */ +#include "ionc/ion.h" + +#include "php_ion.h" +#define ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(pass_by_ref, name, classname, type_mask, default_value) \ + { #name, ZEND_TYPE_INIT_CLASS_CONST_MASK(#classname, type_mask | _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), default_value }, +#include "ion_arginfo.h" +#include "ion_private.h" + +ZEND_METHOD(ion_Symbol_ImportLocation, __construct) +{ + zend_long location; + php_ion_symbol_iloc *obj = php_ion_obj(symbol_iloc, Z_OBJ_P(ZEND_THIS)); + + PTR_CHECK(obj); + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_STR(obj->name) + Z_PARAM_LONG(location) + ZEND_PARSE_PARAMETERS_END(); + + obj->loc.location = location; + php_ion_symbol_iloc_ctor(obj); +} +ZEND_METHOD(ion_Symbol, __construct) +{ + zend_long sid = -1; + php_ion_symbol *obj = php_ion_obj(symbol, Z_OBJ_P(ZEND_THIS)); + + PTR_CHECK(obj); + + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_STR(obj->value) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(sid) + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->iloc, ce_Symbol_ImportLocation) + ZEND_PARSE_PARAMETERS_END(); + + obj->sym.sid = sid; + php_ion_symbol_ctor(obj); +} +ZEND_METHOD(ion_Symbol, equals) +{ + zend_object *other_obj; + php_ion_symbol *sym = php_ion_obj(symbol, Z_OBJ_P(ZEND_THIS)); + + OBJ_CHECK(sym); + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(other_obj, ce_Symbol) + ZEND_PARSE_PARAMETERS_END(); + + BOOL eq = FALSE; + iERR err = ion_symbol_is_equal( + &sym->sym, + &php_ion_obj(symbol, other_obj)->sym, &eq); + ION_CHECK(err); + RETVAL_BOOL(eq); +} +ZEND_METHOD(ion_Timestamp, __construct) +{ + zend_long precision; + zend_string *fmt = NULL, *dt = NULL; + zval *tz = NULL; + php_ion_timestamp *obj = php_ion_obj(timestamp, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + ZEND_PARSE_PARAMETERS_START(1, 4) + Z_PARAM_LONG(precision) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(fmt) + Z_PARAM_STR(dt) + Z_PARAM_ZVAL(tz) + ZEND_PARSE_PARAMETERS_END(); + + php_ion_timestamp_ctor(obj, precision, fmt, dt, tz); +} +ZEND_METHOD(ion_Timestamp, __toString) +{ + php_ion_timestamp *obj = php_ion_obj(timestamp, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + zval fmt; + ZVAL_NULL(&fmt); + zend_call_method_with_1_params(&obj->std, obj->std.ce, NULL, "format", return_value, + zend_read_property(obj->std.ce, &obj->std, ZEND_STRL("format"), 0, &fmt)); +} +ZEND_METHOD(ion_Decimal, __construct) +{ + php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + zend_long num; + zend_string *zstr; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STR_OR_LONG(zstr, num) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->ctx, ce_Decimal_Context) + ZEND_PARSE_PARAMETERS_END(); + + if (zstr) { + ION_CHECK(ion_decimal_from_string(&obj->dec, zstr->val, + obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL)); + } else if (num <= INT32_MAX && num >= INT32_MIN) { + ION_CHECK(ion_decimal_from_int32(&obj->dec, num)); + } else if (num > 0 && num <= UINT32_MAX) { + ION_CHECK(ion_decimal_from_uint32(&obj->dec, num)); + } else { + zend_throw_exception_ex(spl_ce_OverflowException, 0, + "Integer value out of bounds: " ZEND_LONG_FMT " (INT32_MIN < n < UINT32_MAX)", num); + return; + } + + php_ion_decimal_ctor(obj); +} +ZEND_METHOD(ion_Decimal, equals) +{ + php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + zend_object *dec_obj; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(dec_obj, ce_Decimal) + ZEND_PARSE_PARAMETERS_END(); + + BOOL is = FALSE; + ION_CHECK(ion_decimal_equals(&obj->dec, &php_ion_obj(decimal, dec_obj)->dec, + obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL, &is)); + RETURN_BOOL(is); +} +ZEND_METHOD(ion_Decimal, zero) +{ + php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_CHECK(ion_decimal_zero(&obj->dec)); +} +ZEND_METHOD(ion_Decimal, __toString) +{ + php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + RETURN_STR(php_ion_decimal_to_string(&obj->dec)); +} +ZEND_METHOD(ion_Decimal, toInt) +{ + php_ion_decimal *obj = php_ion_obj(decimal, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + int32_t i32 = 0; + iERR err = ion_decimal_to_int32(&obj->dec, + obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL, &i32); + if (IERR_OK == err) { + RETURN_LONG(i32); + } + if (!ion_decimal_is_negative(&obj->dec)) { + uint32_t u32 = 0; + err = ion_decimal_to_uint32(&obj->dec, + obj->ctx ? &php_ion_obj(decimal_ctx, obj->ctx)->ctx : NULL, &u32); + if (IERR_OK == err) { + RETURN_LONG(u32); + } + } + ION_CHECK(err); +} +ZEND_METHOD(ion_Reader_Options, __construct) +{ + php_ion_reader_options *opt = php_ion_obj(reader_options, Z_OBJ_P(ZEND_THIS)); + zend_bool ret_sys_val = false, skip_validation = false; + zend_long ch_nl = 0xa, max_depth = 10, max_ann, max_ann_buf = 512, + sym_thr = 0x1000, uval_thr = 0x1000, chunk_thr = 0x1000, alloc_pgsz = 0x1000; + + PTR_CHECK(opt); + + ZEND_PARSE_PARAMETERS_START(0, 13) + Z_PARAM_OPTIONAL + // public readonly ?\ion\Catalog $catalog = null, + Z_PARAM_OBJ_OF_CLASS_OR_NULL(opt->cat, ce_Catalog) + // public readonly ?\ion\Decimal\Context $decimalContext = null, + Z_PARAM_OBJ_OF_CLASS_OR_NULL(opt->dec_ctx, ce_Decimal_Context) + // public readonly ?\Closure $onContextChange = null, + Z_PARAM_OBJ_OF_CLASS_OR_NULL(opt->cb, zend_ce_closure); + // public readonly bool $returnSystemValues = false, + Z_PARAM_BOOL(ret_sys_val) + // public readonly int $newLine = 0xa, + Z_PARAM_LONG(ch_nl) + // public readonly int $maxContainerDepth = 10, + Z_PARAM_LONG(max_depth) + // public readonly int $maxAnnotations = 10, + Z_PARAM_LONG(max_ann) + // public readonly int $maxAnnotationBuffered = 512, + Z_PARAM_LONG(max_ann_buf) + // public readonly int $symbolThreshold = 4096, + Z_PARAM_LONG(sym_thr) + // public readonly int $userValueThreshold = 4096, + Z_PARAM_LONG(uval_thr) + // public readonly int $chunkThreshold = 4096, + Z_PARAM_LONG(chunk_thr) + // public readonly int $allocationPageSize = 4096, + Z_PARAM_LONG(alloc_pgsz) + // public readonly bool $skipCharacterValidation = false, + Z_PARAM_BOOL(skip_validation) + ZEND_PARSE_PARAMETERS_END(); + + opt->opt.context_change_notifier = EMPTY_READER_CHANGE_NOTIFIER; + if (opt->cb) { + update_property_obj(&opt->std, ZEND_STRL("onContextChange"), opt->cb); + } + if (opt->cat) { + update_property_obj(&opt->std, ZEND_STRL("catalog"), opt->cat); + opt->opt.pcatalog = php_ion_obj(catalog, opt->cat)->cat; + } + if (opt->dec_ctx) { + update_property_obj(&opt->std, ZEND_STRL("decimalContext"), opt->dec_ctx); + opt->opt.decimal_context = &php_ion_obj(decimal_ctx, opt->dec_ctx)->ctx; + } + zend_update_property_bool(opt->std.ce, &opt->std, ZEND_STRL("returnSystemValues"), + opt->opt.return_system_values = ret_sys_val); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("newLine"), + opt->opt.new_line_char = ch_nl); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("maxContainerDepth"), + opt->opt.max_container_depth = max_depth); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("maxAnnotationCount"), + opt->opt.max_annotation_count = max_ann); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("maxAnnotationBuffered"), + opt->opt.max_annotation_buffered = max_ann_buf); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("symbolThreshold"), + opt->opt.symbol_threshold = sym_thr); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("userValueThreshold"), + opt->opt.user_value_threshold = uval_thr); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("chunkThreshold"), + opt->opt.chunk_threshold = chunk_thr); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("allocationPageSize"), + opt->opt.allocation_page_size = alloc_pgsz); + zend_update_property_long(opt->std.ce, &opt->std, ZEND_STRL("skipCharacterValidation"), + opt->opt.skip_character_validation = skip_validation); +} +ZEND_METHOD(ion_Reader_Reader, hasChildren) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + + OBJ_CHECK(obj); + ZEND_PARSE_PARAMETERS_NONE(); + + ION_TYPE t; + ION_CHECK(ion_reader_get_type(obj->reader, &t)); + switch (ION_TYPE_INT(t)) { + case tid_LIST_INT: + case tid_SEXP_INT: + case tid_STRUCT_INT: + RETVAL_TRUE; + break; + default: + RETVAL_FALSE; + break; + } +} +ZEND_METHOD(ion_Reader_Reader, getChildren) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_CHECK(ion_reader_step_in(obj->reader)); + + RETURN_ZVAL(ZEND_THIS, 1, 0); +} +ZEND_METHOD(ion_Reader_Reader, rewind) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_CHECK(ion_reader_next(obj->reader, &obj->state)); +} +ZEND_METHOD(ion_Reader_Reader, next) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + if (obj->state == tid_EOF) { + SIZE depth = 0; + ION_CHECK(ion_reader_get_depth(obj->reader, &depth)); + if (depth) { + ION_CHECK(ion_reader_step_out(obj->reader)); + } + } + ION_CHECK(ion_reader_next(obj->reader, &obj->state)); +} +ZEND_METHOD(ion_Reader_Reader, valid) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + RETURN_BOOL(obj->state != tid_none && obj->state != tid_EOF); +} +ZEND_METHOD(ion_Reader_Reader, key) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + RETURN_IONTYPE(obj->state); +} +ZEND_METHOD(ion_Reader_Reader, current) +{ + ZEND_PARSE_PARAMETERS_NONE(); + RETURN_ZVAL(ZEND_THIS, 1, 0); +} +ZEND_METHOD(ion_Reader_Reader, getType) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_TYPE typ; + ION_CHECK(ion_reader_get_type(obj->reader, &typ)); + RETURN_IONTYPE(typ); +} +ZEND_METHOD(ion_Reader_Reader, hasAnnotations) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + BOOL has = FALSE; + ION_CHECK(ion_reader_has_any_annotations(obj->reader, &has)); + RETURN_BOOL(has); +} +ZEND_METHOD(ion_Reader_Reader, hasAnnotation) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_string *ann_zstr; + ZEND_PARSE_PARAMETERS_START(1, 1); + Z_PARAM_STR(ann_zstr); + ZEND_PARSE_PARAMETERS_END(); + + ION_STRING ann_istr; + BOOL has = FALSE; + ION_CHECK(ion_reader_has_annotation(obj->reader, ion_string_from_zend(&ann_istr, ann_zstr), &has)); + RETURN_BOOL(has); +} +ZEND_METHOD(ion_Reader_Reader, isNull) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + BOOL is = FALSE; + ION_CHECK(ion_reader_is_null(obj->reader, &is)); + RETURN_BOOL(is); +} +ZEND_METHOD(ion_Reader_Reader, isInStruct) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + BOOL is = FALSE; + ION_CHECK(ion_reader_is_in_struct(obj->reader, &is)); + RETURN_BOOL(is); +} +ZEND_METHOD(ion_Reader_Reader, getFieldName) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_STRING name; + ION_CHECK(ion_reader_get_field_name(obj->reader, &name)); + RETURN_STRINGL((char *) name.value, name.length); +} +ZEND_METHOD(ion_Reader_Reader, getFieldNameSymbol) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_SYMBOL *sym_ptr; + ION_CHECK(ion_reader_get_field_name_symbol(obj->reader, &sym_ptr)); + + php_ion_symbol_zval(sym_ptr, return_value); +} +ZEND_METHOD(ion_Reader_Reader, getAnnotations) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + int32_t count, max; + if (obj->opt) { + max = php_ion_obj(reader_options, obj->opt)->opt.max_annotation_count; + } else { + max = 10; + } + ION_STRING *ptr = ecalloc(sizeof(*ptr), max); + iERR err = ion_reader_get_annotations(obj->reader, ptr, max, &count); + if (!err) { + array_init_size(return_value, count); + for (int32_t i = 0; i < count; ++i) { + add_next_index_str(return_value, zend_string_from_ion(&ptr[i])); + } + } + efree(ptr); + ION_CHECK(err); +} +ZEND_METHOD(ion_Reader_Reader, getAnnotationSymbols) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + int32_t count, max = php_ion_obj(reader_options, obj->opt)->opt.max_annotation_count; + ION_SYMBOL *ptr = ecalloc(sizeof(*ptr), max); + iERR err = ion_reader_get_annotation_symbols(obj->reader, ptr, max, &count); + if (!err) { + array_init_size(return_value, count); + for (int32_t i = 0; i < count; ++i) { + zval zsym; + php_ion_symbol_zval(&ptr[i], &zsym); + add_next_index_zval(return_value, &zsym); + } + } + efree(ptr); + ION_CHECK(err); +} +ZEND_METHOD(ion_Reader_Reader, countAnnotations) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + SIZE sz = 0; + ION_CHECK(ion_reader_get_annotation_count(obj->reader, &sz)); + RETURN_LONG(sz); +} +ZEND_METHOD(ion_Reader_Reader, getAnnotation) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_long idx; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(idx); + ZEND_PARSE_PARAMETERS_END(); + + ION_STRING ann; + ION_CHECK(ion_reader_get_an_annotation(obj->reader, idx, &ann)); + RETURN_STRINGL((char *) ann.value, ann.length); +} +ZEND_METHOD(ion_Reader_Reader, getAnnotationSymbol) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_long idx; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(idx); + ZEND_PARSE_PARAMETERS_END(); + + ION_SYMBOL sym; + ION_CHECK(ion_reader_get_an_annotation_symbol(obj->reader, idx, &sym)); + php_ion_symbol_zval(&sym, return_value); +} +ZEND_METHOD(ion_Reader_Reader, readNull) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_TYPE typ; + ION_CHECK(ion_reader_read_null(obj->reader, &typ)); + RETURN_OBJ_COPY(php_ion_type_fetch(typ)); +} +ZEND_METHOD(ion_Reader_Reader, readBool) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + BOOL b; + ION_CHECK(ion_reader_read_bool(obj->reader, &b)); + RETURN_BOOL(b); +} +ZEND_METHOD(ion_Reader_Reader, readInt) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + php_ion_unserialize_int(obj, return_value); +} +ZEND_METHOD(ion_Reader_Reader, readFloat) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_CHECK(ion_reader_read_double(obj->reader, &Z_DVAL_P(return_value))); +} +ZEND_METHOD(ion_Reader_Reader, readDecimal) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + object_init_ex(return_value, ce_Decimal); + php_ion_decimal *dec = php_ion_obj(decimal, Z_OBJ_P(return_value)); + ION_CHECK(ion_reader_read_ion_decimal(obj->reader, &dec->dec)); + php_ion_decimal_ctor(dec); +} +ZEND_METHOD(ion_Reader_Reader, readTimestamp) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + php_ion_unserialize_timestamp(obj, return_value); +} +ZEND_METHOD(ion_Reader_Reader, readSymbol) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_SYMBOL sym; + ION_CHECK(ion_reader_read_ion_symbol(obj->reader, &sym)); + php_ion_symbol_zval(&sym, return_value); +} +ZEND_METHOD(ion_Reader_Reader, readString) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_STRING str; + ION_CHECK(ion_reader_read_string(obj->reader, &str)); + RETURN_STRINGL((char *) str.value, str.length); +} + +typedef iERR (*read_part_fn)(ION_READER *, BYTE *, SIZE, SIZE *); +static void read_part(INTERNAL_FUNCTION_PARAMETERS, read_part_fn fn) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zval *ref; + zend_string *zstr; + zend_long len = 0x1000; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(ref) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(len) + ZEND_PARSE_PARAMETERS_END(); + + ZVAL_DEREF(ref); + + if (Z_TYPE_P(ref) == IS_STRING && Z_STRLEN_P(ref) == len) { + /* reuse */ + zstr = Z_STR_P(ref); + } else { + zval_dtor(ref); + zstr = zend_string_alloc(len, 0); + } + + SIZE read = 0; + ION_CHECK(fn(obj->reader, (BYTE *) zstr->val, zstr->len, &read), goto fail); + if (read > 0) { + if (read < zstr->len) { + zstr = zend_string_truncate(zstr, read, 0); + } + ZVAL_STR(ref, zstr); + RETURN_TRUE; + } +fail: + if (zstr != Z_STR_P(ref)) { + zend_string_release(zstr); + } + ZVAL_EMPTY_STRING(ref); + RETURN_FALSE; +} +ZEND_METHOD(ion_Reader_Reader, readStringPart) +{ + read_part(INTERNAL_FUNCTION_PARAM_PASSTHRU, ion_reader_read_partial_string); +} +ZEND_METHOD(ion_Reader_Reader, readLob) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + php_ion_unserialize_lob(obj, return_value); +} +ZEND_METHOD(ion_Reader_Reader, readLobPart) +{ + read_part(INTERNAL_FUNCTION_PARAM_PASSTHRU, ion_reader_read_lob_partial_bytes); +} +ZEND_METHOD(ion_Reader_Reader, getPosition) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + int64_t bytes = 0; + int32_t dummy; + ION_CHECK(ion_reader_get_position(obj->reader, &bytes, &dummy, &dummy)); + RETURN_LONG(bytes); +} +ZEND_METHOD(ion_Reader_Reader, getDepth) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + SIZE depth = 0; + ION_CHECK(ion_reader_get_depth(obj->reader, &depth)); + RETURN_LONG(depth); +} +ZEND_METHOD(ion_Reader_Reader, seek) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_long off, len = -1; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_LONG(off) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(len) + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_reader_seek(obj->reader, off, len)); +} +ZEND_METHOD(ion_Reader_Reader, getValueOffset) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + POSITION off = 0; + ION_CHECK(ion_reader_get_value_offset(obj->reader, &off)); + RETURN_LONG(off); +} +ZEND_METHOD(ion_Reader_Reader, getValueLength) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + SIZE len = 0; + ION_CHECK(ion_reader_get_value_length(obj->reader, &len)); + RETURN_LONG(len); +} +ZEND_METHOD(ion_Reader_Buffer_Reader, __construct) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + zend_string *zstr; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STR(zstr) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Reader_Options) + ZEND_PARSE_PARAMETERS_END(); + + obj->type = BUFFER_READER; + obj->buffer = zend_string_copy(zstr); + + php_ion_reader_ctor(obj); +} +ZEND_METHOD(ion_Reader_Buffer_Reader, getBuffer) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + RETURN_STR_COPY(obj->buffer); +} + +ZEND_METHOD(ion_Reader_Stream_Reader, __construct) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + zval *zstream; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(zstream) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Reader_Options) + ZEND_PARSE_PARAMETERS_END(); + + obj->type = STREAM_READER; + php_stream_from_zval_no_verify(obj->stream.ptr, zstream); + + php_ion_reader_ctor(obj); +} +ZEND_METHOD(ion_Reader_Stream_Reader, getStream) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + PTR_CHECK(obj->stream.ptr); + + GC_ADDREF(obj->stream.ptr->res); + RETURN_RES(obj->stream.ptr->res); +} +ZEND_METHOD(ion_Reader_Stream_Reader, resetStream) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zval *zstream; + ZEND_PARSE_PARAMETERS_START(1, 1); + Z_PARAM_RESOURCE(zstream); + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_reader_reset_stream(&obj->reader, obj, php_ion_reader_stream_handler)); + + if (obj->stream.ptr) { + zend_list_delete(obj->stream.ptr->res); + } + php_stream_from_zval_no_verify(obj->stream.ptr, zstream); + PTR_CHECK(obj->stream.ptr); + Z_ADDREF_P(zstream); +} +ZEND_METHOD(ion_Reader_Stream_Reader, resetStreamWithLength) +{ + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zval *zstream; + zend_long length; + ZEND_PARSE_PARAMETERS_START(1, 2); + Z_PARAM_RESOURCE(zstream); + Z_PARAM_LONG(length) + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_reader_reset_stream_with_length(&obj->reader, obj, php_ion_reader_stream_handler, length)); + + if (obj->stream.ptr) { + zend_list_delete(obj->stream.ptr->res); + } + php_stream_from_zval_no_verify(obj->stream.ptr, zstream); + PTR_CHECK(obj->stream.ptr); + Z_ADDREF_P(zstream); +} +ZEND_METHOD(ion_Writer_Options, __construct) +{ + php_ion_writer_options *obj = php_ion_obj(writer_options, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + zend_bool binary = false, compact_floats = false, escape = false, pretty = false, + tabs = true, small_cntr_inl = true, suppress_sys = false, flush = false; + zend_long indent = 2, max_depth = 10, max_ann = 10, temp = 0x400, alloc = 0x1000; + ZEND_PARSE_PARAMETERS_START(0, 16) + Z_PARAM_OPTIONAL + //public readonly ?\ion\Catalog $catalog = null, + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->cat, ce_Catalog) + //public readonly ?\ion\Collection $encodingSymbolTable = null, + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->col, ce_Collection) + //public readonly ?\ion\Decimal\Context $decimalContext = null, + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->dec_ctx, ce_Decimal_Context) + //public readonly bool $outputBinary = false, + Z_PARAM_BOOL(binary) + //public readonly bool $compactFloats = false, + Z_PARAM_BOOL(compact_floats) + //public readonly bool $escapeNonAscii = false, + Z_PARAM_BOOL(escape) + //public readonly bool $prettyPrint = false, + Z_PARAM_BOOL(pretty) + //public readonly bool $indentTabs = true, + Z_PARAM_BOOL(tabs) + //public readonly int $indentSize = 2, + Z_PARAM_LONG(indent) + //public readonly bool $smallContainersInline = true, + Z_PARAM_BOOL(small_cntr_inl) + //public readonly bool $suppressSystemValues = false, + Z_PARAM_BOOL(suppress_sys) + //public readonly bool $flushEveryValue = false, + Z_PARAM_BOOL(flush) + //public readonly int $maxContainerDepth = 10, + Z_PARAM_LONG(max_depth) + //public readonly int $maxAnnotations = 10, + Z_PARAM_LONG(max_ann) + //public readonly int $tempBufferSize = 0x400, + Z_PARAM_LONG(temp) + //public readonly int $allocationPageSize = 0x1000, + Z_PARAM_LONG(alloc) + ZEND_PARSE_PARAMETERS_END(); + + if (obj->cat) { + update_property_obj(&obj->std, ZEND_STRL("catalog"), obj->cat); + obj->opt.pcatalog = php_ion_obj(catalog, obj->cat)->cat; + } + if (obj->col) { + // TODO + } + if (obj->dec_ctx) { + update_property_obj(&obj->std, ZEND_STRL("decimalContext"), obj->dec_ctx); + obj->opt.decimal_context = &php_ion_obj(decimal_ctx, obj->dec_ctx)->ctx; + } + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("outputBinary"), + obj->opt.output_as_binary = binary); + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("comactFloats"), + obj->opt.compact_floats = compact_floats); + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("excapeNonAscii"), + obj->opt.escape_all_non_ascii = escape); + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("prettyPrint"), + obj->opt.pretty_print = pretty); + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("indentTabs"), + obj->opt.indent_with_tabs = tabs); + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("indentSize"), + obj->opt.indent_size = indent); + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("smallContainersInline"), + obj->opt.small_containers_in_line = small_cntr_inl); + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("suppressSystemValues"), + obj->opt.supress_system_values = suppress_sys); + zend_update_property_bool(obj->std.ce, &obj->std, ZEND_STRL("flushEveryValue"), + obj->opt.flush_every_value = flush); + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("maxContainerDepth"), + obj->opt.max_container_depth = max_depth); + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("maxAnnotations"), + obj->opt.max_annotation_count = max_ann); + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("tempBufferSize"), + obj->opt.temp_buffer_size = temp); + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("allocationPageSize"), + obj->opt.allocation_page_size = alloc); +} +ZEND_METHOD(ion_Writer_Writer, writeNull) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_CHECK(ion_writer_write_null(obj->writer)); +} +ZEND_METHOD(ion_Writer_Writer, writeTypedNull) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_object *typ_obj; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(typ_obj, ce_Type) + ZEND_PARSE_PARAMETERS_END(); + + php_ion_type *typ = php_ion_obj(type, typ_obj); + OBJ_CHECK(typ); + ION_CHECK(ion_writer_write_typed_null(obj->writer, php_ion_obj(type, typ)->typ)); +} +ZEND_METHOD(ion_Writer_Writer, writeBool) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_bool b; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_BOOL(b) + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_writer_write_bool(obj->writer, b)); +} +ZEND_METHOD(ion_Writer_Writer, writeInt) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_long l; + zend_string *s; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR_OR_LONG(s, l) + ZEND_PARSE_PARAMETERS_END(); + + if (s) { + ION_INT *i; + ION_CHECK(ion_int_alloc(obj->writer, &i)); + ION_CHECK(ion_int_from_chars(i, s->val, s->len)); + ION_CHECK(ion_writer_write_ion_int(obj->writer, i)); + ion_int_free(i); + } else { + ION_CHECK(ion_writer_write_int64(obj->writer, l)); + } +} +ZEND_METHOD(ion_Writer_Writer, writeFloat) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + double d; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_DOUBLE(d) + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_writer_write_double(obj->writer, d)); +} +ZEND_METHOD(ion_Writer_Writer, writeDecimal) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_object *dec_obj; + zend_string *dec_str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS_OR_STR(dec_obj, ce_Decimal, dec_str) + ZEND_PARSE_PARAMETERS_END(); + + if (dec_str) { + ION_STRING s; + ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&s, dec_str))); + } else { + php_ion_decimal *dec = php_ion_obj(decimal, dec_obj); + ION_CHECK(ion_writer_write_ion_decimal(obj->writer, &dec->dec)); + } +} +ZEND_METHOD(ion_Writer_Writer, writeTimestamp) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_object *ts_obj; + zend_string *ts_str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS_OR_STR(ts_obj, ce_Timestamp, ts_str) + ZEND_PARSE_PARAMETERS_END(); + + decContext *ctx = NULL; + if (obj->opt) { + ctx = php_ion_obj(reader_options, obj->opt)->opt.decimal_context; + } + + ION_TIMESTAMP tmp = {0}; + if (ts_str) { + SIZE used; + ION_CHECK(ion_timestamp_parse(&tmp, ts_str->val, ts_str->len, &used, ctx)); + } else { + php_ion_timestamp *ts = php_ion_obj(timestamp, ts_obj); + OBJ_CHECK(ts); + ion_timestamp_from_php(&tmp, ts, ctx); + } + ION_CHECK(ion_writer_write_timestamp(obj->writer, &tmp)); +} +ZEND_METHOD(ion_Writer_Writer, writeSymbol) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_object *sym_obj; + zend_string *sym_str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS_OR_STR(sym_obj, ce_Symbol, sym_str); + ZEND_PARSE_PARAMETERS_END(); + + if (sym_str) { + ION_STRING is; + ION_CHECK(ion_writer_write_symbol(obj->writer, ion_string_from_zend(&is, sym_str))); + } else { + php_ion_symbol *sym = php_ion_obj(symbol, sym_obj); + PTR_CHECK(sym); + ION_CHECK(ion_writer_write_ion_symbol(obj->writer, &sym->sym)); + } +} +ZEND_METHOD(ion_Writer_Writer, writeString) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_string *str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + ION_STRING is; + ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&is, str))); +} +ZEND_METHOD(ion_Writer_Writer, writeCLob) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_string *str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_writer_write_clob(obj->writer, (BYTE *) str->val, str->len)); +} +ZEND_METHOD(ion_Writer_Writer, writeBLob) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_string *str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_writer_write_blob(obj->writer, (BYTE *) str->val, str->len)); +} +ZEND_METHOD(ion_Writer_Writer, startLob) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_object *typ_obj; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(typ_obj, ce_Type) + ZEND_PARSE_PARAMETERS_END(); + + php_ion_type *typ = php_ion_obj(type, typ_obj); + OBJ_CHECK(typ); + ION_CHECK(ion_writer_start_lob(obj->writer, php_ion_obj(type, typ)->typ)); +} +ZEND_METHOD(ion_Writer_Writer, appendLob) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_string *str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + ION_CHECK(ion_writer_append_lob(obj->writer, (BYTE *) str->val, str->len)); +} +ZEND_METHOD(ion_Writer_Writer, finishLob) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_CHECK(ion_writer_finish_lob(obj->writer)); +} +ZEND_METHOD(ion_Writer_Writer, startContainer) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_object *typ_obj; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS(typ_obj, ce_Type) + ZEND_PARSE_PARAMETERS_END(); + + php_ion_type *typ = php_ion_obj(type, typ_obj); + OBJ_CHECK(typ); + ION_CHECK(ion_writer_start_container(obj->writer, php_ion_obj(type, typ)->typ)); +} +ZEND_METHOD(ion_Writer_Writer, finishContainer) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + ION_CHECK(ion_writer_finish_container(obj->writer)); +} +ZEND_METHOD(ion_Writer_Writer, writeFieldName) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zend_object *sym_obj; + zend_string *sym_str; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_OBJ_OF_CLASS_OR_STR(sym_obj, ce_Symbol, sym_str); + ZEND_PARSE_PARAMETERS_END(); + + if (sym_str) { + ION_STRING is; + ION_CHECK(ion_writer_write_field_name(obj->writer, ion_string_from_zend(&is, sym_str))); + } else { + php_ion_symbol *sym = php_ion_obj(symbol, sym_obj); + PTR_CHECK(sym); + ION_CHECK(ion_writer_write_field_name_symbol(obj->writer, &sym->sym)); + } +} +ZEND_METHOD(ion_Writer_Writer, writeAnnotation) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + zval *args; + unsigned argc; + ZEND_PARSE_PARAMETERS_START(1, -1) + Z_PARAM_VARIADIC('+', args, argc); + ZEND_PARSE_PARAMETERS_END(); + + for (unsigned i = 0; i < argc; ++i) { + switch (Z_TYPE(args[i])) { + case IS_STRING: + ION_STRING is; + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, Z_STR(args[i])))); + break; + + case IS_OBJECT: + ION_CHECK(ion_writer_add_annotation_symbol(obj->writer, &php_ion_obj(symbol, Z_OBJ(args[i]))->sym)); + break; + } + } +} +ZEND_METHOD(ion_Writer_Writer, getDepth) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + SIZE depth; + ION_CHECK(ion_writer_get_depth(obj->writer, &depth)); + RETURN_LONG(depth); +} +ZEND_METHOD(ion_Writer_Writer, flush) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + SIZE flushed; + ION_CHECK(ion_writer_flush(obj->writer, &flushed)); + if (obj->type == BUFFER_WRITER) { + smart_str_0(&obj->buffer.str); + } + RETURN_LONG(flushed); +} +ZEND_METHOD(ion_Writer_Writer, finish) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + SIZE flushed; + ION_CHECK(ion_writer_finish(obj->writer, &flushed)); + if (obj->type == BUFFER_WRITER) { + smart_str_0(&obj->buffer.str); + } + RETURN_LONG(flushed); +} +ZEND_METHOD(ion_Writer_Writer, writeOne) +{ +} +ZEND_METHOD(ion_Writer_Writer, writeAll) +{ +} +ZEND_METHOD(ion_Writer_Buffer_Writer, __construct) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + zval *ref; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(ref) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Writer_Options) + ZEND_PARSE_PARAMETERS_END(); + + obj->type = BUFFER_WRITER; + ZVAL_COPY(&obj->buffer.val, ref); + zval_dtor(Z_REFVAL_P(ref)); + + php_ion_writer_ctor(obj); +} +ZEND_METHOD(ion_Writer_Buffer_Writer, getBuffer) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + + RETVAL_STR(zend_string_dup(obj->buffer.str.s, 0)); +} +ZEND_METHOD(ion_Writer_Stream_Writer, __construct) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + PTR_CHECK(obj); + + zval *zstream; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(zstream) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Writer_Options) + ZEND_PARSE_PARAMETERS_END(); + + obj->type = STREAM_WRITER; + php_stream_from_zval_no_verify(obj->stream.ptr, zstream); + + php_ion_writer_ctor(obj); +} +ZEND_METHOD(ion_Writer_Stream_Writer, getStream) +{ + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS)); + OBJ_CHECK(obj); + + ZEND_PARSE_PARAMETERS_NONE(); + PTR_CHECK(obj->stream.ptr); + + GC_ADDREF(obj->stream.ptr->res); + RETURN_RES(obj->stream.ptr->res); +} + +ZEND_METHOD(ion_PHP_Serializer, __construct) +{ + zend_object *obj = Z_OBJ_P(ZEND_THIS); + + zend_object *writer_obj; + zend_bool call_magic = true; + zend_string *call_custom = NULL; + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_OBJ_OF_CLASS(writer_obj, ce_Writer) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(call_magic) + Z_PARAM_STR_OR_NULL(call_custom) + ZEND_PARSE_PARAMETERS_END(); + + update_property_obj(obj, ZEND_STRL("writer"), writer_obj); + zend_update_property_bool(obj->ce, obj, ZEND_STRL("callMagicSerialize"), + php_ion_obj(writer, writer_obj)->php.call_magic_serialize = call_magic); + if (call_custom) { + zend_update_property_str(obj->ce, obj, ZEND_STRL("callCustomSerialize"), call_custom); + php_ion_obj(writer, writer_obj)->php.custom_serialize = zend_string_tolower(call_custom); + } else { + zend_update_property_null(obj->ce, obj, ZEND_STRL("callCustomSerialize")); + } +} +ZEND_METHOD(ion_PHP_Serializer, __invoke) +{ + zend_object *obj = Z_OBJ_P(ZEND_THIS); + + zval *data; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(data) + ZEND_PARSE_PARAMETERS_END(); + + zval tmp, *zwriter; + if ((zwriter = zend_read_property(obj->ce, obj, ZEND_STRL("writer"), 0, &tmp))) { + if (Z_OBJCE_P(zwriter) == ce_Writer_Buffer_Writer || Z_OBJCE_P(zwriter) == ce_Writer_Stream_Writer) { + php_ion_writer *writer = php_ion_obj(writer, Z_OBJ_P(zwriter)); + php_ion_serialize(writer, data, &writer->buffer.val); + RETURN_STR_COPY(writer->buffer.str.s); + } else { + zend_call_method_with_1_params(obj, obj->ce, NULL /* TODO */, "serialize", return_value, data); + } + } +} +ZEND_METHOD(ion_PHP_Serializer, serialize) +{ + //zend_object *obj = Z_OBJ_P(ZEND_THIS); + + zval *data; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ZVAL(data) + ZEND_PARSE_PARAMETERS_END(); + + // TODO +} +ZEND_METHOD(ion_PHP_Unserializer, __construct) +{ + zend_object *obj = Z_OBJ_P(ZEND_THIS); + + zend_object *reader_obj; + zend_bool call_magic = true; + zend_string *call_custom = NULL; + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_OBJ_OF_CLASS(reader_obj, ce_Reader) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL(call_magic) + Z_PARAM_STR_OR_NULL(call_custom) + ZEND_PARSE_PARAMETERS_END(); + + update_property_obj(obj, ZEND_STRL("reader"), reader_obj); + zend_update_property_bool(obj->ce, obj, ZEND_STRL("callMagicUnserialize"), + php_ion_obj(reader, reader_obj)->php.call_magic_unserialize = call_magic); + if (call_custom) { + zend_update_property_str(obj->ce, obj, ZEND_STRL("callCustomUnserialize"), call_custom); + php_ion_obj(reader, reader_obj)->php.custom_unserialize = zend_string_tolower(call_custom); + } else { + zend_update_property_null(obj->ce, obj, ZEND_STRL("callCustomUnserialize")); + } +} +ZEND_METHOD(ion_PHP_Unserializer, __invoke) +{ + zend_object *obj = Z_OBJ_P(ZEND_THIS); + + zval zreader; + if (zend_read_property(obj->ce, obj, ZEND_STRL("reader"), 0, &zreader)) { + if (Z_OBJCE(zreader) == ce_Reader_Buffer_Reader || Z_OBJCE(zreader) == ce_Reader_Stream_Reader) { + php_ion_unserialize(php_ion_obj(reader, Z_OBJ(zreader)), NULL, return_value); + } else { + zend_call_method_with_0_params(obj, obj->ce, NULL /* TODO */, "unserialize", return_value); + } + } +} +ZEND_METHOD(ion_PHP_Unserializer, unserialize) +{ + //zend_object *obj = Z_OBJ_P(ZEND_THIS); + + ZEND_PARSE_PARAMETERS_NONE(); + + // TODO +} + +ZEND_FUNCTION(ion_serialize) +{ + zval *zv; + zend_object *zo_opt = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ZVAL(zv) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(zo_opt, ce_Writer_Options) + ZEND_PARSE_PARAMETERS_END(); + + zval zwriter; + object_init_ex(&zwriter, ce_Writer_Buffer_Writer); + + php_ion_writer *obj = php_ion_obj(writer, Z_OBJ(zwriter)); + obj->opt = zo_opt; + obj->type = BUFFER_WRITER; + + php_ion_writer_ctor(obj); + + php_ion_serialize(obj, zv, return_value); + zval_ptr_dtor(&zwriter); +} +ZEND_FUNCTION(ion_unserialize) +{ + zend_string *zstr; + zend_object *zo_opt = NULL; + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_STR(zstr) + Z_PARAM_OPTIONAL + Z_PARAM_OBJ_OF_CLASS_OR_NULL(zo_opt, ce_Reader_Options) + ZEND_PARSE_PARAMETERS_END(); + + zval zreader; + object_init_ex(&zreader, ce_Reader_Buffer_Reader); + + php_ion_reader *obj = php_ion_obj(reader, Z_OBJ(zreader)); + obj->opt = zo_opt; + obj->type = BUFFER_READER; + obj->buffer = zend_string_copy(zstr); + + php_ion_reader_ctor(obj); + php_ion_unserialize(obj, NULL, return_value); + zval_ptr_dtor(&zreader); +} + +PHP_RINIT_FUNCTION(ion) +{ +#if defined(ZTS) && defined(COMPILE_DL_ION) + ZEND_TSRMLS_CACHE_UPDATE(); +#endif + + php_ion_globals_serializer_init(); + php_ion_globals_unserializer_init(); + return SUCCESS; +} + +PHP_RSHUTDOWN_FUNCTION(ion) +{ + php_ion_globals_serializer_dtor(); + php_ion_globals_unserializer_dtor(); + return SUCCESS; +} + +php_ion_decl(type, Type); +php_ion_decl(symbol, Symbol, php_ion_symbol_dtor(obj)); +php_ion_decl(symbol_iloc, Symbol_ImportLocation, php_ion_symbol_iloc_dtor(obj)); +php_ion_decl(symbol_table, Symbol_Table); +php_ion_decl(decimal, Decimal, php_ion_decimal_dtor(obj)); +php_ion_decl(decimal_ctx, Decimal_Context); +php_ion_decl(timestamp, Timestamp, php_ion_timestamp_dtor(obj)); +php_ion_decl(catalog, Catalog); +php_ion_decl(reader_options, Reader_Options); +php_ion_decl(reader, Reader_Reader, php_ion_reader_dtor(obj)); +php_ion_decl(writer_options, Writer_Options); +php_ion_decl(writer, Writer_Writer, php_ion_writer_dtor(obj)); + +PHP_MINIT_FUNCTION(ion) +{ + ce_Annotation = register_class_ion_Annotation(); + + php_ion_register(type, Type); + php_ion_register(symbol, Symbol); + php_ion_register(symbol_iloc, Symbol_ImportLocation); + php_ion_register(symbol_table, Symbol_Table); + + ce_Symbol_System = register_class_ion_Symbol_System(); + ce_Symbol_System_SID = register_class_ion_Symbol_System_SID(); + + ce_Collection = register_class_ion_Collection(); + + php_ion_register(decimal, Decimal); + oh_decimal.get_properties_for = php_ion_decimal_get_props_for; + php_ion_register(decimal_ctx, Decimal_Context); + php_ion_register(timestamp, Timestamp, php_date_get_date_ce()); + php_ion_register(catalog, Catalog); + + ce_Reader = register_class_ion_Reader(spl_ce_RecursiveIterator); + + php_ion_register(reader_options, Reader_Options); + php_ion_register(reader, Reader_Reader, ce_Reader); + + ce_Reader_Buffer = register_class_ion_Reader_Buffer(ce_Reader); + ce_Reader_Buffer_Reader = register_class_ion_Reader_Buffer_Reader(ce_Reader_Reader, ce_Reader_Buffer); + ce_Reader_Stream = register_class_ion_Reader_Stream(ce_Reader); + ce_Reader_Stream_Reader = register_class_ion_Reader_Stream_Reader(ce_Reader_Reader, ce_Reader_Stream); + + ce_Writer = register_class_ion_Writer(); + + php_ion_register(writer_options, Writer_Options); + php_ion_register(writer, Writer_Writer, ce_Writer); + + ce_Writer_Buffer = register_class_ion_Writer_Buffer(ce_Writer); + ce_Writer_Buffer_Writer = register_class_ion_Writer_Buffer_Writer(ce_Writer_Writer, ce_Writer_Buffer); + ce_Writer_Stream = register_class_ion_Writer_Stream(ce_Writer); + ce_Writer_Stream_Writer = register_class_ion_Writer_Stream_Writer(ce_Writer_Writer, ce_Writer_Stream); + + ce_PHP_Serializer = register_class_ion_PHP_Serializer(); + ce_PHP_Unserializer = register_class_ion_PHP_Unserializer(); + + return SUCCESS; +} + +PHP_MINFO_FUNCTION(ion) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "ion support", "enabled"); + php_info_print_table_end(); +} + +PHP_GINIT_FUNCTION(ion) +{ + memset(ion_globals, 0, sizeof(*ion_globals)); +} +PHP_GSHUTDOWN_FUNCTION(ion) +{ +} + +static zend_module_dep ion_module_deps[] = { + ZEND_MOD_REQUIRED("spl") + ZEND_MOD_END +}; + +zend_module_entry ion_module_entry = { + STANDARD_MODULE_HEADER_EX, + NULL, + ion_module_deps, + "ion", /* Extension name */ + ext_functions, /* zend_function_entry */ + PHP_MINIT(ion), /* PHP_MINIT - Module initialization */ + NULL, /* PHP_MSHUTDOWN - Module shutdown */ + PHP_RINIT(ion), /* PHP_RINIT - Request initialization */ + PHP_RSHUTDOWN(ion), /* PHP_RSHUTDOWN - Request shutdown */ + PHP_MINFO(ion), /* PHP_MINFO - Module info */ + PHP_ION_VERSION, /* Version */ + ZEND_MODULE_GLOBALS(ion), + PHP_GINIT(ion), /* PHP_GINIT */ + PHP_GSHUTDOWN(ion), /* PHP_GSHUTDOWN */ + NULL, + STANDARD_MODULE_PROPERTIES_EX +}; + +#ifdef COMPILE_DL_ION +# ifdef ZTS +ZEND_TSRMLS_CACHE_DEFINE() +# endif +ZEND_GET_MODULE(ion) +#endif diff --git a/ion.stub.php b/ion.stub.php new file mode 100644 index 0000000..8225a1b --- /dev/null +++ b/ion.stub.php @@ -0,0 +1,446 @@ +ce_flags |= ZEND_ACC_ABSTRACT; + zend_class_implements(class_entry, 1, class_entry_ion_Reader); + + zend_string *property_options_class_ion_Reader_Options = zend_string_init("ion\\Reader\\Options", sizeof("ion\\Reader\\Options")-1, 1); + zval property_options_default_value; + ZVAL_UNDEF(&property_options_default_value); + zend_string *property_options_name = zend_string_init("options", sizeof("options") - 1, 1); + zend_declare_typed_property(class_entry, property_options_name, &property_options_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_options_class_ion_Reader_Options, 0, MAY_BE_NULL)); + zend_string_release(property_options_name); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Reader_Buffer(zend_class_entry *class_entry_ion_Reader) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Reader", "Buffer", class_ion_Reader_Buffer_methods); + class_entry = zend_register_internal_interface(&ce); + zend_class_implements(class_entry, 1, class_entry_ion_Reader); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Reader_Buffer_Reader(zend_class_entry *class_entry_ion_Reader_Reader, zend_class_entry *class_entry_ion_Reader_Buffer) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Reader\\Buffer", "Reader", class_ion_Reader_Buffer_Reader_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Reader_Reader); + zend_class_implements(class_entry, 1, class_entry_ion_Reader_Buffer); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Reader_Stream(zend_class_entry *class_entry_ion_Reader) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Reader", "Stream", class_ion_Reader_Stream_methods); + class_entry = zend_register_internal_interface(&ce); + zend_class_implements(class_entry, 1, class_entry_ion_Reader); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Reader_Stream_Reader(zend_class_entry *class_entry_ion_Reader_Reader, zend_class_entry *class_entry_ion_Reader_Stream) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Reader\\Stream", "Reader", class_ion_Reader_Stream_Reader_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Reader_Reader); + zend_class_implements(class_entry, 1, class_entry_ion_Reader_Stream); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Writer_Options(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Options", class_ion_Writer_Options_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + + zend_string *property_catalog_class_ion_Catalog = zend_string_init("ion\\Catalog", sizeof("ion\\Catalog")-1, 1); + zval property_catalog_default_value; + ZVAL_UNDEF(&property_catalog_default_value); + zend_string *property_catalog_name = zend_string_init("catalog", sizeof("catalog") - 1, 1); + zend_declare_typed_property(class_entry, property_catalog_name, &property_catalog_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_catalog_class_ion_Catalog, 0, MAY_BE_NULL)); + zend_string_release(property_catalog_name); + + zend_string *property_decimalContext_class_ion_Decimal_Context = zend_string_init("ion\\Decimal\\Context", sizeof("ion\\Decimal\\Context")-1, 1); + zval property_decimalContext_default_value; + ZVAL_UNDEF(&property_decimalContext_default_value); + zend_string *property_decimalContext_name = zend_string_init("decimalContext", sizeof("decimalContext") - 1, 1); + zend_declare_typed_property(class_entry, property_decimalContext_name, &property_decimalContext_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_decimalContext_class_ion_Decimal_Context, 0, MAY_BE_NULL)); + zend_string_release(property_decimalContext_name); + + zval property_outputBinary_default_value; + ZVAL_UNDEF(&property_outputBinary_default_value); + zend_string *property_outputBinary_name = zend_string_init("outputBinary", sizeof("outputBinary") - 1, 1); + zend_declare_typed_property(class_entry, property_outputBinary_name, &property_outputBinary_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_outputBinary_name); + + zval property_compactFloats_default_value; + ZVAL_UNDEF(&property_compactFloats_default_value); + zend_string *property_compactFloats_name = zend_string_init("compactFloats", sizeof("compactFloats") - 1, 1); + zend_declare_typed_property(class_entry, property_compactFloats_name, &property_compactFloats_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_compactFloats_name); + + zval property_escapeNonAscii_default_value; + ZVAL_UNDEF(&property_escapeNonAscii_default_value); + zend_string *property_escapeNonAscii_name = zend_string_init("escapeNonAscii", sizeof("escapeNonAscii") - 1, 1); + zend_declare_typed_property(class_entry, property_escapeNonAscii_name, &property_escapeNonAscii_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_escapeNonAscii_name); + + zval property_prettyPrint_default_value; + ZVAL_UNDEF(&property_prettyPrint_default_value); + zend_string *property_prettyPrint_name = zend_string_init("prettyPrint", sizeof("prettyPrint") - 1, 1); + zend_declare_typed_property(class_entry, property_prettyPrint_name, &property_prettyPrint_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_prettyPrint_name); + + zval property_indentTabs_default_value; + ZVAL_UNDEF(&property_indentTabs_default_value); + zend_string *property_indentTabs_name = zend_string_init("indentTabs", sizeof("indentTabs") - 1, 1); + zend_declare_typed_property(class_entry, property_indentTabs_name, &property_indentTabs_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_indentTabs_name); + + zval property_indentSize_default_value; + ZVAL_UNDEF(&property_indentSize_default_value); + zend_string *property_indentSize_name = zend_string_init("indentSize", sizeof("indentSize") - 1, 1); + zend_declare_typed_property(class_entry, property_indentSize_name, &property_indentSize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_indentSize_name); + + zval property_smallContainersInline_default_value; + ZVAL_UNDEF(&property_smallContainersInline_default_value); + zend_string *property_smallContainersInline_name = zend_string_init("smallContainersInline", sizeof("smallContainersInline") - 1, 1); + zend_declare_typed_property(class_entry, property_smallContainersInline_name, &property_smallContainersInline_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_smallContainersInline_name); + + zval property_suppressSystemValues_default_value; + ZVAL_UNDEF(&property_suppressSystemValues_default_value); + zend_string *property_suppressSystemValues_name = zend_string_init("suppressSystemValues", sizeof("suppressSystemValues") - 1, 1); + zend_declare_typed_property(class_entry, property_suppressSystemValues_name, &property_suppressSystemValues_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_suppressSystemValues_name); + + zval property_flushEveryValue_default_value; + ZVAL_UNDEF(&property_flushEveryValue_default_value); + zend_string *property_flushEveryValue_name = zend_string_init("flushEveryValue", sizeof("flushEveryValue") - 1, 1); + zend_declare_typed_property(class_entry, property_flushEveryValue_name, &property_flushEveryValue_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_flushEveryValue_name); + + zval property_maxContainerDepth_default_value; + ZVAL_UNDEF(&property_maxContainerDepth_default_value); + zend_string *property_maxContainerDepth_name = zend_string_init("maxContainerDepth", sizeof("maxContainerDepth") - 1, 1); + zend_declare_typed_property(class_entry, property_maxContainerDepth_name, &property_maxContainerDepth_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_maxContainerDepth_name); + + zval property_maxAnnotations_default_value; + ZVAL_UNDEF(&property_maxAnnotations_default_value); + zend_string *property_maxAnnotations_name = zend_string_init("maxAnnotations", sizeof("maxAnnotations") - 1, 1); + zend_declare_typed_property(class_entry, property_maxAnnotations_name, &property_maxAnnotations_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_maxAnnotations_name); + + zval property_tempBufferSize_default_value; + ZVAL_UNDEF(&property_tempBufferSize_default_value); + zend_string *property_tempBufferSize_name = zend_string_init("tempBufferSize", sizeof("tempBufferSize") - 1, 1); + zend_declare_typed_property(class_entry, property_tempBufferSize_name, &property_tempBufferSize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_tempBufferSize_name); + + zval property_allocationPageSize_default_value; + ZVAL_UNDEF(&property_allocationPageSize_default_value); + zend_string *property_allocationPageSize_name = zend_string_init("allocationPageSize", sizeof("allocationPageSize") - 1, 1); + zend_declare_typed_property(class_entry, property_allocationPageSize_name, &property_allocationPageSize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(property_allocationPageSize_name); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Writer(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion", "Writer", class_ion_Writer_methods); + class_entry = zend_register_internal_interface(&ce); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Writer_Writer(zend_class_entry *class_entry_ion_Writer) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Writer", class_ion_Writer_Writer_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_ABSTRACT; + zend_class_implements(class_entry, 1, class_entry_ion_Writer); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Writer_Buffer(zend_class_entry *class_entry_ion_Writer) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Buffer", class_ion_Writer_Buffer_methods); + class_entry = zend_register_internal_interface(&ce); + zend_class_implements(class_entry, 1, class_entry_ion_Writer); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Writer_Buffer_Writer(zend_class_entry *class_entry_ion_Writer_Writer, zend_class_entry *class_entry_ion_Writer_Buffer) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Writer\\Buffer", "Writer", class_ion_Writer_Buffer_Writer_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Writer_Writer); + zend_class_implements(class_entry, 1, class_entry_ion_Writer_Buffer); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Writer_Stream(zend_class_entry *class_entry_ion_Writer) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Writer", "Stream", class_ion_Writer_Stream_methods); + class_entry = zend_register_internal_interface(&ce); + zend_class_implements(class_entry, 1, class_entry_ion_Writer); + + return class_entry; +} + +static zend_class_entry *register_class_ion_Writer_Stream_Writer(zend_class_entry *class_entry_ion_Writer_Writer, zend_class_entry *class_entry_ion_Writer_Stream) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\Writer\\Stream", "Writer", class_ion_Writer_Stream_Writer_methods); + class_entry = zend_register_internal_class_ex(&ce, class_entry_ion_Writer_Writer); + zend_class_implements(class_entry, 1, class_entry_ion_Writer_Stream); + + return class_entry; +} + +static zend_class_entry *register_class_ion_PHP_Serializer(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\PHP", "Serializer", class_ion_PHP_Serializer_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + + zend_string *property_writer_class_ion_Writer = zend_string_init("ion\\Writer", sizeof("ion\\Writer")-1, 1); + zval property_writer_default_value; + ZVAL_UNDEF(&property_writer_default_value); + zend_string *property_writer_name = zend_string_init("writer", sizeof("writer") - 1, 1); + zend_declare_typed_property(class_entry, property_writer_name, &property_writer_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_writer_class_ion_Writer, 0, 0)); + zend_string_release(property_writer_name); + + zval property_callMagicSerialize_default_value; + ZVAL_UNDEF(&property_callMagicSerialize_default_value); + zend_string *property_callMagicSerialize_name = zend_string_init("callMagicSerialize", sizeof("callMagicSerialize") - 1, 1); + zend_declare_typed_property(class_entry, property_callMagicSerialize_name, &property_callMagicSerialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_callMagicSerialize_name); + + zval property_callCustomSerialize_default_value; + ZVAL_UNDEF(&property_callCustomSerialize_default_value); + zend_string *property_callCustomSerialize_name = zend_string_init("callCustomSerialize", sizeof("callCustomSerialize") - 1, 1); + zend_declare_typed_property(class_entry, property_callCustomSerialize_name, &property_callCustomSerialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string_release(property_callCustomSerialize_name); + + return class_entry; +} + +static zend_class_entry *register_class_ion_PHP_Unserializer(void) +{ + zend_class_entry ce, *class_entry; + + INIT_NS_CLASS_ENTRY(ce, "ion\\PHP", "Unserializer", class_ion_PHP_Unserializer_methods); + class_entry = zend_register_internal_class_ex(&ce, NULL); + + zend_string *property_reader_class_ion_Reader = zend_string_init("ion\\Reader", sizeof("ion\\Reader")-1, 1); + zval property_reader_default_value; + ZVAL_UNDEF(&property_reader_default_value); + zend_string *property_reader_name = zend_string_init("reader", sizeof("reader") - 1, 1); + zend_declare_typed_property(class_entry, property_reader_name, &property_reader_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_CLASS(property_reader_class_ion_Reader, 0, 0)); + zend_string_release(property_reader_name); + + zval property_callMagicUnserialize_default_value; + ZVAL_UNDEF(&property_callMagicUnserialize_default_value); + zend_string *property_callMagicUnserialize_name = zend_string_init("callMagicUnserialize", sizeof("callMagicUnserialize") - 1, 1); + zend_declare_typed_property(class_entry, property_callMagicUnserialize_name, &property_callMagicUnserialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_BOOL)); + zend_string_release(property_callMagicUnserialize_name); + + zval property_callCustomUnserialize_default_value; + ZVAL_UNDEF(&property_callCustomUnserialize_default_value); + zend_string *property_callCustomUnserialize_name = zend_string_init("callCustomUnserialize", sizeof("callCustomUnserialize") - 1, 1); + zend_declare_typed_property(class_entry, property_callCustomUnserialize_name, &property_callCustomUnserialize_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING|MAY_BE_NULL)); + zend_string_release(property_callCustomUnserialize_name); + + return class_entry; +} diff --git a/ion_private.h b/ion_private.h new file mode 100644 index 0000000..0192e14 --- /dev/null +++ b/ion_private.h @@ -0,0 +1,1486 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: ion | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2021, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#include "ionc/ion.h" + +#include "php.h" +#include "ext/date/php_date.h" + +typedef struct php_ion_global_serializer php_ion_global_serializer; +typedef struct php_ion_global_unserializer php_ion_global_unserializer; + +ZEND_BEGIN_MODULE_GLOBALS(ion) + + struct php_ion_global_serializer { + HashTable ids; + HashTable tmp; + uint64_t level; + } serializer; + + struct php_ion_global_unserializer { + HashTable ids; + HashTable tmp; + uint64_t level; + } unserializer; + +ZEND_END_MODULE_GLOBALS(ion); + +#ifdef ZTS +# define php_ion_globals (*((zend_ion_globals *) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(ion_globals_id)])) +#else +# define php_ion_globals ion_globals +#endif + +ZEND_DECLARE_MODULE_GLOBALS(ion); + +static inline void php_ion_globals_serializer_init(void) +{ + php_ion_global_serializer *s = &php_ion_globals.serializer; + + zend_hash_init(&s->tmp, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(&s->ids, 0, NULL, NULL, 0); +} + +static inline void php_ion_globals_serializer_step(void) +{ + php_ion_global_serializer *s = &php_ion_globals.serializer; + + if (!s->level++) { + zend_hash_clean(&s->ids); + zend_hash_clean(&s->tmp); + } +} + +static inline void php_ion_globals_serializer_exit(void) +{ + php_ion_global_serializer *s = &php_ion_globals.serializer; + + ZEND_ASSERT(s->level); + if (!--s->level) { + zend_hash_clean(&s->ids); + zend_hash_clean(&s->tmp); + } +} + +static inline void php_ion_globals_serializer_dtor(void) +{ + php_ion_global_serializer *s = &php_ion_globals.serializer; + + zend_hash_destroy(&s->tmp); + zend_hash_destroy(&s->ids); +} + +static inline void php_ion_globals_unserializer_init(void) +{ + php_ion_global_unserializer *s = &php_ion_globals.unserializer; + + zend_hash_init(&s->tmp, 0, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(&s->ids, 0, NULL, NULL, 0); +} + +static inline void php_ion_globals_unserializer_step(void) +{ + php_ion_global_unserializer *s = &php_ion_globals.unserializer; + + if (!s->level++) { + zend_hash_clean(&s->ids); + zend_hash_clean(&s->tmp); + } +} + +static inline void php_ion_globals_unserializer_exit(void) +{ + php_ion_global_unserializer *s = &php_ion_globals.unserializer; + + ZEND_ASSERT(s->level); + if (!--s->level) { + zend_hash_clean(&s->ids); + zend_hash_clean(&s->tmp); + } +} + +static inline void php_ion_globals_unserializer_dtor(void) +{ + php_ion_global_unserializer *s = &php_ion_globals.unserializer; + + zend_hash_destroy(&s->tmp); + zend_hash_destroy(&s->ids); +} + +static zend_class_entry + *ce_Annotation, + *ce_Catalog, + *ce_Collection, + *ce_Decimal, + *ce_Decimal_Context, + *ce_PHP_Serializer, + *ce_PHP_Unserializer, + *ce_Reader, + *ce_Reader_Options, + *ce_Reader_Reader, + *ce_Reader_Buffer, + *ce_Reader_Stream, + *ce_Reader_Buffer_Reader, + *ce_Reader_Stream_Reader, + *ce_Symbol, + *ce_Symbol_ImportLocation, + *ce_Symbol_System, + *ce_Symbol_System_SID, + *ce_Symbol_Table, + *ce_Timestamp, + *ce_Type, + *ce_Writer, + *ce_Writer_Options, + *ce_Writer_Buffer, + *ce_Writer_Buffer_Writer, + *ce_Writer_Stream, + *ce_Writer_Stream_Writer, + *ce_Writer_Writer + ; +static zend_object_handlers + oh_catalog, + oh_decimal, + oh_decimal_ctx, + oh_reader_options, + oh_reader, + oh_symbol, + oh_symbol_iloc, + oh_symbol_table, + oh_timestamp, + oh_type, + oh_writer_options, + oh_writer + ; + +#define php_ion_decl(type, name, ...) \ + static zend_object *create_ion_ ## name(zend_class_entry *ce) \ + { \ + if (!ce) ce = ce_ ## name; \ + php_ion_ ## type *o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce)); \ + zend_object_std_init(&o->std, ce); \ + object_properties_init(&o->std, ce); \ + o->std.handlers = &oh_ ## type; \ + return &o->std; \ + } \ + static void free_ion_ ## name(zend_object *std) \ + { \ + php_ion_ ## type *obj = php_ion_obj(type, std); \ + __VA_ARGS__; \ + zend_object_std_dtor(std); \ + (void) obj; \ + } +#define php_ion_register(type, name, ...) do { \ + ce_ ## name = register_class_ion_ ## name(__VA_ARGS__); \ + ce_ ## name ->create_object = create_ion_ ## name; \ + memcpy(&oh_ ## type, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); \ + oh_ ## type .offset = offsetof(php_ion_ ## type, std); \ + oh_ ## type .free_obj = free_ion_ ## name; \ +} while (0) + +#define php_ion_obj(type, obj) \ + ((php_ion_ ## type *) (obj ? ((char *)(obj) - XtOffsetOf(php_ion_ ## type, std)) : NULL)) + +#define ION_CHECK(err, ...) do { \ + iERR __err = err; \ + if (__err) { \ + zend_throw_exception_ex(spl_ce_RuntimeException, __err, "%s: %s", ion_error_to_str(__err), #err); \ + __VA_ARGS__; \ + return; \ + } \ +} while (0) + +#define ION_CATCH(...) do { \ + if (EG(exception)) { \ + __VA_ARGS__; \ + return; \ + } \ +} while (0) + +#define PTR_CHECK(ptr, ...) do { \ + if (!(ptr)) { \ + zend_throw_error(NULL, "Uninitialized object"); \ + __VA_ARGS__; \ + return; \ + } \ +} while (0) + +#define OBJ_CHECK(obj) do { \ + PTR_CHECK(obj); \ + PTR_CHECK(*((void **)obj)); \ +} while (0) + +static inline ION_STRING *ion_string_from_cstr(ION_STRING *is, const char *s, size_t l) +{ + is->length = l; + is->value = (BYTE *) s; + return is; +} + +static inline ION_STRING *ion_string_from_zend(ION_STRING *is, const zend_string *zs) +{ + is->length = ZSTR_LEN(zs); + is->value = (BYTE *) ZSTR_VAL(zs); + return is; +} + +static inline zend_string *zend_string_from_ion(const ION_STRING *s) +{ + return zend_string_init((const char *) s->value, s->length, 0); +} + +static inline void update_property_obj(zend_object *obj, const char *n, size_t l, zend_object *p) +{ + zval zobj; + ZVAL_OBJ(&zobj, p); + zend_update_property(obj->ce, obj, n, l, &zobj); +} + +typedef struct php_ion_type { + ION_TYPE typ; + zend_object std; +} php_ion_type; + +#define RETURN_IONTYPE(typ) do { \ + zend_object *__zo = php_ion_type_fetch(typ); \ + if (UNEXPECTED(!__zo)) { \ + RETURN_THROWS(); \ + } \ + RETURN_OBJ_COPY(__zo); \ +} while(0) + +static inline zend_object *php_ion_type_fetch(ION_TYPE typ) +{ + zend_long index = ION_TYPE_INT(typ); + zval *ztype = zend_hash_index_find(ce_Type->backed_enum_table, index); + + if (UNEXPECTED(!ztype || Z_TYPE_P(ztype) != IS_STRING)) { + zend_value_error(ZEND_LONG_FMT " is not a valid backing value for enum \"%s\"", index, ZSTR_VAL(ce_Type->name)); + return NULL; + } + return zend_enum_get_case(ce_Type, Z_STR_P(ztype)); +} + +typedef struct php_ion_symbol_iloc { + ION_SYMBOL_IMPORT_LOCATION loc; + zend_string *name; + zend_object std; +} php_ion_symbol_iloc; + +static inline void php_ion_symbol_iloc_ctor(php_ion_symbol_iloc *obj) +{ + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("location"), obj->loc.location); + zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("name"), obj->name); + ion_string_from_zend(&obj->loc.name, obj->name); +} + +static inline void php_ion_symbol_iloc_dtor(php_ion_symbol_iloc *obj) +{ + zend_string_release(obj->name); +} + +typedef struct php_ion_symbol { + ION_SYMBOL sym; + zend_string *value; + zend_object *iloc, std; +} php_ion_symbol; + +static inline void php_ion_symbol_ctor(php_ion_symbol *obj) +{ + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("sid"), + obj->sym.sid); + zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("value"), obj->value); + ion_string_from_zend(&obj->sym.value, obj->value); + if (obj->iloc) { + update_property_obj(&obj->std, ZEND_STRL("importLocation"), obj->iloc); + obj->sym.import_location = php_ion_obj(symbol_iloc, obj->iloc)->loc; + } else { + zend_update_property_null(obj->std.ce, &obj->std, ZEND_STRL("importLocation")); + } +} + +static inline void php_ion_symbol_dtor(php_ion_symbol *obj) +{ + zend_string_release(obj->value); +} + +static inline void php_ion_symbol_zval(ION_SYMBOL *sym_ptr, zval *return_value) +{ + object_init_ex(return_value, ce_Symbol); + php_ion_symbol *sym = php_ion_obj(symbol, Z_OBJ_P(return_value)); + + sym->sym.sid = sym_ptr->sid; + sym->value = zend_string_from_ion(&sym_ptr->value); + if (!ION_SYMBOL_IMPORT_LOCATION_IS_NULL(sym_ptr)) { + zval ziloc; + object_init_ex(&ziloc, ce_Symbol_ImportLocation); + sym->iloc = Z_OBJ(ziloc); + + php_ion_symbol_iloc *iloc = php_ion_obj(symbol_iloc, sym->iloc); + iloc->loc.location = sym_ptr->import_location.location; + iloc->name = zend_string_from_ion(&sym_ptr->import_location.name); + + php_ion_symbol_iloc_ctor(iloc); + } + + php_ion_symbol_ctor(sym); +} + +typedef struct php_ion_symbol_table { + zend_object std; +} php_ion_symbol_table; + +typedef struct php_ion_decimal_ctx { + decContext ctx; + zend_object std; +} php_ion_decimal_ctx; + +typedef struct php_ion_decimal { + ION_DECIMAL dec; + zend_object *ctx, std; +} php_ion_decimal; + +static inline void php_ion_decimal_ctor(php_ion_decimal *obj) +{ + if (obj->ctx) { + update_property_obj(&obj->std, ZEND_STRL("context"), obj->ctx); + } else { + zend_update_property_null(obj->std.ce, &obj->std, ZEND_STRL("context")); + } +} + +static inline void php_ion_decimal_dtor(php_ion_decimal *obj) +{ + ion_decimal_free(&obj->dec); +} + +static inline zend_string *php_ion_decimal_to_string(ION_DECIMAL *dec) +{ + zend_string *zstr = zend_string_alloc(ION_DECIMAL_STRLEN(dec), 0); + (void) ion_decimal_to_string(dec, zstr->val); + return zend_string_truncate(zstr, strlen(zstr->val), 0); +} + +static zend_array *php_ion_decimal_get_props_for(zend_object *object, zend_prop_purpose purpose) +{ + php_ion_decimal *obj = php_ion_obj(decimal, object); + + switch (purpose) { + case ZEND_PROP_PURPOSE_DEBUG: + zend_array *arr = zend_new_array(1); + zval *zv = zend_hash_str_add_empty_element(arr, ZEND_STRL("value")); + ZVAL_STR(zv, php_ion_decimal_to_string(&obj->dec)); + return arr; + + default: + return zend_std_get_properties_for(object, purpose); + } +} + +typedef php_date_obj php_ion_timestamp; + +static inline void php_ion_timestamp_ctor(php_ion_timestamp *obj, zend_long precision, zend_string *fmt, zend_string *dt, zval *tz) +{ + if (!obj->time) { + php_date_initialize(obj, dt ? dt->val : "now", dt ? dt->len : 3, fmt ? fmt->val : NULL, tz, PHP_DATE_INIT_CTOR); + } + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("precision"), precision); + if (fmt) { + zend_update_property_str(obj->std.ce, &obj->std, ZEND_STRL("format"), fmt); + } else { + zend_update_property_stringl(obj->std.ce, &obj->std, ZEND_STRL("format"), ZEND_STRL("c")); + } +} + +static inline void php_ion_timestamp_dtor(php_ion_timestamp *obj) +{ + if (obj->time) { + timelib_time_dtor(obj->time); + } +} + +static inline zend_long php_usec_from_ion(const decQuad *frac, decContext *ctx) +{ + decQuad microsecs, result; + decQuadMultiply(&result, decQuadFromInt32(µsecs, 1000000), frac, ctx); + return (zend_long) decQuadToUInt32(&result, ctx, DEC_ROUND_HALF_EVEN); +} + +static inline decQuad *ion_ts_frac_from_usec(decQuad *frac, zend_long usec, decContext *ctx) +{ + decQuad microsecs, us; + return decQuadDivide(frac, decQuadFromInt32(&us, usec), decQuadFromInt32(µsecs, 1000000), ctx); +} + +static inline timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContext *ctx, zend_string **fmt) +{ + timelib_time *time = timelib_time_ctor(); + + switch (ts->precision) { + case ION_TS_FRAC: + time->us = php_usec_from_ion(&ts->fraction, ctx); + if (fmt) *fmt = zend_string_init(ZEND_STRL("c"), 0); + /* fallthrough */ + case ION_TS_SEC: + time->s = ts->seconds; + if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\TH:i:sP"), 0); + /* fallthrough */ + case ION_TS_MIN: + time->i = ts->minutes; + time->h = ts->hours; + if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\TH:iP"), 0); + /* fallthrough */ + case ION_TS_DAY: + time->d = ts->day; + if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m-d\\T"), 0); + /* fallthrough */ + case ION_TS_MONTH: + time->m = ts->month; + if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y-m\\T"), 0); + /* fallthrough */ + case ION_TS_YEAR: + time->y = ts->year; + if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("Y\\T"), 0); + /* fallthrough */ + default: + if (fmt && !*fmt) *fmt = zend_string_init(ZEND_STRL("c"), 0); + time->z = ts->tz_offset * 60; + } + + return time; +} + +static inline ION_TIMESTAMP *ion_timestamp_from_php(ION_TIMESTAMP *buf, php_ion_timestamp *ts, decContext *ctx) +{ + memset(buf, 0, sizeof(*buf)); + + zval tmp; + uint8_t precision = Z_LVAL_P(zend_read_property(ts->std.ce, &ts->std, ZEND_STRL("precision"), 0, &tmp)); + + if (!precision || precision > ION_TS_FRAC) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG, + "Invalid precision (%u) of ion\\Timestamp", (unsigned) precision); + } else switch ((buf->precision = precision)) { + case ION_TS_FRAC: + ion_ts_frac_from_usec(&buf->fraction, ts->time->us, ctx); + /* fallthrough */ + case ION_TS_SEC: + buf->seconds = ts->time->s; + /* fallthrough */ + case ION_TS_MIN: + buf->minutes = ts->time->i; + /* fallthrough */ + case ION_TS_DAY: + buf->hours = ts->time->h; + buf->day = ts->time->d; + /* fallthrough */ + case ION_TS_MONTH: + buf->month = ts->time->m; + /* fallthrough */ + case ION_TS_YEAR: + buf->year = ts->time->y; + /* fallthrough */ + default: + buf->tz_offset = ts->time->z / 60; + } + + return buf; +} + +typedef struct php_ion_catalog { + ION_CATALOG *cat; + zend_object std; +} php_ion_catalog; + +typedef struct php_ion_reader_options { + ION_READER_OPTIONS opt; + zend_object *cat, *dec_ctx, *cb, std; +} php_ion_reader_options; + +typedef struct php_ion_reader { + ION_READER *reader; + ION_TYPE state; + enum { + BUFFER_READER, + STREAM_READER, + } type; + union { + zend_string *buffer; + struct { + php_stream *ptr; + ION_STRING buf; + } stream; + }; + struct { + zend_bool call_magic_unserialize; + zend_string *custom_unserialize; + } php; + zend_object *opt, std; +} php_ion_reader; + +static iERR php_ion_reader_stream_handler(struct _ion_user_stream *user) +{ + php_ion_reader *reader = (php_ion_reader *) user->handler_state; + size_t remaining = 0, spare = reader->stream.buf.length; + + if (user->curr && user->limit && (remaining = user->limit - user->curr)) { + memmove(reader->stream.buf.value, user->curr, remaining); + user->limit -= remaining; + spare -= remaining; + } else { + user->curr = user->limit = reader->stream.buf.value; + } + + ssize_t read = php_stream_read(reader->stream.ptr, (char *) user->limit, spare); + if (EXPECTED(read > 0)) { + user->limit += read; + return IERR_OK; + } + + if (EXPECTED(read == 0)) { + return IERR_EOF; + } + + return IERR_READ_ERROR; +} + +static iERR on_context_change(void *context, ION_COLLECTION *imports) +{ + if (context) { + php_ion_reader *obj = php_ion_obj(reader, context); + (void) obj; + } + return IERR_OK; +} + +static ION_READER_CONTEXT_CHANGE_NOTIFIER EMPTY_READER_CHANGE_NOTIFIER = { + on_context_change, + NULL +}; + +static inline void php_ion_reader_ctor(php_ion_reader *obj) +{ + iERR err; + php_ion_reader_options *opt = php_ion_obj(reader_options, obj->opt); + + if (opt) { + opt->opt.context_change_notifier.context = obj; + } + if (obj->type == STREAM_READER) { + PTR_CHECK(obj->stream.ptr); + GC_ADDREF(obj->stream.ptr->res); + + php_ion_reader_options *opt = php_ion_obj(reader_options, obj->opt); + obj->stream.buf.length = opt ? opt->opt.allocation_page_size : 0x1000; + obj->stream.buf.value = emalloc(obj->stream.buf.length); + err = ion_reader_open_stream(&obj->reader, obj, php_ion_reader_stream_handler, opt ? &opt->opt : NULL); + + } else { + err = ion_reader_open_buffer(&obj->reader, + (BYTE *) obj->buffer->val, obj->buffer->len, + opt ? &opt->opt : NULL); + } + if (opt) { + opt->opt.context_change_notifier.context = NULL; + } + + ION_CHECK(err); + OBJ_CHECK(obj); +} +static inline void php_ion_reader_dtor(php_ion_reader *obj) +{ + if (obj->reader) { + ion_reader_close(obj->reader); + } + if (obj->type == STREAM_READER) { + if (obj->stream.buf.value) { + efree(obj->stream.buf.value); + } + if (obj->stream.ptr) { + zend_list_delete(obj->stream.ptr->res); + } + } else { + if (obj->buffer) { + zend_string_release(obj->buffer); + } + } +} + +typedef struct php_ion_writer_options { + ION_WRITER_OPTIONS opt; + zend_object *cat, *dec_ctx, *col, std; +} php_ion_writer_options; + +typedef struct php_ion_writer { + ION_WRITER *writer; + enum { + BUFFER_WRITER, + STREAM_WRITER, + } type; + union { + struct { + zval val; + smart_str str; + } buffer; + struct { + ION_STRING buf; + php_stream *ptr; + } stream; + }; + struct { + zend_bool call_magic_serialize; + zend_string *custom_serialize; + } php; + zend_object *opt, std; + +} php_ion_writer; + +static iERR php_ion_writer_stream_handler(struct _ion_user_stream *user) +{ + php_ion_writer *writer = (php_ion_writer *) user->handler_state; + + if (EXPECTED(user->limit && user->curr)) { + ptrdiff_t len = user->curr - writer->stream.buf.value; + if (len != php_stream_write(writer->stream.ptr, (char *) writer->stream.buf.value, len)) { + return IERR_WRITE_ERROR; + } + } + user->curr = writer->stream.buf.value; + user->limit = writer->stream.buf.value + writer->stream.buf.length; + return IERR_OK; +} + +#define REF_STR() do { \ + ZVAL_NEW_STR(ref, obj->buffer.str.s); \ + GC_ADDREF(obj->buffer.str.s); \ +} while (0) + +#define NEW_REF_STR() do {\ + if (Z_STR_P(ref) != obj->buffer.str.s) { \ + zval_ptr_dtor(ref); \ + REF_STR(); \ + } \ +} while(0) + +static inline void php_ion_writer_stream_init(php_ion_writer *obj, php_ion_writer_options *opt) +{ + PTR_CHECK(obj->stream.ptr); + GC_ADDREF(obj->stream.ptr->res); + + obj->stream.buf.length = opt ? opt->opt.allocation_page_size : 0x1000; + obj->stream.buf.value = emalloc(obj->stream.buf.length); +} +static inline void php_ion_writer_buffer_init(php_ion_writer *obj) +{ + zval *ref = &obj->buffer.val; + ZVAL_DEREF(ref); + + smart_str_alloc(&obj->buffer.str, 0, 0); + smart_str_0(&obj->buffer.str); + REF_STR(); +} + +static inline void php_ion_writer_buffer_grow(php_ion_writer *obj) +{ + zval *ref = &obj->buffer.val; + ZVAL_DEREF(ref); + + switch (GC_REFCOUNT(obj->buffer.str.s)) { + case 2: + // nothing to do + break; + case 1: + // we've been separated + GC_ADDREF(obj->buffer.str.s); + break; + default: + // we have to separate + fprintf(stderr, "SEPARATE\n"); + obj->buffer.str.s = zend_string_dup(obj->buffer.str.s, 0); + break; + } + + zend_string *old = obj->buffer.str.s; + GC_DELREF(old); + smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1); + if (old == obj->buffer.str.s) { + GC_ADDREF(old); + } else if(old == Z_STR_P(ref)) { + ZVAL_NULL(ref); + } + + NEW_REF_STR(); +} + +static iERR php_ion_writer_buffer_handler(struct _ion_user_stream *user) +{ + php_ion_writer *writer = (php_ion_writer *) user->handler_state; + + if (user->curr) { + writer->buffer.str.s->len += user->curr - (BYTE *) &writer->buffer.str.s->val[writer->buffer.str.s->len]; + smart_str_0(&writer->buffer.str); + if (user->limit == user->curr) { + php_ion_writer_buffer_grow(writer); + } + } + user->curr = (BYTE *) &writer->buffer.str.s->val[writer->buffer.str.s->len]; + user->limit = user->curr + writer->buffer.str.a - writer->buffer.str.s->len; + + return IERR_OK; +} + +static inline void php_ion_writer_ctor(php_ion_writer *obj) +{ + if (obj->opt) { + update_property_obj(&obj->std, ZEND_STRL("options"), obj->opt); + } + + php_ion_writer_options *opt = php_ion_obj(writer_options, obj->opt); + ION_STREAM_HANDLER h; + if (obj->type == STREAM_WRITER) { + h = php_ion_writer_stream_handler; + php_ion_writer_stream_init(obj, opt); + } else { + h = php_ion_writer_buffer_handler; + php_ion_writer_buffer_init(obj); + } + + ION_CHECK(ion_writer_open_stream(&obj->writer, h, obj, opt ? &opt->opt : NULL)); + OBJ_CHECK(obj); +} + +static inline void php_ion_writer_dtor(php_ion_writer *obj) +{ + if (obj->writer) { + ion_writer_close(obj->writer); + } + if (obj->type == STREAM_WRITER) { + if (obj->stream.buf.value) { + efree(obj->stream.buf.value); + } + if (obj->stream.ptr) { + zend_list_delete(obj->stream.ptr->res); + } + } else { + smart_str_0(&obj->buffer.str); + zend_string_release(obj->buffer.str.s); + zval_ptr_dtor(&obj->buffer.val); + } + if (obj->php.custom_serialize) { + zend_string_release(obj->php.custom_serialize); + } +} + +static inline void php_ion_serialize_zval(php_ion_writer *, zval *); + +static inline void php_ion_serialize_struct(php_ion_writer *obj, zend_array *arr) +{ + ION_CHECK(ion_writer_start_container(obj->writer, tid_STRUCT)); + + zval *v; + zend_ulong h; + zend_string *k = NULL; + if (arr) ZEND_HASH_FOREACH_KEY_VAL_IND(arr, h, k, v) + ION_STRING is; + if (k) { + ION_CHECK(ion_writer_write_field_name(obj->writer, ion_string_from_zend(&is, k))); + } else { + char buf[MAX_LENGTH_OF_LONG + 1], *ptr = zend_print_ulong_to_buf(buf + sizeof(buf), h); + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("i")))); + ION_CHECK(ion_writer_write_field_name(obj->writer, ion_string_from_cstr(&is, ptr, buf - ptr))); + } + + php_ion_serialize_zval(obj, v); + ION_CATCH(); + ZEND_HASH_FOREACH_END(); + + ION_CHECK(ion_writer_finish_container(obj->writer)); +} + +static inline void php_ion_serialize_list(php_ion_writer *obj, zend_array *arr) +{ + ION_CHECK(ion_writer_start_container(obj->writer, tid_LIST)); + + zval *v; + ZEND_HASH_FOREACH_VAL_IND(arr, v) + php_ion_serialize_zval(obj, v); + ION_CATCH(); + ZEND_HASH_FOREACH_END(); + + ION_CHECK(ion_writer_finish_container(obj->writer)); +} + +static inline void php_ion_serialize_array(php_ion_writer *obj, zend_array *arr) +{ + if (zend_array_is_list(arr)) { + php_ion_serialize_list(obj, arr); + } else { + php_ion_serialize_struct(obj, arr); + } +} + +static inline void php_ion_serialize_object_iface(php_ion_writer *obj, zend_object *zobject) +{ + uint8_t *buf; + size_t len; + zval tmp; + + ZVAL_OBJ(&tmp, zobject); + if (SUCCESS == zobject->ce->serialize(&tmp, &buf, &len, NULL)) { + ION_STRING is; + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("S")))); + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, zobject->ce->name))); + ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_cstr(&is, (char *) buf, len))); + efree(buf); + } else if (!EG(exception)){ + zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR, + "Failed to serialize class %s", zobject->ce->name->val); + } +} + +static inline void php_ion_serialize_object_magic(php_ion_writer *obj, zend_object *zobject, zend_function *fn) +{ + zval rv; + + ZVAL_NULL(&rv); + zend_call_method_with_0_params(zobject, zobject->ce, fn ? &fn : &zobject->ce->__serialize, "", &rv); + ION_CATCH(); + + if (IS_ARRAY == Z_TYPE(rv)) { + ION_STRING is; + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL(fn ? "C" : "O")))); + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, zobject->ce->name))); + php_ion_serialize_zval(obj, &rv); + zval_ptr_dtor(&rv); + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR, + "%s serializer %s::%s did not return an array", + fn ? "Custom" : "Magic", zobject->ce->name->val, + fn ? fn->common.function_name->val : "__serialize"); + } +} + +static inline zend_string *fq_enum_case(zend_object *zobject) +{ + zval *cn = zend_enum_fetch_case_name(zobject); + zend_string *en = zend_string_alloc(zobject->ce->name->len + Z_STRLEN_P(cn) + strlen("\\"), 0); + memcpy(en->val, zobject->ce->name->val, zobject->ce->name->len); + en->val[zobject->ce->name->len] = '\\'; + memcpy(&en->val[zobject->ce->name->len + 1], Z_STRVAL_P(cn), Z_STRLEN_P(cn)); + en->val[en->len] = 0; + return en; +} + +static inline void php_ion_serialize_object_enum(php_ion_writer *obj, zend_object *zobject) +{ + ION_STRING is; + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("E")))); + + zend_string *en = fq_enum_case(zobject); + ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&is, en))); + zend_string_release(en); +} + +static inline void php_ion_serialize_object_std(php_ion_writer *obj, zend_object *zobject) +{ + ION_STRING is; + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("o")))); + + if (zobject->ce != zend_standard_class_def) { + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_zend(&is, zobject->ce->name))); + } + + zval zobj; + ZVAL_OBJ(&zobj, zobject); + HashTable *props = zend_get_properties_for(&zobj, ZEND_PROP_PURPOSE_SERIALIZE); + if (props) { + php_ion_serialize_struct(obj, props); + zend_release_properties(props); + } else { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR, + "Could not get properties for serialization of class %s", + zobject->ce->name->val); + } +} + +static inline bool can_call_magic_serialize(php_ion_writer *obj, zend_class_entry *ce) +{ + if (ce->__serialize && obj->php.call_magic_serialize) { + return true; + } + return false; +} + +static inline bool can_call_iface_serialize(php_ion_writer *obj, zend_class_entry *ce) +{ + return !!ce->serialize; +} + +static inline bool can_call_custom_serialize(php_ion_writer *obj, zend_object *zobject, zend_function **fn) +{ + if (obj->php.custom_serialize) { + return !!((*fn = zend_hash_find_ptr(&zobject->ce->function_table, obj->php.custom_serialize))); + } + return false; +} + +static inline void php_ion_serialize_object(php_ion_writer *obj, zend_object *zobject) +{ + zend_function *fn; + zend_class_entry *ce = zobject->ce; + ZEND_ASSERT(ce); + + if (ce->ce_flags & ZEND_ACC_NOT_SERIALIZABLE) { + zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG, + "Serializing %s is not allowed", ce->name->val); + return; + } + + if (can_call_magic_serialize(obj, ce)) { + php_ion_serialize_object_magic(obj, zobject, NULL); + } else if (can_call_iface_serialize(obj, ce)) { + php_ion_serialize_object_iface(obj, zobject); + } else if (can_call_custom_serialize(obj, zobject, &fn)) { + php_ion_serialize_object_magic(obj, zobject, fn); + } else if (zobject->ce->ce_flags & ZEND_ACC_ENUM) { + php_ion_serialize_object_enum(obj, zobject); + } else if (ce == ce_Symbol) { + ION_CHECK(ion_writer_write_ion_symbol(obj->writer, &php_ion_obj(symbol, zobject)->sym)); + } else if (ce == ce_Decimal) { + ION_CHECK(ion_writer_write_ion_decimal(obj->writer, &php_ion_obj(decimal, zobject)->dec)); + } else if (ce == ce_Timestamp) { + ION_TIMESTAMP its; + php_ion_timestamp *pts = php_ion_obj(timestamp, zobject); + php_ion_writer_options *opt = php_ion_obj(writer_options, obj->opt); + decContext *ctx = opt ? opt->opt.decimal_context : NULL; + ION_CHECK(ion_writer_write_timestamp(obj->writer, ion_timestamp_from_php(&its, pts, ctx))); + } else { + php_ion_serialize_object_std(obj, zobject); + } +} + +static inline void php_ion_serialize_refcounted(php_ion_writer *obj, zval *zv) +{ + zend_ulong idx = (zend_ulong) (uintptr_t) Z_COUNTED_P(zv); + + ION_STRING is; + if (zend_hash_index_exists(&php_ion_globals.serializer.ids, idx)) { + zval *num = zend_hash_index_find(&php_ion_globals.serializer.ids, idx); + + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("r")))); + ION_CHECK(ion_writer_write_int64(obj->writer, Z_LVAL_P(num))); + } else { + zval num; + + ZVAL_LONG(&num, zend_hash_num_elements(&php_ion_globals.serializer.ids)); + zend_hash_index_add(&php_ion_globals.serializer.ids, idx, &num); + + Z_TRY_ADDREF_P(zv); + zend_hash_next_index_insert(&php_ion_globals.serializer.tmp, zv); + + switch (Z_TYPE_P(zv)) { + case IS_STRING: + ION_CHECK(ion_writer_write_string(obj->writer, ion_string_from_zend(&is, Z_STR_P(zv)))); + break; + + case IS_ARRAY: + php_ion_serialize_array(obj, Z_ARRVAL_P(zv)); + break; + + case IS_OBJECT: + php_ion_serialize_object(obj, Z_OBJ_P(zv)); + break; + + case IS_REFERENCE: + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("R")))); + php_ion_serialize_zval(obj, Z_REFVAL_P(zv)); + break; + } + } +} + +static inline void php_ion_serialize_zval(php_ion_writer *obj, zval *zv) +{ + OBJ_CHECK(obj); + + switch (Z_TYPE_P(zv)) { + case IS_NULL: + ION_CHECK(ion_writer_write_null(obj->writer)); + break; + case IS_TRUE: + ION_CHECK(ion_writer_write_bool(obj->writer, TRUE)); + break; + case IS_FALSE: + ION_CHECK(ion_writer_write_bool(obj->writer, FALSE)); + break; + case IS_LONG: + ION_CHECK(ion_writer_write_int64(obj->writer, Z_LVAL_P(zv))); + break; + case IS_DOUBLE: + ION_CHECK(ion_writer_write_double(obj->writer, Z_DVAL_P(zv))); + break; + case IS_STRING: + case IS_ARRAY: + case IS_OBJECT: + case IS_REFERENCE: + php_ion_serialize_refcounted(obj, zv); + break; + default: + zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG, + "Failed to serialize value of type %s", zend_zval_get_legacy_type(zv)->val); + } +} + +void php_ion_serialize(php_ion_writer *obj, zval *zv, zval *return_value) +{ + zval zwriter; + + if (obj) { + ZVAL_OBJ_COPY(&zwriter, &obj->std); + } else { + object_init_ex(&zwriter, ce_Writer_Buffer_Writer); + obj = php_ion_obj(writer, Z_OBJ(zwriter)); + obj->type = BUFFER_WRITER; + php_ion_writer_ctor(obj); + } + + php_ion_globals_serializer_step(); + + /* start off with a global PHP annotation instead of repeating it all over the place */ + ION_STRING is; + ION_CHECK(ion_writer_add_annotation(obj->writer, ion_string_from_cstr(&is, ZEND_STRL("PHP")))); + + php_ion_serialize_zval(obj, zv); + + /* make sure to flush when done, else str.s might not contain everything until the writer is closed */ + ion_writer_flush(obj->writer, NULL); + RETVAL_STR_COPY(obj->buffer.str.s); + + php_ion_globals_serializer_exit(); + + zval_ptr_dtor(&zwriter); +} + +static inline void php_ion_unserialize_zval(php_ion_reader *obj, zval *return_value); + +static inline bool can_call_magic_unserialize(php_ion_reader *obj, zend_class_entry *ce) +{ + if (ce->__unserialize && obj->php.call_magic_unserialize) { + return true; + } + return false; +} + +static inline bool can_call_iface_unserialize(php_ion_reader *obj, zend_class_entry *ce) +{ + return !!ce->unserialize; +} + +static inline bool can_call_custom_unserialize(php_ion_reader *obj, zend_object *zobject, zend_function **fn) +{ + if (obj->php.custom_unserialize) { + return !!((*fn = zend_hash_find_ptr(&zobject->ce->function_table, obj->php.custom_unserialize))); + } + return false; +} + +static inline zval *php_ion_unserialize_class(php_ion_reader *obj, zend_string *class_name, zval *return_value) +{ + zend_class_entry *ce = zend_lookup_class(class_name); + + if (ce) { + object_init_ex(return_value, ce); + return zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + } + + zend_throw_exception_ex(spl_ce_RuntimeException, IERR_IMPORT_NOT_FOUND, + "Could not find class %s", class_name->val); + return NULL; +} + +static inline void php_ion_unserialize_object_iface(php_ion_reader *obj, zend_string *class_name, zval *return_value) +{ + ZEND_ASSERT(Z_TYPE_P(return_value) == IS_STRING); + zend_string *s = Z_STR_P(return_value); + + zval *backref = php_ion_unserialize_class(obj, class_name, return_value); + ION_CATCH(); + + zend_class_entry *ce = Z_OBJCE_P(return_value); + if (can_call_iface_unserialize(obj, ce)) { + if (SUCCESS == ce->unserialize(backref, ce, (BYTE *) s->val, s->len, NULL)) { + // remove all this Serializable crap in PHP-9 + zval_ptr_dtor(return_value); + ZVAL_COPY_VALUE(return_value, backref); + } else if (!EG(exception)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR, + "Failed to unserialize class %s", ce->name->val); + } + } else { + zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN, + "Class %s does not implement Serializable", class_name->val); + } + + zend_string_release(s); +} + +static inline void php_ion_unserialize_hash(php_ion_reader *obj, zval *return_value) +{ + ION_CHECK(ion_reader_step_in(obj->reader)); + + ION_TYPE typ; + while (true) { + ION_CHECK(ion_reader_next(obj->reader, &typ)); + + if (typ == tid_EOF) { + break; + } + + ION_STRING name; + ION_CHECK(ion_reader_get_field_name(obj->reader, &name)); + + zend_string *zkey = zend_string_from_ion(&name); + zval *zvalue = zend_hash_add_empty_element(HASH_OF(return_value), zkey); + php_ion_unserialize_zval(obj, zvalue); + zend_string_release(zkey); + ION_CATCH(); + } + + ION_CHECK(ion_reader_step_out(obj->reader)); +} + +static inline void php_ion_unserialize_object_magic(php_ion_reader *obj, zend_string *class_name, bool custom, zval *return_value) +{ + php_ion_unserialize_class(obj, class_name, return_value); + ION_CATCH(); + + zend_object *zobject = Z_OBJ_P(return_value); + zend_function *fn = NULL; + if (custom) { + if (!can_call_custom_unserialize(obj, Z_OBJ_P(return_value), &fn)) { + zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN, + "Could not find custom serializer method of %s", class_name->val); + return; + } + } else { + if (!can_call_magic_unserialize(obj, zobject->ce)) { + zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN, + "Could not find method %s::__serialize()", class_name->val); + } + } + + zval sv; + array_init(&sv); + php_ion_unserialize_hash(obj, &sv); + ION_CATCH(zval_ptr_dtor(&sv)); + + zval rv; + ZVAL_NULL(&rv); + zend_call_method_with_1_params(zobject, zobject->ce, fn ? &fn : &zobject->ce->__serialize, "", &rv, &sv); + zval_ptr_dtor(&rv); + zval_ptr_dtor(&sv); +} + +static inline void php_ion_unserialize_object_of_class(php_ion_reader *obj, uint8_t object_type, zend_string *class_name, zval *return_value) +{ + switch (object_type) { + case 'S': + php_ion_unserialize_object_iface(obj, class_name, return_value); + break; + + case 'C': + php_ion_unserialize_object_magic(obj, class_name, true, return_value); + break; + + case 'O': + php_ion_unserialize_object_magic(obj, class_name, false, return_value); + break; + + default: + zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN, + "Invalid object type %c", object_type); + } +} + +static inline void php_ion_unserialize_struct(php_ion_reader *obj, uint8_t object_type, zend_string *class_name, zval *return_value) +{ + if (class_name) { + php_ion_unserialize_object_of_class(obj, object_type, class_name, return_value); + } else if (!object_type) { + array_init(return_value); + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + php_ion_unserialize_hash(obj, return_value); + } else if (object_type == 'o') { + object_init(return_value); + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + php_ion_unserialize_hash(obj, return_value); + } else { + zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INVALID_TOKEN, + "Invalid object type %c", object_type); + } +} + +static inline void php_ion_unserialize_list(php_ion_reader *obj, zval *return_value) +{ + ION_CHECK(ion_reader_step_in(obj->reader)); + array_init(return_value); + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + + ION_TYPE typ; + HashTable *ht = Z_ARRVAL_P(return_value); + while (true) { + zval next; + php_ion_unserialize_zval(obj, &next); + ION_CATCH(); + + ION_CHECK(ion_reader_get_type(obj->reader, &typ)); + if (typ == tid_EOF) { + break; + } + + zend_hash_next_index_insert(ht, &next); + } + + ION_CHECK(ion_reader_step_out(obj->reader)); +} + +static inline void php_ion_unserialize_lob(php_ion_reader *obj, zval *return_value) +{ + zend_string *zstr = zend_string_alloc(0x1000, 0); +again: + SIZE read = 0; + iERR err = ion_reader_read_lob_bytes(obj->reader, (BYTE *) zstr->val, zstr->len, &read); + if (err == IERR_BUFFER_TOO_SMALL) { + zstr = zend_string_extend(zstr, zstr->len << 2, 0); + goto again; + } + ION_CHECK(err, zend_string_release(zstr)); + if (zstr->len > read) { + zstr = zend_string_truncate(zstr, read, 0); + } + RETURN_STR(zstr); +} + +static inline void php_ion_unserialize_timestamp(php_ion_reader *obj, zval *return_value) +{ + ION_TIMESTAMP ts; + ION_CHECK(ion_reader_read_timestamp(obj->reader, &ts)); + + decContext *ctx = NULL; + if (obj->opt) { + ctx = php_ion_obj(reader_options, obj->opt)->opt.decimal_context; + } + + object_init_ex(return_value, ce_Timestamp); + php_ion_timestamp *ts_obj = php_ion_obj(timestamp, Z_OBJ_P(return_value)); + + zend_string *fmt = NULL; + ts_obj->time = php_time_from_ion(&ts, ctx, &fmt); + php_ion_timestamp_ctor(ts_obj, ts.precision, fmt, NULL, NULL); + zend_string_release(fmt); + + OBJ_CHECK(ts_obj); +} + +static inline void php_ion_unserialize_int(php_ion_reader *obj, zval *return_value) +{ + ION_INT *num = NULL; + ION_CHECK(ion_int_alloc(obj->reader, &num)); + ION_CHECK(ion_reader_read_ion_int(obj->reader, num)); + + // TODO: SIZEOF_ZEND_LONG == 4 + int64_t i64; + iERR err = ion_int_to_int64(num, &i64); + switch (err) { + case IERR_OK: + RETVAL_LONG(i64); + goto done; + + case IERR_NUMERIC_OVERFLOW: + SIZE max, len; + ION_CHECK(ion_int_char_length(num, &max)); + zend_string *zs = zend_string_alloc(max-1, 0); + + err = ion_int_to_char(num, (BYTE *) zs->val, max, &len); + ZEND_ASSERT(len == zs->len); + RETVAL_STR(zs); + /* fall through */ + + default: + done: + ion_int_free(num); + ION_CHECK(err); + } +} + +static inline void php_ion_unserialize_backref(php_ion_reader *obj, zval *return_value) +{ + php_ion_global_unserializer *u = &php_ion_globals.unserializer; + zval *backref = zend_hash_index_find(&u->ids, Z_LVAL_P(return_value)); + + if (backref) { + ZVAL_COPY(return_value, backref); + } else { + zend_throw_exception_ex(spl_ce_RuntimeException, IERR_INTERNAL_ERROR, + "Could not find backref %ld", Z_LVAL_P(return_value)); + } +} + +static inline void php_ion_unserialize_zval(php_ion_reader *obj, zval *return_value) +{ + ION_TYPE typ; + ION_CHECK(ion_reader_next(obj->reader, &typ)); + +#define next_annotation() do { \ + if (ann_count) { \ + --ann_count; \ + ION_CHECK(ion_reader_get_an_annotation(obj->reader, ann_index++, &annotation)); \ + } \ +} while (0) +#define has_annotation(a) (has_annotations && annotation.length == 1 && annotation.value[0] == a) + + BOOL has_annotations; + int32_t ann_index = 0, ann_count = 0; + ION_STRING annotation = {0}; + ION_CHECK(ion_reader_has_any_annotations(obj->reader, &has_annotations)); + if (has_annotations) { + ION_CHECK(ion_reader_get_annotation_count(obj->reader, &ann_count)); + next_annotation(); + } + + if (has_annotation('r')) { + // BACKREF + php_ion_unserialize_int(obj, return_value); + ION_CATCH(); + php_ion_unserialize_backref(obj, return_value); + ION_CATCH(); + return; + } + + if (has_annotation('R')) { + // REFERENCE + ZVAL_MAKE_REF(return_value); + ZVAL_DEREF(return_value); + next_annotation(); + } + + BOOL bval; + ION_CHECK(ion_reader_is_null(obj->reader, &bval)); + if (bval) { + goto read_null; + } + + switch (ION_TYPE_INT(typ)) { + case tid_NULL_INT: + read_null: ; + ION_CHECK(ion_reader_read_null(obj->reader, &typ)); + RETURN_NULL(); + + case tid_BOOL_INT: + ION_CHECK(ion_reader_read_bool(obj->reader, &bval)); + RETURN_BOOL(bval); + + case tid_INT_INT: + php_ion_unserialize_int(obj, return_value); + return; + + case tid_FLOAT_INT: + ION_CHECK(ion_reader_read_double(obj->reader, &Z_DVAL_P(return_value))); + return; + + case tid_DECIMAL_INT: + object_init_ex(return_value, ce_Decimal); + php_ion_decimal *dec = php_ion_obj(decimal, Z_OBJ_P(return_value)); + ION_CHECK(ion_reader_read_ion_decimal(obj->reader, &dec->dec)); + php_ion_decimal_ctor(dec); + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + return; + + case tid_TIMESTAMP_INT: + php_ion_unserialize_timestamp(obj, return_value); + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + return; + + case tid_SYMBOL_INT: + ION_SYMBOL sym; + ION_CHECK(ion_reader_read_ion_symbol(obj->reader, &sym)); + php_ion_symbol_zval(&sym, return_value); + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + return; + + case tid_STRING_INT: + ION_STRING str; + ION_CHECK(ion_reader_read_string(obj->reader, &str)); + RETVAL_STRINGL((char *) str.value, str.length); + if (has_annotation('S')) { + goto serializable; + } + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + return; + + case tid_CLOB_INT: + case tid_BLOB_INT: + php_ion_unserialize_lob(obj, return_value); + if (has_annotation('S')) { + goto serializable; + } + zend_hash_next_index_insert(&php_ion_globals.unserializer.ids, return_value); + return; + + case tid_LIST_INT: + case tid_SEXP_INT: // FIXME + php_ion_unserialize_list(obj, return_value); + return; + + case tid_STRUCT_INT: + serializable: ; + zend_string *class_name = NULL; + uint8_t object_type = annotation.length == 1 ? annotation.value[0] : 0; + if (object_type && object_type != 'o') { + next_annotation(); + class_name = zend_string_from_ion(&annotation); + } + php_ion_unserialize_struct(obj, object_type, class_name, return_value); + if (class_name) { + zend_string_release(class_name); + } + return; + + case tid_none_INT: + ZEND_ASSERT(0); + break; + + case tid_DATAGRAM_INT: + case tid_EOF_INT: + return; + } +} + +void php_ion_unserialize(php_ion_reader *obj, zend_string *zstr, zval *return_value) +{ + zval zreader; + + if (obj) { + ZVAL_OBJ_COPY(&zreader, &obj->std); + } else { + object_init_ex(&zreader, ce_Reader_Buffer_Reader); + obj = php_ion_obj(reader, Z_OBJ(zreader)); + obj->type = BUFFER_READER; + obj->buffer = zend_string_copy(zstr); + php_ion_reader_ctor(obj); + } + + php_ion_globals_serializer_step(); + php_ion_unserialize_zval(obj, return_value); + php_ion_globals_serializer_exit(); + + zval_ptr_dtor(&zreader); +} diff --git a/php_ion.h b/php_ion.h new file mode 100644 index 0000000..e1e158e --- /dev/null +++ b/php_ion.h @@ -0,0 +1,27 @@ +/* + +--------------------------------------------------------------------+ + | PECL :: ion | + +--------------------------------------------------------------------+ + | Redistribution and use in source and binary forms, with or without | + | modification, are permitted provided that the conditions mentioned | + | in the accompanying LICENSE file are met. | + +--------------------------------------------------------------------+ + | Copyright (c) 2021, Michael Wallner | + +--------------------------------------------------------------------+ +*/ + +#ifndef PHP_ION_H +# define PHP_ION_H + +extern zend_module_entry ion_module_entry; +# define phpext_ion_ptr &ion_module_entry + +# define PHP_ION_VERSION "0.1.0" + +# if defined(ZTS) && defined(COMPILE_DL_ION) +ZEND_TSRMLS_CACHE_EXTERN() +# endif + +#define SUCCESS 0 + +#endif /* PHP_ION_H */ -- 2.30.2