From ffb2b538347d3a1e1f63bf85db8260dc4d514aa9 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Thu, 9 Jul 2020 11:06:24 -0700 Subject: [PATCH] Remove old PHP extension (#7695) * Removed references to legacy class names from generated code. * Removed old PHP extension in favor of new extension. This drops PHP5 compat. * Updated failure lists for things fixed by the new extension. * Updated Makefile.am for new file list. * Fix distcheck. --- Makefile.am | 43 +- conformance/failure_list_php_c.txt | 53 - conformance/failure_list_php_c_32.txt | 86 - .../google/{protobuf2 => protobuf}/arena.c | 0 .../google/{protobuf2 => protobuf}/arena.h | 0 php/ext/google/protobuf/array.c | 777 +- .../google/{protobuf2 => protobuf}/array.h | 0 .../google/protobuf/builtin_descriptors.inc | 635 - .../{protobuf2 => protobuf}/bundled_php.h | 0 php/ext/google/protobuf/config.m4 | 2 +- .../google/{protobuf2 => protobuf}/convert.c | 0 .../google/{protobuf2 => protobuf}/convert.h | 0 php/ext/google/protobuf/def.c | 1578 +- php/ext/google/{protobuf2 => protobuf}/def.h | 0 php/ext/google/protobuf/encode_decode.c | 2283 --- .../{protobuf2 => protobuf}/make-preload.php | 2 +- php/ext/google/protobuf/map.c | 918 +- php/ext/google/{protobuf2 => protobuf}/map.h | 0 php/ext/google/protobuf/message.c | 3231 +--- .../google/{protobuf2 => protobuf}/message.h | 0 .../google/{protobuf2 => protobuf}/names.c | 0 .../google/{protobuf2 => protobuf}/names.h | 0 php/ext/google/protobuf/package.xml | 22 +- .../google/{protobuf2 => protobuf}/php-upb.c | 0 .../google/{protobuf2 => protobuf}/php-upb.h | 0 php/ext/google/protobuf/protobuf.c | 730 +- php/ext/google/protobuf/protobuf.h | 1586 +- php/ext/google/protobuf/storage.c | 1180 -- php/ext/google/protobuf/type_check.c | 680 - php/ext/google/protobuf/upb.c | 13840 ---------------- php/ext/google/protobuf/upb.h | 6796 -------- php/ext/google/protobuf/utf8.c | 68 - php/ext/google/protobuf/utf8.h | 36 - php/ext/google/protobuf2/array.c | 602 - php/ext/google/protobuf2/config.m4 | 10 - php/ext/google/protobuf2/def.c | 1085 -- php/ext/google/protobuf2/map.c | 590 - php/ext/google/protobuf2/message.c | 841 - php/ext/google/protobuf2/protobuf.c | 349 - php/ext/google/protobuf2/protobuf.h | 89 - php/tests/compile_extension.sh | 11 +- php/tests/php_implementation_test.php | 2 +- php/tests/test.sh | 17 +- .../protobuf/compiler/php/php_generator.cc | 6 +- 44 files changed, 2618 insertions(+), 35530 deletions(-) rename php/ext/google/{protobuf2 => protobuf}/arena.c (100%) rename php/ext/google/{protobuf2 => protobuf}/arena.h (100%) rename php/ext/google/{protobuf2 => protobuf}/array.h (100%) delete mode 100644 php/ext/google/protobuf/builtin_descriptors.inc rename php/ext/google/{protobuf2 => protobuf}/bundled_php.h (100%) rename php/ext/google/{protobuf2 => protobuf}/convert.c (100%) rename php/ext/google/{protobuf2 => protobuf}/convert.h (100%) rename php/ext/google/{protobuf2 => protobuf}/def.h (100%) delete mode 100644 php/ext/google/protobuf/encode_decode.c rename php/ext/google/{protobuf2 => protobuf}/make-preload.php (97%) rename php/ext/google/{protobuf2 => protobuf}/map.h (100%) rename php/ext/google/{protobuf2 => protobuf}/message.h (100%) rename php/ext/google/{protobuf2 => protobuf}/names.c (100%) rename php/ext/google/{protobuf2 => protobuf}/names.h (100%) rename php/ext/google/{protobuf2 => protobuf}/php-upb.c (100%) rename php/ext/google/{protobuf2 => protobuf}/php-upb.h (100%) delete mode 100644 php/ext/google/protobuf/storage.c delete mode 100644 php/ext/google/protobuf/type_check.c delete mode 100644 php/ext/google/protobuf/upb.c delete mode 100644 php/ext/google/protobuf/upb.h delete mode 100644 php/ext/google/protobuf/utf8.c delete mode 100644 php/ext/google/protobuf/utf8.h delete mode 100644 php/ext/google/protobuf2/array.c delete mode 100644 php/ext/google/protobuf2/config.m4 delete mode 100644 php/ext/google/protobuf2/def.c delete mode 100644 php/ext/google/protobuf2/map.c delete mode 100644 php/ext/google/protobuf2/message.c delete mode 100644 php/ext/google/protobuf2/protobuf.c delete mode 100644 php/ext/google/protobuf2/protobuf.h diff --git a/Makefile.am b/Makefile.am index 9b864faaecc1..631df6f31487 100644 --- a/Makefile.am +++ b/Makefile.am @@ -767,43 +767,28 @@ php_EXTRA_DIST= \ composer.json \ php/README.md \ php/composer.json \ + php/ext/google/protobuf/arena.c \ + php/ext/google/protobuf/arena.h \ php/ext/google/protobuf/array.c \ - php/ext/google/protobuf/builtin_descriptors.inc \ + php/ext/google/protobuf/array.h \ + php/ext/google/protobuf/bundled_php.h \ php/ext/google/protobuf/config.m4 \ + php/ext/google/protobuf/convert.c \ + php/ext/google/protobuf/convert.h \ php/ext/google/protobuf/def.c \ - php/ext/google/protobuf/encode_decode.c \ + php/ext/google/protobuf/def.h \ + php/ext/google/protobuf/make-preload.php \ php/ext/google/protobuf/map.c \ + php/ext/google/protobuf/map.h \ php/ext/google/protobuf/message.c \ + php/ext/google/protobuf/message.h \ + php/ext/google/protobuf/names.c \ + php/ext/google/protobuf/names.h \ php/ext/google/protobuf/package.xml \ + php/ext/google/protobuf/php-upb.c \ + php/ext/google/protobuf/php-upb.h \ php/ext/google/protobuf/protobuf.c \ php/ext/google/protobuf/protobuf.h \ - php/ext/google/protobuf/storage.c \ - php/ext/google/protobuf/type_check.c \ - php/ext/google/protobuf/upb.c \ - php/ext/google/protobuf/upb.h \ - php/ext/google/protobuf/utf8.c \ - php/ext/google/protobuf/utf8.h \ - php/ext/google/protobuf2/arena.c \ - php/ext/google/protobuf2/arena.h \ - php/ext/google/protobuf2/array.c \ - php/ext/google/protobuf2/array.h \ - php/ext/google/protobuf2/bundled_php.h \ - php/ext/google/protobuf2/config.m4 \ - php/ext/google/protobuf2/convert.c \ - php/ext/google/protobuf2/convert.h \ - php/ext/google/protobuf2/def.c \ - php/ext/google/protobuf2/def.h \ - php/ext/google/protobuf2/make-preload.php \ - php/ext/google/protobuf2/map.c \ - php/ext/google/protobuf2/map.h \ - php/ext/google/protobuf2/message.c \ - php/ext/google/protobuf2/message.h \ - php/ext/google/protobuf2/names.c \ - php/ext/google/protobuf2/names.h \ - php/ext/google/protobuf2/php-upb.c \ - php/ext/google/protobuf2/php-upb.h \ - php/ext/google/protobuf2/protobuf.c \ - php/ext/google/protobuf2/protobuf.h \ php/generate_descriptor_protos.sh \ php/phpunit.xml \ php/release.sh \ diff --git a/conformance/failure_list_php_c.txt b/conformance/failure_list_php_c.txt index f6c6bc8d2445..cfed9f6d4d42 100644 --- a/conformance/failure_list_php_c.txt +++ b/conformance/failure_list_php_c.txt @@ -1,23 +1,4 @@ -Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput -Recommended.FieldMaskPathsDontRoundTrip.JsonOutput -Recommended.FieldMaskTooManyUnderscore.JsonOutput Recommended.Proto2.JsonInput.FieldNameExtension.Validator -Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput -Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput -Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator -Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator -Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter -Recommended.Proto3.JsonInput.MapFieldValueIsNull -Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput -Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull -Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull -Recommended.Proto3.JsonInput.StringEndsWithEscapeChar -Recommended.Proto3.JsonInput.StringFieldSurrogateInWrongOrder -Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate -Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate -Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator -Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator -Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput @@ -28,10 +9,8 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultO Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.PackedOutput.ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.PackedOutput.ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput @@ -76,36 +55,4 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOut Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.PackedOutput.ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataScalarBinary.ENUM[3].ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataScalarBinary.ENUM[4].ProtobufOutput -Required.DurationProtoInputTooLarge.JsonOutput -Required.DurationProtoInputTooSmall.JsonOutput Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator -Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput -Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput -Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput -Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput -Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput -Required.Proto3.JsonInput.DurationMinValue.JsonOutput -Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput -Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput -Required.Proto3.JsonInput.FloatFieldNan.JsonOutput -Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput -Required.Proto3.JsonInput.OneofFieldDuplicate -Required.Proto3.JsonInput.RejectTopLevelNull -Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput -Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput -Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput -Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput -Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput -Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput -Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.DefaultValue.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.BYTES.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.BYTES.ProtobufOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.STRING.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.STRING.ProtobufOutput -Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[2].JsonOutput -Required.TimestampProtoInputTooLarge.JsonOutput -Required.TimestampProtoInputTooSmall.JsonOutput diff --git a/conformance/failure_list_php_c_32.txt b/conformance/failure_list_php_c_32.txt index 280e5ff3f968..cfed9f6d4d42 100644 --- a/conformance/failure_list_php_c_32.txt +++ b/conformance/failure_list_php_c_32.txt @@ -1,28 +1,4 @@ -Recommended.FieldMaskNumbersDontRoundTrip.JsonOutput -Recommended.FieldMaskPathsDontRoundTrip.JsonOutput -Recommended.FieldMaskTooManyUnderscore.JsonOutput Recommended.Proto2.JsonInput.FieldNameExtension.Validator -Recommended.Proto3.JsonInput.BytesFieldBase64Url.JsonOutput -Recommended.Proto3.JsonInput.BytesFieldBase64Url.ProtobufOutput -Recommended.Proto3.JsonInput.DurationHas3FractionalDigits.Validator -Recommended.Proto3.JsonInput.DurationHas6FractionalDigits.Validator -Recommended.Proto3.JsonInput.DurationHas9FractionalDigits.Validator -Recommended.Proto3.JsonInput.DurationHasZeroFractionalDigit.Validator -Recommended.Proto3.JsonInput.FieldMaskInvalidCharacter -Recommended.Proto3.JsonInput.MapFieldValueIsNull -Recommended.Proto3.JsonInput.OneofZeroBytes.JsonOutput -Recommended.Proto3.JsonInput.RepeatedFieldMessageElementIsNull -Recommended.Proto3.JsonInput.RepeatedFieldPrimitiveElementIsNull -Recommended.Proto3.JsonInput.StringEndsWithEscapeChar -Recommended.Proto3.JsonInput.StringFieldSurrogateInWrongOrder -Recommended.Proto3.JsonInput.StringFieldUnpairedHighSurrogate -Recommended.Proto3.JsonInput.StringFieldUnpairedLowSurrogate -Recommended.Proto3.JsonInput.TimestampHas3FractionalDigits.Validator -Recommended.Proto3.JsonInput.TimestampHas6FractionalDigits.Validator -Recommended.Proto3.JsonInput.TimestampHas9FractionalDigits.Validator -Recommended.Proto3.JsonInput.TimestampHasZeroFractionalDigit.Validator -Recommended.Proto3.JsonInput.TimestampZeroNormalized.Validator -Recommended.Proto3.ProtobufInput.OneofZeroBytes.JsonOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.PackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.BOOL.UnpackedInput.DefaultOutput.ProtobufOutput @@ -33,10 +9,8 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.DefaultO Recommended.Proto3.ProtobufInput.ValidDataRepeated.DOUBLE.UnpackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.PackedOutput.ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.PackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.PackedOutput.ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataRepeated.ENUM.UnpackedInput.UnpackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.PackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.FIXED32.UnpackedInput.DefaultOutput.ProtobufOutput @@ -81,64 +55,4 @@ Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.DefaultOut Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.PackedInput.PackedOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.DefaultOutput.ProtobufOutput Recommended.Proto3.ProtobufInput.ValidDataRepeated.UINT64.UnpackedInput.PackedOutput.ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataScalarBinary.ENUM[3].ProtobufOutput -Recommended.Proto3.ProtobufInput.ValidDataScalarBinary.ENUM[4].ProtobufOutput -Required.DurationProtoInputTooLarge.JsonOutput -Required.DurationProtoInputTooSmall.JsonOutput Required.Proto2.JsonInput.StoresDefaultPrimitive.Validator -Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.JsonOutput -Required.Proto3.JsonInput.DoubleFieldMaxNegativeValue.ProtobufOutput -Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.JsonOutput -Required.Proto3.JsonInput.DoubleFieldMinPositiveValue.ProtobufOutput -Required.Proto3.JsonInput.DoubleFieldNan.JsonOutput -Required.Proto3.JsonInput.DurationMaxValue.JsonOutput -Required.Proto3.JsonInput.DurationMaxValue.ProtobufOutput -Required.Proto3.JsonInput.DurationMinValue.JsonOutput -Required.Proto3.JsonInput.DurationMinValue.ProtobufOutput -Required.Proto3.JsonInput.DurationRepeatedValue.JsonOutput -Required.Proto3.JsonInput.DurationRepeatedValue.ProtobufOutput -Required.Proto3.JsonInput.FloatFieldInfinity.JsonOutput -Required.Proto3.JsonInput.FloatFieldNan.JsonOutput -Required.Proto3.JsonInput.FloatFieldNegativeInfinity.JsonOutput -Required.Proto3.JsonInput.Int64FieldMaxValue.JsonOutput -Required.Proto3.JsonInput.Int64FieldMaxValueNotQuoted.JsonOutput -Required.Proto3.JsonInput.Int64FieldMaxValueNotQuoted.ProtobufOutput -Required.Proto3.JsonInput.Int64FieldMaxValue.ProtobufOutput -Required.Proto3.JsonInput.Int64FieldMinValue.JsonOutput -Required.Proto3.JsonInput.Int64FieldMinValueNotQuoted.JsonOutput -Required.Proto3.JsonInput.Int64FieldMinValueNotQuoted.ProtobufOutput -Required.Proto3.JsonInput.Int64FieldMinValue.ProtobufOutput -Required.Proto3.JsonInput.OneofFieldDuplicate -Required.Proto3.JsonInput.RejectTopLevelNull -Required.Proto3.JsonInput.StringFieldSurrogatePair.JsonOutput -Required.Proto3.JsonInput.StringFieldSurrogatePair.ProtobufOutput -Required.Proto3.JsonInput.TimestampLeap.JsonOutput -Required.Proto3.JsonInput.TimestampLeap.ProtobufOutput -Required.Proto3.JsonInput.TimestampMaxValue.JsonOutput -Required.Proto3.JsonInput.TimestampMaxValue.ProtobufOutput -Required.Proto3.JsonInput.TimestampMinValue.JsonOutput -Required.Proto3.JsonInput.TimestampMinValue.ProtobufOutput -Required.Proto3.JsonInput.TimestampRepeatedValue.JsonOutput -Required.Proto3.JsonInput.TimestampRepeatedValue.ProtobufOutput -Required.Proto3.JsonInput.TimestampWithNegativeOffset.JsonOutput -Required.Proto3.JsonInput.TimestampWithNegativeOffset.ProtobufOutput -Required.Proto3.JsonInput.TimestampWithPositiveOffset.JsonOutput -Required.Proto3.JsonInput.TimestampWithPositiveOffset.ProtobufOutput -Required.Proto3.JsonInput.Uint64FieldMaxValue.JsonOutput -Required.Proto3.JsonInput.Uint64FieldMaxValueNotQuoted.JsonOutput -Required.Proto3.JsonInput.Uint64FieldMaxValueNotQuoted.ProtobufOutput -Required.Proto3.JsonInput.Uint64FieldMaxValue.ProtobufOutput -Required.Proto3.ProtobufInput.DoubleFieldNormalizeQuietNan.JsonOutput -Required.Proto3.ProtobufInput.DoubleFieldNormalizeSignalingNan.JsonOutput -Required.Proto3.ProtobufInput.FloatFieldNormalizeQuietNan.JsonOutput -Required.Proto3.ProtobufInput.FloatFieldNormalizeSignalingNan.JsonOutput -Required.Proto3.ProtobufInput.ValidDataOneof.BYTES.DefaultValue.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.BYTES.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.BYTES.ProtobufOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.PackedInput.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.FLOAT.UnpackedInput.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.STRING.JsonOutput -Required.Proto3.ProtobufInput.ValidDataRepeated.STRING.ProtobufOutput -Required.Proto3.ProtobufInput.ValidDataScalar.FLOAT[2].JsonOutput -Required.TimestampProtoInputTooLarge.JsonOutput -Required.TimestampProtoInputTooSmall.JsonOutput diff --git a/php/ext/google/protobuf2/arena.c b/php/ext/google/protobuf/arena.c similarity index 100% rename from php/ext/google/protobuf2/arena.c rename to php/ext/google/protobuf/arena.c diff --git a/php/ext/google/protobuf2/arena.h b/php/ext/google/protobuf/arena.h similarity index 100% rename from php/ext/google/protobuf2/arena.h rename to php/ext/google/protobuf/arena.h diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c index 5174f4a78bb6..571d3e41cdee 100644 --- a/php/ext/google/protobuf/array.c +++ b/php/ext/google/protobuf/array.c @@ -28,389 +28,268 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include +#include "array.h" + #include #include -#include "protobuf.h" +#include -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) - ZEND_ARG_INFO(0, index) -ZEND_END_ARG_INFO() +// This is not self-contained: it must be after other Zend includes. +#include -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, newval) -ZEND_END_ARG_INFO() +#include "arena.h" +#include "convert.h" +#include "def.h" +#include "php-upb.h" +#include "protobuf.h" -ZEND_BEGIN_ARG_INFO(arginfo_void, 0) -ZEND_END_ARG_INFO() +static void RepeatedFieldIter_make(zval *val, zval *repeated_field); -static zend_function_entry repeated_field_methods[] = { - PHP_ME(RepeatedField, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, append, NULL, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, count, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, getIterator, arginfo_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; +// ----------------------------------------------------------------------------- +// RepeatedField +// ----------------------------------------------------------------------------- -static zend_function_entry repeated_field_iter_methods[] = { - PHP_ME(RepeatedFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; +typedef struct { + zend_object std; + zval arena; + upb_array *array; + upb_fieldtype_t type; + const Descriptor* desc; // When values are messages. +} RepeatedField; -// Forward declare static functions. - -static int repeated_field_array_init(zval *array, upb_fieldtype_t type, - uint size ZEND_FILE_LINE_DC); -static void repeated_field_write_dimension(zval *object, zval *offset, - zval *value TSRMLS_DC); -static HashTable *repeated_field_get_gc(zval *object, CACHED_VALUE **table, - int *n TSRMLS_DC); -#if PHP_MAJOR_VERSION < 7 -static zend_object_value repeated_field_create(zend_class_entry *ce TSRMLS_DC); -static zend_object_value repeated_field_iter_create(zend_class_entry *ce TSRMLS_DC); -#else -static zend_object *repeated_field_create(zend_class_entry *ce TSRMLS_DC); -static zend_object *repeated_field_iter_create(zend_class_entry *ce TSRMLS_DC); -#endif +zend_class_entry *RepeatedField_class_entry; +static zend_object_handlers RepeatedField_object_handlers; -// ----------------------------------------------------------------------------- -// RepeatedField creation/destruction -// ----------------------------------------------------------------------------- +// PHP Object Handlers ///////////////////////////////////////////////////////// -zend_class_entry* repeated_field_type; -zend_class_entry* repeated_field_iter_type; -zend_object_handlers* repeated_field_handlers; -zend_object_handlers* repeated_field_iter_handlers; - -// Define object free method. -PHP_PROTO_OBJECT_FREE_START(RepeatedField, repeated_field) -#if PHP_MAJOR_VERSION < 7 -php_proto_zval_ptr_dtor(intern->array); -#else -php_proto_zval_ptr_dtor(&intern->array); -#endif -PHP_PROTO_OBJECT_FREE_END - -PHP_PROTO_OBJECT_EMPTY_DTOR_START(RepeatedField, repeated_field) -PHP_PROTO_OBJECT_DTOR_END - -// Define object create method. -PHP_PROTO_OBJECT_CREATE_START(RepeatedField, repeated_field) -#if PHP_MAJOR_VERSION < 7 -intern->array = NULL; -#endif -intern->type = 0; -intern->msg_ce = NULL; -PHP_PROTO_OBJECT_CREATE_END(RepeatedField, repeated_field) - -// Init class entry. -PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\RepeatedField", - RepeatedField, repeated_field) -zend_class_implements(repeated_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess, - zend_ce_aggregate, spl_ce_Countable); -repeated_field_handlers->write_dimension = repeated_field_write_dimension; -repeated_field_handlers->get_gc = repeated_field_get_gc; -PHP_PROTO_INIT_CLASS_END - -// Define array element free function. -#if PHP_MAJOR_VERSION < 7 -static inline void php_proto_array_string_release(void *value) { - zval_ptr_dtor(value); +/** + * RepeatedField_create() + * + * PHP class entry function to allocate and initialize a new RepeatedField + * object. + */ +static zend_object* RepeatedField_create(zend_class_entry *class_type) { + RepeatedField *intern = emalloc(sizeof(RepeatedField)); + zend_object_std_init(&intern->std, class_type); + intern->std.handlers = &RepeatedField_object_handlers; + Arena_Init(&intern->arena); + intern->array = NULL; + intern->desc = NULL; + // Skip object_properties_init(), we don't allow derived classes. + return &intern->std; } -static inline void php_proto_array_object_release(void *value) { - zval_ptr_dtor(value); -} -static inline void php_proto_array_default_release(void *value) { -} -#else -static inline void php_proto_array_string_release(zval *value) { - void* ptr = Z_PTR_P(value); - zend_string* object = *(zend_string**)ptr; - zend_string_release(object); - efree(ptr); -} -static inline void php_proto_array_object_release(zval *value) { - zval_ptr_dtor(value); -} -static void php_proto_array_default_release(zval* value) { - void* ptr = Z_PTR_P(value); - efree(ptr); -} -#endif - -static int repeated_field_array_init(zval *array, upb_fieldtype_t type, - uint size ZEND_FILE_LINE_DC) { - PHP_PROTO_ALLOC_ARRAY(array); - - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - zend_hash_init(Z_ARRVAL_P(array), size, NULL, - php_proto_array_string_release, 0); - break; - case UPB_TYPE_MESSAGE: - zend_hash_init(Z_ARRVAL_P(array), size, NULL, - php_proto_array_object_release, 0); - break; - default: - zend_hash_init(Z_ARRVAL_P(array), size, NULL, - php_proto_array_default_release, 0); - } - return SUCCESS; +/** + * RepeatedField_dtor() + * + * Object handler to destroy a RepeatedField. This releases all resources + * associated with the message. Note that it is possible to access a destroyed + * object from PHP in rare cases. + */ +static void RepeatedField_destructor(zend_object* obj) { + RepeatedField* intern = (RepeatedField*)obj; + ObjCache_Delete(intern->array); + zval_ptr_dtor(&intern->arena); + zend_object_std_dtor(&intern->std); } -// ----------------------------------------------------------------------------- -// RepeatedField Handlers -// ----------------------------------------------------------------------------- +static HashTable *RepeatedField_GetProperties(zval *object TSRMLS_DC) { + return NULL; // We do not have a properties table. +} -static void repeated_field_write_dimension(zval *object, zval *offset, - zval *value TSRMLS_DC) { - uint64_t index; +static zval *RepeatedField_GetPropertyPtrPtr(zval *object, zval *member, + int type, void **cache_slot) { + return NULL; // We don't offer direct references to our properties. +} - RepeatedField *intern = UNBOX(RepeatedField, object); - HashTable *ht = PHP_PROTO_HASH_OF(intern->array); - int size = native_slot_size(intern->type); +// C Functions from array.h //////////////////////////////////////////////////// - unsigned char memory[NATIVE_SLOT_MAX_SIZE]; - memset(memory, 0, NATIVE_SLOT_MAX_SIZE); +// These are documented in the header file. - if (!native_slot_set_by_array(intern->type, intern->msg_ce, memory, - value TSRMLS_CC)) { +void RepeatedField_GetPhpWrapper(zval *val, upb_array *arr, + const upb_fielddef *f, zval *arena) { + if (!arr) { + ZVAL_NULL(val); return; } - if (!offset || Z_TYPE_P(offset) == IS_NULL) { - index = zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)); - } else { - if (protobuf_convert_to_uint64(offset, &index)) { - if (!zend_hash_index_exists(ht, index)) { - zend_error(E_USER_ERROR, "Element at %llu doesn't exist.\n", - (long long unsigned int)index); - return; - } - } else { - return; - } + if (!ObjCache_Get(arr, val)) { + RepeatedField *intern = emalloc(sizeof(RepeatedField)); + zend_object_std_init(&intern->std, RepeatedField_class_entry); + intern->std.handlers = &RepeatedField_object_handlers; + ZVAL_COPY(&intern->arena, arena); + intern->array = arr; + intern->type = upb_fielddef_type(f); + intern->desc = Descriptor_GetFromFieldDef(f); + // Skip object_properties_init(), we don't allow derived classes. + ObjCache_Add(intern->array, &intern->std); + ZVAL_OBJ(val, &intern->std); } +} - if (intern->type == UPB_TYPE_MESSAGE) { - php_proto_zend_hash_index_update_zval(ht, index, *(zval**)memory); - } else { - php_proto_zend_hash_index_update_mem(ht, index, memory, size, NULL); +upb_array *RepeatedField_GetUpbArray(zval *val, const upb_fielddef *f, + upb_arena *arena) { + if (Z_ISREF_P(val)) { + ZVAL_DEREF(val); } -} -#if PHP_MAJOR_VERSION < 7 -static HashTable *repeated_field_get_gc(zval *object, zval ***table, - int *n TSRMLS_DC) { -#else -static HashTable *repeated_field_get_gc(zval *object, zval **table, int *n) { -#endif - *table = NULL; - *n = 0; - RepeatedField *intern = UNBOX(RepeatedField, object); - return PHP_PROTO_HASH_OF(intern->array); -} + if (Z_TYPE_P(val) == IS_ARRAY) { + // Auto-construct, eg. [1, 2, 3] -> upb_array([1, 2, 3]). + upb_array *arr = upb_array_new(arena, upb_fielddef_type(f)); + HashTable *table = HASH_OF(val); + HashPosition pos; + upb_fieldtype_t type = upb_fielddef_type(f); + const Descriptor *desc = Descriptor_GetFromFieldDef(f); -// ----------------------------------------------------------------------------- -// C RepeatedField Utilities -// ----------------------------------------------------------------------------- + zend_hash_internal_pointer_reset_ex(table, &pos); + + while (true) { + zval *zv = zend_hash_get_current_data_ex(table, &pos); + upb_msgval val; -void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC) { - HashTable *ht = PHP_PROTO_HASH_OF(intern->array); - void *value; + if (!zv) return arr; - if (intern->type == UPB_TYPE_MESSAGE) { - if (php_proto_zend_hash_index_find_zval(ht, index, (void **)&value) == - FAILURE) { - zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index); - return NULL; + if (!Convert_PhpToUpbAutoWrap(zv, &val, type, desc, arena)) { + return NULL; + } + + upb_array_append(arr, val, arena); + zend_hash_move_forward_ex(table, &pos); } - } else { - if (php_proto_zend_hash_index_find_mem(ht, index, (void **)&value) == - FAILURE) { - zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index); - return NULL; + } else if (Z_TYPE_P(val) == IS_OBJECT && + Z_OBJCE_P(val) == RepeatedField_class_entry) { + // Unwrap existing RepeatedField object to get the upb_array* inside. + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(val); + const Descriptor *desc = Descriptor_GetFromFieldDef(f); + + if (intern->type != upb_fielddef_type(f) || intern->desc != desc) { + php_error_docref(NULL, E_USER_ERROR, + "Wrong type for this repeated field."); } - } - - return value; -} -void repeated_field_push_native(RepeatedField *intern, void *value) { - HashTable *ht = PHP_PROTO_HASH_OF(intern->array); - int size = native_slot_size(intern->type); - if (intern->type == UPB_TYPE_MESSAGE) { - php_proto_zend_hash_next_index_insert_zval(ht, value); + upb_arena_fuse(arena, Arena_Get(&intern->arena)); + return intern->array; } else { - php_proto_zend_hash_next_index_insert_mem(ht, (void **)value, size, NULL); + php_error_docref(NULL, E_USER_ERROR, "Must be a repeated field"); + return NULL; } } -void repeated_field_ensure_created( - const upb_fielddef *field, - CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) { - if (ZVAL_IS_NULL(CACHED_PTR_TO_ZVAL_PTR(repeated_field))) { - zval_ptr_dtor(repeated_field); -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(CACHED_PTR_TO_ZVAL_PTR(repeated_field)); -#endif - repeated_field_create_with_field(repeated_field_type, field, - repeated_field PHP_PROTO_TSRMLS_CC); - } -} - -void repeated_field_create_with_field( - zend_class_entry *ce, const upb_fielddef *field, - CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) { - upb_fieldtype_t type = upb_fielddef_type(field); - const zend_class_entry *msg_ce = field_type_class(field PHP_PROTO_TSRMLS_CC); - repeated_field_create_with_type(ce, type, msg_ce, - repeated_field PHP_PROTO_TSRMLS_CC); -} - -void repeated_field_create_with_type( - zend_class_entry *ce, upb_fieldtype_t type, const zend_class_entry *msg_ce, - CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC) { - CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(CACHED_PTR_TO_ZVAL_PTR(repeated_field), - repeated_field_type); - - RepeatedField *intern = - UNBOX(RepeatedField, CACHED_TO_ZVAL_PTR(*repeated_field)); - intern->type = type; - intern->msg_ce = msg_ce; -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(intern->array); - repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC); -#else - repeated_field_array_init(&intern->array, intern->type, 0 ZEND_FILE_LINE_CC); -#endif - - // TODO(teboring): Link class entry for message and enum -} - - -// ----------------------------------------------------------------------------- -// PHP RepeatedField Methods -// ----------------------------------------------------------------------------- +// RepeatedField PHP methods /////////////////////////////////////////////////// /** + * RepeatedField::__construct() + * * Constructs an instance of RepeatedField. * @param long Type of the stored element. - * @param string Message/Enum class name (message/enum fields only). + * @param string Message/Enum class. */ PHP_METHOD(RepeatedField, __construct) { - long type; + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); + upb_arena *arena = Arena_Get(&intern->arena); + zend_long type; zend_class_entry* klass = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|C", &type, &klass) == - FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|C", &type, &klass) != SUCCESS) { return; } - RepeatedField *intern = UNBOX(RepeatedField, getThis()); - intern->type = to_fieldtype(type); - intern->msg_ce = klass; - -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(intern->array); - repeated_field_array_init(intern->array, intern->type, 0 ZEND_FILE_LINE_CC); -#else - repeated_field_array_init(&intern->array, intern->type, 0 ZEND_FILE_LINE_CC); -#endif + intern->type = pbphp_dtype_to_type(type); + intern->desc = Descriptor_GetFromClassEntry(klass); if (intern->type == UPB_TYPE_MESSAGE && klass == NULL) { - zend_error(E_USER_ERROR, "Message type must have concrete class."); + php_error_docref(NULL, E_USER_ERROR, + "Message/enum type must have concrete class."); return; } - // TODO(teboring): Consider enum. + intern->array = upb_array_new(arena, intern->type); + ObjCache_Add(intern->array, &intern->std); } /** + * RepeatedField::append() + * * Append element to the end of the repeated field. * @param object The element to be added. */ PHP_METHOD(RepeatedField, append) { - zval *value; + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); + upb_arena *arena = Arena_Get(&intern->arena); + zval *php_val; + upb_msgval msgval; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == - FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &php_val) != SUCCESS || + !Convert_PhpToUpb(php_val, &msgval, intern->type, intern->desc, arena)) { return; } - repeated_field_write_dimension(getThis(), NULL, value TSRMLS_CC); + + upb_array_append(intern->array, msgval, arena); } /** - * Check whether the element at given index exists. + * RepeatedField::offsetExists() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * isset($arr[$idx]); + * empty($arr[$idx]); + * * @param long The index to be checked. * @return bool True if the element at the given index exists. */ PHP_METHOD(RepeatedField, offsetExists) { - long index; + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); + zend_long index; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) { return; } - RepeatedField *intern = UNBOX(RepeatedField, getThis()); - - RETURN_BOOL(index >= 0 && - index < zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array))); + RETURN_BOOL(index >= 0 && index < upb_array_size(intern->array)); } /** - * Return the element at the given index. - * This will also be called for: $ele = $arr[0] + * RepeatedField::offsetGet() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * $x = $arr[$idx]; + * * @param long The index of the element to be fetched. * @return object The stored element at given index. * @exception Invalid type for index. * @exception Non-existing index. */ PHP_METHOD(RepeatedField, offsetGet) { - long index; - void *memory; + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); + zend_long index; + upb_msgval msgval; + zval ret; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) { return; } - RepeatedField *intern = UNBOX(RepeatedField, getThis()); - HashTable *table = PHP_PROTO_HASH_OF(intern->array); - - if (intern->type == UPB_TYPE_MESSAGE) { - if (php_proto_zend_hash_index_find_zval(table, index, (void **)&memory) == - FAILURE) { - zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); - return; - } - } else { - if (php_proto_zend_hash_index_find_mem(table, index, (void **)&memory) == - FAILURE) { - zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); - return; - } + if (index < 0 || index >= upb_array_size(intern->array)) { + zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); + return; } - native_slot_get_by_array(intern->type, memory, - ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC); + + msgval = upb_array_get(intern->array, index); + Convert_UpbToPhp(msgval, &ret, intern->type, intern->desc, &intern->arena); + RETURN_ZVAL(&ret, 0, 1); } /** - * Assign the element at the given index. - * This will also be called for: $arr []= $ele and $arr[0] = ele + * RepeatedField::offsetSet() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * $arr[$idx] = $x; + * $arr []= $x; // Append + * * @param long The index of the element to be assigned. * @param object The element to be assigned. * @exception Invalid type for index. @@ -418,140 +297,306 @@ PHP_METHOD(RepeatedField, offsetGet) { * @exception Incorrect type of the element. */ PHP_METHOD(RepeatedField, offsetSet) { - zval *index, *value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == - FAILURE) { + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); + upb_arena *arena = Arena_Get(&intern->arena); + size_t size = upb_array_size(intern->array); + zval *offset, *val; + int64_t index; + upb_msgval msgval; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &offset, &val) != SUCCESS) { + return; + } + + if (Z_TYPE_P(offset) == IS_NULL) { + index = size; + } else if (!Convert_PhpToInt64(offset, &index)) { return; } - repeated_field_write_dimension(getThis(), index, value TSRMLS_CC); + + if (!Convert_PhpToUpb(val, &msgval, intern->type, intern->desc, arena)) { + return; + } + + if (index > size) { + zend_error(E_USER_ERROR, "Element at index %ld doesn't exist.\n", index); + } else if (index == size) { + upb_array_append(intern->array, msgval, Arena_Get(&intern->arena)); + } else { + upb_array_set(intern->array, index, msgval); + } } /** - * Remove the element at the given index. - * This will also be called for: unset($arr) + * RepeatedField::offsetUnset() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * unset($arr[$idx]); + * * @param long The index of the element to be removed. * @exception Invalid type for index. * @exception The element to be removed is not at the end of the RepeatedField. */ PHP_METHOD(RepeatedField, offsetUnset) { - long index; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); + zend_long index; + zend_long size = upb_array_size(intern->array); + + // Only the element at the end of the array can be removed. + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) != SUCCESS) { return; } - RepeatedField *intern = UNBOX(RepeatedField, getThis()); - - // Only the element at the end of the array can be removed. - if (index == -1 || - index != (zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)) - 1)) { - zend_error(E_USER_ERROR, "Cannot remove element at %ld.\n", index); + if (size == 0 || index != size - 1) { + php_error_docref(NULL, E_USER_ERROR, "Cannot remove element at %ld.\n", + index); return; } - zend_hash_index_del(PHP_PROTO_HASH_OF(intern->array), index); + upb_array_resize(intern->array, size - 1, Arena_Get(&intern->arena)); } /** + * RepeatedField::count() + * + * Implements the Countable interface. Invoked when PHP code calls: + * + * $len = count($arr); * Return the number of stored elements. * This will also be called for: count($arr) * @return long The number of stored elements. */ PHP_METHOD(RepeatedField, count) { - RepeatedField *intern = UNBOX(RepeatedField, getThis()); + RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } - RETURN_LONG(zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array))); + RETURN_LONG(upb_array_size(intern->array)); } /** - * Return the beginning iterator. - * This will also be called for: foreach($arr) + * RepeatedField::getIterator() + * + * Implements the IteratorAggregate interface. Invoked when PHP code calls: + * + * foreach ($arr) {} + * * @return object Beginning iterator. */ PHP_METHOD(RepeatedField, getIterator) { - CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(return_value, - repeated_field_iter_type); - - RepeatedField *intern = UNBOX(RepeatedField, getThis()); - RepeatedFieldIter *iter = UNBOX(RepeatedFieldIter, return_value); - iter->repeated_field = intern; - iter->position = 0; + zval ret; + RepeatedFieldIter_make(&ret, getThis()); + RETURN_ZVAL(&ret, 0, 1); } +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_void, 0) +ZEND_END_ARG_INFO() + +static zend_function_entry repeated_field_methods[] = { + PHP_ME(RepeatedField, __construct, NULL, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedField, append, NULL, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedField, count, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedField, getIterator, arginfo_void, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + // ----------------------------------------------------------------------------- -// RepeatedFieldIter creation/destruction +// PHP RepeatedFieldIter // ----------------------------------------------------------------------------- -// Define object free method. -PHP_PROTO_OBJECT_EMPTY_FREE_START(RepeatedFieldIter, repeated_field_iter) -PHP_PROTO_OBJECT_FREE_END +typedef struct { + zend_object std; + zval repeated_field; + zend_long position; +} RepeatedFieldIter; -PHP_PROTO_OBJECT_EMPTY_DTOR_START(RepeatedFieldIter, repeated_field_iter) -PHP_PROTO_OBJECT_DTOR_END +zend_class_entry *RepeatedFieldIter_class_entry; +static zend_object_handlers repeated_field_iter_object_handlers; -// Define object create method. -PHP_PROTO_OBJECT_CREATE_START(RepeatedFieldIter, repeated_field_iter) -intern->repeated_field = NULL; -intern->position = 0; -PHP_PROTO_OBJECT_CREATE_END(RepeatedFieldIter, repeated_field_iter) +/** + * RepeatedFieldIter_create() + * + * PHP class entry function to allocate and initialize a new RepeatedFieldIter + * object. + */ +zend_object* RepeatedFieldIter_create(zend_class_entry *class_type) { + RepeatedFieldIter *intern = emalloc(sizeof(RepeatedFieldIter)); + zend_object_std_init(&intern->std, class_type); + intern->std.handlers = &repeated_field_iter_object_handlers; + ZVAL_NULL(&intern->repeated_field); + intern->position = 0; + // Skip object_properties_init(), we don't allow derived classes. + return &intern->std; +} -// Init class entry. -PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\RepeatedFieldIter", - RepeatedFieldIter, repeated_field_iter) -zend_class_implements(repeated_field_iter_type TSRMLS_CC, 1, zend_ce_iterator); -PHP_PROTO_INIT_CLASS_END +/** + * RepeatedFieldIter_dtor() + * + * Object handler to destroy a RepeatedFieldIter. This releases all resources + * associated with the message. Note that it is possible to access a destroyed + * object from PHP in rare cases. + */ +static void RepeatedFieldIter_dtor(zend_object* obj) { + RepeatedFieldIter* intern = (RepeatedFieldIter*)obj; + zval_ptr_dtor(&intern->repeated_field); + zend_object_std_dtor(&intern->std); +} -// ----------------------------------------------------------------------------- -// PHP RepeatedFieldIter Methods -// ----------------------------------------------------------------------------- +/** + * RepeatedFieldIter_make() + * + * C function to create a RepeatedFieldIter. + */ +static void RepeatedFieldIter_make(zval *val, zval *repeated_field) { + RepeatedFieldIter *iter; + ZVAL_OBJ(val, RepeatedFieldIter_class_entry->create_object( + RepeatedFieldIter_class_entry)); + iter = (RepeatedFieldIter*)Z_OBJ_P(val); + ZVAL_COPY(&iter->repeated_field, repeated_field); +} +/* + * When a user writes: + * + * foreach($arr as $key => $val) {} + * + * PHP's iterator protocol is: + * + * $iter = $arr->getIterator(); + * for ($iter->rewind(); $iter->valid(); $iter->next()) { + * $key = $iter->key(); + * $val = $iter->current(); + * } + */ + +/** + * RepeatedFieldIter::rewind() + * + * Implements the Iterator interface. Sets the iterator to the first element. + */ PHP_METHOD(RepeatedFieldIter, rewind) { - RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis()); + RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); intern->position = 0; } +/** + * RepeatedFieldIter::current() + * + * Implements the Iterator interface. Returns the current value. + */ PHP_METHOD(RepeatedFieldIter, current) { - RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis()); - RepeatedField *repeated_field = intern->repeated_field; - - long index = 0; - void *memory; + RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); + RepeatedField *field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field); + upb_array *array = field->array; + zend_long index = intern->position; + upb_msgval msgval; + zval ret; + + if (index < 0 || index >= upb_array_size(array)) { + zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); + } - HashTable *table = PHP_PROTO_HASH_OF(repeated_field->array); + msgval = upb_array_get(array, index); - if (repeated_field->type == UPB_TYPE_MESSAGE) { - if (php_proto_zend_hash_index_find_zval(table, intern->position, - (void **)&memory) == FAILURE) { - zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); - return; - } - } else { - if (php_proto_zend_hash_index_find_mem(table, intern->position, - (void **)&memory) == FAILURE) { - zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); - return; - } - } - native_slot_get_by_array(repeated_field->type, memory, - ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC); + Convert_UpbToPhp(msgval, &ret, field->type, field->desc, &field->arena); + RETURN_ZVAL(&ret, 0, 1); } +/** + * RepeatedFieldIter::key() + * + * Implements the Iterator interface. Returns the current key. + */ PHP_METHOD(RepeatedFieldIter, key) { - RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis()); + RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); RETURN_LONG(intern->position); } +/** + * RepeatedFieldIter::next() + * + * Implements the Iterator interface. Advances to the next element. + */ PHP_METHOD(RepeatedFieldIter, next) { - RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis()); + RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); ++intern->position; } +/** + * RepeatedFieldIter::valid() + * + * Implements the Iterator interface. Returns true if this is a valid element. + */ PHP_METHOD(RepeatedFieldIter, valid) { - RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis()); - RETURN_BOOL(zend_hash_num_elements(PHP_PROTO_HASH_OF( - intern->repeated_field->array)) > intern->position); + RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); + RepeatedField *field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field); + RETURN_BOOL(intern->position < upb_array_size(field->array)); +} + +static zend_function_entry repeated_field_iter_methods[] = { + PHP_ME(RepeatedFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(RepeatedFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + +// ----------------------------------------------------------------------------- +// Module init. +// ----------------------------------------------------------------------------- + +/** + * Array_ModuleInit() + * + * Called when the C extension is loaded to register all types. + */ +void Array_ModuleInit() { + zend_class_entry tmp_ce; + zend_object_handlers *h; + + // RepeatedField. + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedField", + repeated_field_methods); + + RepeatedField_class_entry = zend_register_internal_class(&tmp_ce); + zend_class_implements(RepeatedField_class_entry, 3, spl_ce_ArrayAccess, + zend_ce_aggregate, spl_ce_Countable); + RepeatedField_class_entry->ce_flags |= ZEND_ACC_FINAL; + RepeatedField_class_entry->create_object = RepeatedField_create; + + h = &RepeatedField_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = RepeatedField_destructor; + h->get_properties = RepeatedField_GetProperties; + h->get_property_ptr_ptr = RepeatedField_GetPropertyPtrPtr; + + // RepeatedFieldIter + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedFieldIter", + repeated_field_iter_methods); + + RepeatedFieldIter_class_entry = zend_register_internal_class(&tmp_ce); + zend_class_implements(RepeatedFieldIter_class_entry, 1, zend_ce_iterator); + RepeatedFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL; + RepeatedFieldIter_class_entry->create_object = RepeatedFieldIter_create; + + h = &repeated_field_iter_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = RepeatedFieldIter_dtor; } diff --git a/php/ext/google/protobuf2/array.h b/php/ext/google/protobuf/array.h similarity index 100% rename from php/ext/google/protobuf2/array.h rename to php/ext/google/protobuf/array.h diff --git a/php/ext/google/protobuf/builtin_descriptors.inc b/php/ext/google/protobuf/builtin_descriptors.inc deleted file mode 100644 index 1bb5dbfa85b9..000000000000 --- a/php/ext/google/protobuf/builtin_descriptors.inc +++ /dev/null @@ -1,635 +0,0 @@ -unsigned char descriptor_proto[] = { - 0x0a, 0x9b, 0x3b, 0x0a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x0f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x4d, 0x0a, 0x11, 0x46, 0x69, - 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, - 0x53, 0x65, 0x74, 0x12, 0x38, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x04, 0x66, 0x69, 0x6c, - 0x65, 0x22, 0xe4, 0x04, 0x0a, 0x13, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, - 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, - 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x70, - 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x2b, 0x0a, 0x11, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, - 0x65, 0x6e, 0x63, 0x79, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x05, 0x52, 0x10, - 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, - 0x65, 0x6e, 0x63, 0x79, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x65, 0x61, 0x6b, - 0x5f, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x0b, 0x20, 0x03, 0x28, 0x05, 0x52, 0x0e, 0x77, 0x65, 0x61, 0x6b, 0x44, - 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x43, 0x0a, - 0x0c, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x0b, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x65, 0x6e, - 0x75, 0x6d, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, - 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, - 0x6f, 0x74, 0x6f, 0x52, 0x08, 0x65, 0x6e, 0x75, 0x6d, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x41, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, - 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x43, 0x0a, 0x09, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, - 0x65, 0x6c, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, - 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x07, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x49, 0x0a, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, - 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x52, 0x0e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x79, 0x6e, 0x74, - 0x61, 0x78, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x79, - 0x6e, 0x74, 0x61, 0x78, 0x22, 0xb9, 0x06, 0x0a, 0x0f, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3b, 0x0a, 0x05, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, - 0x74, 0x6f, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x43, 0x0a, - 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x09, 0x65, 0x78, 0x74, - 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, 0x0b, 0x6e, 0x65, - 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x52, 0x0a, 0x6e, 0x65, 0x73, 0x74, 0x65, 0x64, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x41, 0x0a, 0x09, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x52, 0x08, - 0x65, 0x6e, 0x75, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x58, 0x0a, 0x0f, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x61, - 0x6e, 0x67, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x0e, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x12, 0x44, 0x0a, 0x0a, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x5f, - 0x64, 0x65, 0x63, 0x6c, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4f, 0x6e, 0x65, 0x6f, 0x66, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x52, 0x09, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x44, 0x65, 0x63, 0x6c, - 0x12, 0x39, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x55, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x5f, - 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x0d, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x4e, - 0x61, 0x6d, 0x65, 0x1a, 0x7a, 0x0a, 0x0e, 0x45, 0x78, 0x74, 0x65, 0x6e, - 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x65, - 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x65, 0x6e, - 0x64, 0x12, 0x40, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x61, - 0x6e, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x37, 0x0a, 0x0d, 0x52, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x03, 0x65, 0x6e, 0x64, 0x22, 0x7c, 0x0a, 0x15, 0x45, 0x78, 0x74, 0x65, - 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x58, 0x0a, 0x14, 0x75, 0x6e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, - 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2a, - 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, 0x98, - 0x06, 0x0a, 0x14, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x41, 0x0a, 0x05, 0x6c, - 0x61, 0x62, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2b, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x12, 0x3e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x79, 0x70, 0x65, - 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x79, - 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x74, 0x79, 0x70, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x6e, - 0x64, 0x65, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, - 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0c, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x6e, 0x65, 0x6f, - 0x66, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x0a, 0x6f, 0x6e, 0x65, 0x6f, 0x66, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x12, 0x1b, 0x0a, 0x09, 0x6a, 0x73, 0x6f, 0x6e, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6a, 0x73, - 0x6f, 0x6e, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x6f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x22, 0xb6, 0x02, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x4f, 0x55, - 0x42, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x02, 0x12, 0x0e, 0x0a, - 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, - 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x49, - 0x4e, 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x05, 0x12, 0x10, - 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x58, 0x45, 0x44, - 0x36, 0x34, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x46, 0x49, 0x58, 0x45, 0x44, 0x33, 0x32, 0x10, 0x07, 0x12, 0x0d, - 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x4f, 0x4f, 0x4c, 0x10, - 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, - 0x52, 0x49, 0x4e, 0x47, 0x10, 0x09, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, 0x0a, 0x12, 0x10, - 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x45, 0x53, 0x53, 0x41, - 0x47, 0x45, 0x10, 0x0b, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x0c, 0x12, 0x0f, 0x0a, 0x0b, - 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, - 0x0d, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, - 0x55, 0x4d, 0x10, 0x0e, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x53, 0x46, 0x49, 0x58, 0x45, 0x44, 0x33, 0x32, 0x10, 0x0f, 0x12, - 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x46, 0x49, 0x58, - 0x45, 0x44, 0x36, 0x34, 0x10, 0x10, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, - 0x50, 0x45, 0x5f, 0x53, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, 0x11, 0x12, - 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x49, 0x4e, 0x54, - 0x36, 0x34, 0x10, 0x12, 0x22, 0x43, 0x0a, 0x05, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x4f, - 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x01, 0x12, 0x12, 0x0a, - 0x0e, 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, - 0x52, 0x45, 0x44, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x41, 0x42, - 0x45, 0x4c, 0x5f, 0x52, 0x45, 0x50, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, - 0x03, 0x22, 0x63, 0x0a, 0x14, 0x4f, 0x6e, 0x65, 0x6f, 0x66, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4f, 0x6e, 0x65, - 0x6f, 0x66, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xe3, 0x02, 0x0a, 0x13, 0x45, - 0x6e, 0x75, 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, - 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x44, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x5d, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x64, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x36, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, - 0x75, 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x65, - 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x52, - 0x0d, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x61, 0x6e, - 0x67, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, - 0x65, 0x64, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0c, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x4e, - 0x61, 0x6d, 0x65, 0x1a, 0x3b, 0x0a, 0x11, 0x45, 0x6e, 0x75, 0x6d, 0x52, - 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x61, 0x6e, 0x67, 0x65, - 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, - 0x03, 0x65, 0x6e, 0x64, 0x22, 0x83, 0x01, 0x0a, 0x18, 0x45, 0x6e, 0x75, - 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6e, - 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x3b, 0x0a, 0x07, 0x6f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x07, 0x6f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa7, 0x01, 0x0a, 0x16, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3e, 0x0a, 0x06, 0x6d, 0x65, 0x74, - 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x39, 0x0a, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x89, 0x02, 0x0a, - 0x15, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6e, - 0x70, 0x75, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, - 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x38, - 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, - 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x10, - 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x69, 0x6e, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, - 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0f, 0x63, 0x6c, 0x69, 0x65, 0x6e, - 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x12, 0x30, - 0x0a, 0x10, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x72, - 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, - 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0f, 0x73, 0x65, 0x72, - 0x76, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x69, 0x6e, 0x67, - 0x22, 0x92, 0x09, 0x0a, 0x0b, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6a, 0x61, 0x76, 0x61, - 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x6a, 0x61, 0x76, 0x61, 0x50, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x6a, 0x61, 0x76, 0x61, 0x5f, - 0x6f, 0x75, 0x74, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6a, - 0x61, 0x76, 0x61, 0x4f, 0x75, 0x74, 0x65, 0x72, 0x43, 0x6c, 0x61, 0x73, - 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x35, 0x0a, 0x13, 0x6a, 0x61, 0x76, - 0x61, 0x5f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x66, - 0x69, 0x6c, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, - 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x11, 0x6a, 0x61, 0x76, 0x61, 0x4d, - 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, - 0x12, 0x44, 0x0a, 0x1d, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x67, 0x65, 0x6e, - 0x65, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x65, 0x71, 0x75, 0x61, 0x6c, 0x73, - 0x5f, 0x61, 0x6e, 0x64, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x08, 0x42, 0x02, 0x18, 0x01, 0x52, 0x19, 0x6a, 0x61, 0x76, - 0x61, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x45, 0x71, 0x75, - 0x61, 0x6c, 0x73, 0x41, 0x6e, 0x64, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3a, - 0x0a, 0x16, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x73, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x5f, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x75, 0x74, 0x66, 0x38, - 0x18, 0x1b, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, - 0x65, 0x52, 0x13, 0x6a, 0x61, 0x76, 0x61, 0x53, 0x74, 0x72, 0x69, 0x6e, - 0x67, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x74, 0x66, 0x38, 0x12, 0x53, - 0x0a, 0x0c, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x5f, 0x66, - 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x29, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x4d, - 0x6f, 0x64, 0x65, 0x3a, 0x05, 0x53, 0x50, 0x45, 0x45, 0x44, 0x52, 0x0b, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x46, 0x6f, 0x72, 0x12, - 0x1d, 0x0a, 0x0a, 0x67, 0x6f, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x67, 0x6f, 0x50, - 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x35, 0x0a, 0x13, 0x63, 0x63, - 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08, 0x3a, - 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x11, 0x63, 0x63, 0x47, 0x65, - 0x6e, 0x65, 0x72, 0x69, 0x63, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x12, 0x39, 0x0a, 0x15, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x67, 0x65, - 0x6e, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, - 0x6c, 0x73, 0x65, 0x52, 0x13, 0x6a, 0x61, 0x76, 0x61, 0x47, 0x65, 0x6e, - 0x65, 0x72, 0x69, 0x63, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x12, 0x35, 0x0a, 0x13, 0x70, 0x79, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, - 0x69, 0x63, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, - 0x12, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, - 0x52, 0x11, 0x70, 0x79, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x53, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x14, 0x70, - 0x68, 0x70, 0x5f, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x2a, 0x20, 0x01, 0x28, - 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x12, 0x70, 0x68, - 0x70, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, - 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x08, - 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x70, - 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2f, 0x0a, 0x10, 0x63, - 0x63, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x61, 0x72, 0x65, - 0x6e, 0x61, 0x73, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, - 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0e, 0x63, 0x63, 0x45, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73, 0x12, 0x2a, 0x0a, 0x11, - 0x6f, 0x62, 0x6a, 0x63, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x70, - 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x24, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0f, 0x6f, 0x62, 0x6a, 0x63, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x50, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x73, 0x68, 0x61, - 0x72, 0x70, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x18, 0x25, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x63, 0x73, 0x68, 0x61, - 0x72, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x73, 0x77, 0x69, 0x66, 0x74, 0x5f, 0x70, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x18, 0x27, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, - 0x77, 0x69, 0x66, 0x74, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x28, - 0x0a, 0x10, 0x70, 0x68, 0x70, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, - 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x28, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0e, 0x70, 0x68, 0x70, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x50, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x68, 0x70, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x29, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x68, 0x70, 0x4e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x68, 0x70, - 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x2c, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x14, 0x70, 0x68, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x72, 0x75, 0x62, 0x79, 0x5f, 0x70, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x18, 0x2d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, - 0x75, 0x62, 0x79, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x58, - 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, - 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, - 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, - 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3a, 0x0a, 0x0c, 0x4f, 0x70, 0x74, 0x69, - 0x6d, 0x69, 0x7a, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x09, 0x0a, 0x05, - 0x53, 0x50, 0x45, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, - 0x4f, 0x44, 0x45, 0x5f, 0x53, 0x49, 0x5a, 0x45, 0x10, 0x02, 0x12, 0x10, - 0x0a, 0x0c, 0x4c, 0x49, 0x54, 0x45, 0x5f, 0x52, 0x55, 0x4e, 0x54, 0x49, - 0x4d, 0x45, 0x10, 0x03, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, - 0x80, 0x80, 0x02, 0x4a, 0x04, 0x08, 0x26, 0x10, 0x27, 0x22, 0xd1, 0x02, - 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3c, 0x0a, 0x17, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, 0x74, 0x5f, 0x77, 0x69, 0x72, 0x65, - 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x14, 0x6d, 0x65, - 0x73, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x74, 0x57, 0x69, 0x72, 0x65, - 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x4c, 0x0a, 0x1f, 0x6e, 0x6f, - 0x5f, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x5f, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x3a, - 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x1c, 0x6e, 0x6f, 0x53, 0x74, - 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x6f, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, - 0x12, 0x25, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, - 0x6c, 0x73, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, - 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x61, 0x70, 0x5f, 0x65, - 0x6e, 0x74, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, - 0x6d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x58, 0x0a, 0x14, - 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, - 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x6e, 0x74, - 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, - 0x02, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, - 0x0a, 0x22, 0xe2, 0x03, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x41, 0x0a, 0x05, 0x63, 0x74, - 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x43, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x06, - 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x52, 0x05, 0x63, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x61, 0x63, 0x6b, 0x65, - 0x64, 0x12, 0x47, 0x0a, 0x06, 0x6a, 0x73, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x2e, 0x4a, 0x53, 0x54, 0x79, 0x70, 0x65, 0x3a, 0x09, 0x4a, 0x53, 0x5f, - 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x52, 0x06, 0x6a, 0x73, 0x74, 0x79, - 0x70, 0x65, 0x12, 0x19, 0x0a, 0x04, 0x6c, 0x61, 0x7a, 0x79, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, - 0x04, 0x6c, 0x61, 0x7a, 0x79, 0x12, 0x25, 0x0a, 0x0a, 0x64, 0x65, 0x70, - 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0a, 0x64, 0x65, - 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x19, 0x0a, 0x04, - 0x77, 0x65, 0x61, 0x6b, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, - 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x04, 0x77, 0x65, 0x61, 0x6b, 0x12, - 0x58, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, - 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0xe7, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, - 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2f, 0x0a, 0x05, 0x43, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, - 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x4f, 0x52, 0x44, 0x10, 0x01, - 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x5f, 0x50, - 0x49, 0x45, 0x43, 0x45, 0x10, 0x02, 0x22, 0x35, 0x0a, 0x06, 0x4a, 0x53, - 0x54, 0x79, 0x70, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x4a, 0x53, 0x5f, 0x4e, - 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4a, - 0x53, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0d, - 0x0a, 0x09, 0x4a, 0x53, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x10, - 0x02, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, - 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x22, 0x73, 0x0a, 0x0c, 0x4f, 0x6e, - 0x65, 0x6f, 0x66, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x58, - 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, - 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, - 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, - 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, - 0x80, 0x80, 0x02, 0x22, 0xc0, 0x01, 0x0a, 0x0b, 0x45, 0x6e, 0x75, 0x6d, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x61, - 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x41, - 0x6c, 0x69, 0x61, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, - 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, - 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x70, - 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x58, 0x0a, 0x14, 0x75, - 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, - 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, - 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x22, 0x9e, 0x01, 0x0a, 0x10, 0x45, - 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, - 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x3a, - 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, - 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x58, 0x0a, 0x14, 0x75, 0x6e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, - 0x9c, 0x01, 0x0a, 0x0e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a, 0x0a, 0x64, 0x65, - 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x21, 0x20, 0x01, - 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, 0x0a, 0x64, - 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x58, 0x0a, - 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, - 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, - 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, - 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, - 0x80, 0x02, 0x22, 0xe0, 0x02, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x68, 0x6f, - 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a, 0x0a, - 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x21, - 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x52, - 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, - 0x71, 0x0a, 0x11, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, - 0x63, 0x79, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x22, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, - 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x49, - 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x3a, 0x13, 0x49, 0x44, 0x45, 0x4d, 0x50, 0x4f, 0x54, - 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x52, 0x10, 0x69, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, 0x6e, 0x63, - 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x58, 0x0a, 0x14, 0x75, 0x6e, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, - 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x50, 0x0a, 0x10, 0x49, 0x64, 0x65, 0x6d, 0x70, 0x6f, 0x74, 0x65, - 0x6e, 0x63, 0x79, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x17, 0x0a, 0x13, - 0x49, 0x44, 0x45, 0x4d, 0x50, 0x4f, 0x54, 0x45, 0x4e, 0x43, 0x59, 0x5f, - 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x13, 0x0a, - 0x0f, 0x4e, 0x4f, 0x5f, 0x53, 0x49, 0x44, 0x45, 0x5f, 0x45, 0x46, 0x46, - 0x45, 0x43, 0x54, 0x53, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x44, - 0x45, 0x4d, 0x50, 0x4f, 0x54, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x2a, 0x09, - 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, 0x9a, 0x03, - 0x0a, 0x13, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, - 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x41, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x74, 0x52, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x64, 0x65, 0x6e, - 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x2c, 0x0a, 0x12, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x5f, - 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x10, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x76, - 0x65, 0x49, 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, - 0x12, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x69, 0x6e, - 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x10, 0x6e, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x49, - 0x6e, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, - 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x74, - 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x61, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x4a, - 0x0a, 0x08, 0x4e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x74, 0x12, 0x1b, - 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x18, - 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x08, 0x6e, 0x61, 0x6d, 0x65, 0x50, - 0x61, 0x72, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x65, 0x78, - 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x02, 0x28, - 0x08, 0x52, 0x0b, 0x69, 0x73, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, - 0x6f, 0x6e, 0x22, 0xa7, 0x02, 0x0a, 0x0e, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x43, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x44, 0x0a, - 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, - 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0xce, 0x01, 0x0a, 0x08, - 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x04, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x05, 0x42, 0x02, - 0x10, 0x01, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x16, 0x0a, 0x04, - 0x73, 0x70, 0x61, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x05, 0x42, 0x02, - 0x10, 0x01, 0x52, 0x04, 0x73, 0x70, 0x61, 0x6e, 0x12, 0x29, 0x0a, 0x10, - 0x6c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, - 0x6c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x65, - 0x6e, 0x74, 0x73, 0x12, 0x2b, 0x0a, 0x11, 0x74, 0x72, 0x61, 0x69, 0x6c, - 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x74, 0x72, 0x61, 0x69, - 0x6c, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x12, 0x3a, 0x0a, 0x19, 0x6c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x5f, - 0x64, 0x65, 0x74, 0x61, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6d, - 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x17, 0x6c, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x74, 0x61, - 0x63, 0x68, 0x65, 0x64, 0x43, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, - 0x22, 0xd1, 0x01, 0x0a, 0x11, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, - 0x65, 0x64, 0x43, 0x6f, 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x4d, - 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x64, 0x43, 0x6f, - 0x64, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x41, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x6d, 0x0a, 0x0a, 0x41, 0x6e, 0x6e, - 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x04, 0x70, - 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x05, 0x42, 0x02, 0x10, - 0x01, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x46, 0x69, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x65, 0x67, 0x69, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x62, 0x65, 0x67, - 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x03, 0x65, 0x6e, 0x64, 0x42, 0x8f, 0x01, 0x0a, - 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x10, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x73, 0x48, 0x01, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2f, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x3b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0xf8, 0x01, 0x01, 0xa2, - 0x02, 0x03, 0x47, 0x50, 0x42, 0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x52, 0x65, 0x66, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e -}; -unsigned int descriptor_proto_len = 7582; diff --git a/php/ext/google/protobuf2/bundled_php.h b/php/ext/google/protobuf/bundled_php.h similarity index 100% rename from php/ext/google/protobuf2/bundled_php.h rename to php/ext/google/protobuf/bundled_php.h diff --git a/php/ext/google/protobuf/config.m4 b/php/ext/google/protobuf/config.m4 index ab032e466b57..3fdcb00480d4 100644 --- a/php/ext/google/protobuf/config.m4 +++ b/php/ext/google/protobuf/config.m4 @@ -4,7 +4,7 @@ if test "$PHP_PROTOBUF" != "no"; then PHP_NEW_EXTENSION( protobuf, - array.c def.c encode_decode.c map.c message.c protobuf.c storage.c type_check.c upb.c utf8.c, + arena.c array.c bundled_php.c convert.c def.c map.c message.c names.c php-upb.c protobuf.c, $ext_shared) fi diff --git a/php/ext/google/protobuf2/convert.c b/php/ext/google/protobuf/convert.c similarity index 100% rename from php/ext/google/protobuf2/convert.c rename to php/ext/google/protobuf/convert.c diff --git a/php/ext/google/protobuf2/convert.h b/php/ext/google/protobuf/convert.h similarity index 100% rename from php/ext/google/protobuf2/convert.h rename to php/ext/google/protobuf/convert.h diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c index 5edcb03516d4..c76134d86baa 100644 --- a/php/ext/google/protobuf/def.c +++ b/php/ext/google/protobuf/def.c @@ -28,326 +28,332 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "def.h" + #include + +// This is not self-contained: it must be after other Zend includes. #include +#include "names.h" +#include "php-upb.h" #include "protobuf.h" -#include "builtin_descriptors.inc" - -// Forward declare. -static void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC); -static void descriptor_free_c(Descriptor* object TSRMLS_DC); - -static void field_descriptor_init_c_instance(FieldDescriptor* intern TSRMLS_DC); -static void field_descriptor_free_c(FieldDescriptor* object TSRMLS_DC); -static void enum_descriptor_init_c_instance(EnumDescriptor* intern TSRMLS_DC); -static void enum_descriptor_free_c(EnumDescriptor* object TSRMLS_DC); - -static void enum_value_descriptor_init_c_instance( - EnumValueDescriptor *intern TSRMLS_DC); -static void enum_value_descriptor_free_c(EnumValueDescriptor *object TSRMLS_DC); +static void CheckUpbStatus(const upb_status* status, const char* msg) { + if (!upb_ok(status)) { + zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(status)); + } +} -static void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC); -static void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC); +static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f); -static void internal_descriptor_pool_free_c( - InternalDescriptorPool *object TSRMLS_DC); -static void internal_descriptor_pool_init_c_instance( - InternalDescriptorPool *pool TSRMLS_DC); +// We use this for objects that should not be created directly from PHP. +static zend_object *CreateHandler_ReturnNull(zend_class_entry *class_type) { + return NULL; // Nobody should call this. +} -static void oneof_descriptor_free_c(Oneof* object TSRMLS_DC); -static void oneof_descriptor_init_c_instance(Oneof* pool TSRMLS_DC); // ----------------------------------------------------------------------------- -// Common Utilities +// EnumValueDescriptor // ----------------------------------------------------------------------------- -static void check_upb_status(const upb_status* status, const char* msg) { - if (!upb_ok(status)) { - zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(status)); - } +typedef struct { + zend_object std; + const char *name; + int32_t number; +} EnumValueDescriptor; + +zend_class_entry *EnumValueDescriptor_class_entry; +static zend_object_handlers EnumValueDescriptor_object_handlers; + +/* + * EnumValueDescriptor_Make() + * + * Function to create an EnumValueDescriptor object from C. + */ +static void EnumValueDescriptor_Make(zval *val, const char *name, + int32_t number) { + EnumValueDescriptor *intern = emalloc(sizeof(EnumValueDescriptor)); + zend_object_std_init(&intern->std, EnumValueDescriptor_class_entry); + intern->std.handlers = &EnumValueDescriptor_object_handlers; + intern->name = name; + intern->number = number; + // Skip object_properties_init(), we don't allow derived classes. + ZVAL_OBJ(val, &intern->std); } -// ----------------------------------------------------------------------------- -// GPBType -// ----------------------------------------------------------------------------- +/* + * EnumValueDescriptor::getName() + * + * Returns the name for this enum value. + */ +PHP_METHOD(EnumValueDescriptor, getName) { + EnumValueDescriptor *intern = (EnumValueDescriptor*)Z_OBJ_P(getThis()); + RETURN_STRING(intern->name); +} -zend_class_entry* gpb_type_type; +/* + * EnumValueDescriptor::getNumber() + * + * Returns the number for this enum value. + */ +PHP_METHOD(EnumValueDescriptor, getNumber) { + EnumValueDescriptor *intern = (EnumValueDescriptor*)Z_OBJ_P(getThis()); + RETURN_LONG(intern->number); +} -static zend_function_entry gpb_type_methods[] = { +static zend_function_entry EnumValueDescriptor_methods[] = { + PHP_ME(EnumValueDescriptor, getName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(EnumValueDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) ZEND_FE_END }; -void gpb_type_init(TSRMLS_D) { - zend_class_entry class_type; - INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBType", - gpb_type_methods); - gpb_type_type = zend_register_internal_class(&class_type TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("DOUBLE"), 1 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("FLOAT"), 2 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("INT64"), 3 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("UINT64"), 4 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("INT32"), 5 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("FIXED64"), 6 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("FIXED32"), 7 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("BOOL"), 8 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("STRING"), 9 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("GROUP"), 10 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("MESSAGE"), 11 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("BYTES"), 12 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("UINT32"), 13 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("ENUM"), 14 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("SFIXED32"), - 15 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("SFIXED64"), - 16 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("SINT32"), 17 TSRMLS_CC); - zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18 TSRMLS_CC); -} - // ----------------------------------------------------------------------------- -// Descriptor +// EnumDescriptor // ----------------------------------------------------------------------------- -static zend_function_entry descriptor_methods[] = { - PHP_ME(Descriptor, getClass, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getFullName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getField, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getOneofDecl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getOneofDeclCount, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; +typedef struct { + zend_object std; + const upb_enumdef *enumdef; +} EnumDescriptor; -DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Descriptor"); +zend_class_entry *EnumDescriptor_class_entry; +static zend_object_handlers EnumDescriptor_object_handlers; -static void descriptor_free_c(Descriptor *self TSRMLS_DC) { -} +void EnumDescriptor_FromClassEntry(zval *val, zend_class_entry *ce) { + // To differentiate enums from classes, we pointer-tag the class entry. + void* key = (void*)((uintptr_t)ce | 1); + PBPHP_ASSERT(key != ce); -static void descriptor_init_c_instance(Descriptor *desc TSRMLS_DC) { - desc->intern = NULL; -} + if (ce == NULL) { + ZVAL_NULL(val); + return; + } -PHP_METHOD(Descriptor, getClass) { - Descriptor* desc = UNBOX(Descriptor, getThis()); - DescriptorInternal* intern = desc->intern; - register_class(intern, false TSRMLS_CC); -#if PHP_MAJOR_VERSION < 7 - const char* classname = intern->klass->name; -#else - const char* classname = ZSTR_VAL(intern->klass->name); -#endif - PHP_PROTO_RETVAL_STRINGL(classname, strlen(classname), 1); -} + if (!ObjCache_Get(key, val)) { + const upb_enumdef *e = NameMap_GetEnum(ce); + if (!e) { + ZVAL_NULL(val); + return; + } + EnumDescriptor* ret = emalloc(sizeof(EnumDescriptor)); + zend_object_std_init(&ret->std, EnumDescriptor_class_entry); + ret->std.handlers = &EnumDescriptor_object_handlers; + ret->enumdef = e; + ObjCache_Add(key, &ret->std); -PHP_METHOD(Descriptor, getFullName) { - Descriptor* desc = UNBOX(Descriptor, getThis()); - DescriptorInternal* intern = desc->intern; - const char* fullname = upb_msgdef_fullname(intern->msgdef); - PHP_PROTO_RETVAL_STRINGL(fullname, strlen(fullname), 1); -} + // Prevent this from ever being collected (within a request). + GC_ADDREF(&ret->std); -PHP_METHOD(Descriptor, getField) { - long index; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { - zend_error(E_USER_ERROR, "Expect integer for index.\n"); - return; + ZVAL_OBJ(val, &ret->std); } +} - Descriptor* desc = UNBOX(Descriptor, getThis()); - DescriptorInternal* intern = desc->intern; - int field_num = upb_msgdef_numfields(intern->msgdef); - if (index < 0 || index >= field_num) { - zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); - return; - } +void EnumDescriptor_FromEnumDef(zval *val, const upb_enumdef *m) { + if (!m) { + ZVAL_NULL(val); + } else { + char *classname = + GetPhpClassname(upb_enumdef_file(m), upb_enumdef_fullname(m)); + zend_string *str = zend_string_init(classname, strlen(classname), 0); + zend_class_entry *ce = zend_lookup_class(str); // May autoload the class. - upb_msg_field_iter iter; - int i; - for(upb_msg_field_begin(&iter, intern->msgdef), i = 0; - !upb_msg_field_done(&iter) && i < index; - upb_msg_field_next(&iter), i++); - const upb_fielddef *field = upb_msg_iter_field(&iter); + zend_string_release (str); - PHP_PROTO_HASHTABLE_VALUE field_hashtable_value = get_def_obj(field); - if (field_hashtable_value == NULL) { -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(field_hashtable_value); - ZVAL_OBJ(field_hashtable_value, field_descriptor_type->create_object( - field_descriptor_type TSRMLS_CC)); - Z_DELREF_P(field_hashtable_value); -#else - field_hashtable_value = - field_descriptor_type->create_object(field_descriptor_type TSRMLS_CC); - GC_DELREF(field_hashtable_value); -#endif - FieldDescriptor *field_php = - UNBOX_HASHTABLE_VALUE(FieldDescriptor, field_hashtable_value); - field_php->fielddef = field; - add_def_obj(field, field_hashtable_value); - } + if (!ce) { + zend_error(E_ERROR, "Couldn't load generated class %s", classname); + } -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(field_hashtable_value, 1, 0); -#else - GC_ADDREF(field_hashtable_value); - RETURN_OBJ(field_hashtable_value); -#endif + free(classname); + EnumDescriptor_FromClassEntry(val, ce); + } } -PHP_METHOD(Descriptor, getFieldCount) { - Descriptor* desc = UNBOX(Descriptor, getThis()); - DescriptorInternal* intern = desc->intern; - RETURN_LONG(upb_msgdef_numfields(intern->msgdef)); -} +/* + * EnumDescriptor::getValue() + * + * Returns an EnumValueDescriptor for this index. Note: we are not looking + * up by numeric enum value, but by the index in the list of enum values. + */ +PHP_METHOD(EnumDescriptor, getValue) { + EnumDescriptor *intern = (EnumDescriptor*)Z_OBJ_P(getThis()); + zend_long index; + zval ret; -PHP_METHOD(Descriptor, getOneofDecl) { - long index; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == FAILURE) { zend_error(E_USER_ERROR, "Expect integer for index.\n"); return; } - Descriptor* desc = UNBOX(Descriptor, getThis()); - DescriptorInternal* intern = desc->intern; - int field_num = upb_msgdef_numoneofs(intern->msgdef); + int field_num = upb_enumdef_numvals(intern->enumdef); if (index < 0 || index >= field_num) { zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); return; } - upb_msg_oneof_iter iter; + upb_enum_iter iter; int i; - for(upb_msg_oneof_begin(&iter, intern->msgdef), i = 0; - !upb_msg_oneof_done(&iter) && i < index; - upb_msg_oneof_next(&iter), i++); - const upb_oneofdef *oneof = upb_msg_iter_oneof(&iter); + for(upb_enum_begin(&iter, intern->enumdef), i = 0; + !upb_enum_done(&iter) && i < index; + upb_enum_next(&iter), i++); - ZVAL_OBJ(return_value, oneof_descriptor_type->create_object( - oneof_descriptor_type TSRMLS_CC)); - Oneof *oneof_php = UNBOX(Oneof, return_value); - oneof_php->oneofdef = oneof; + EnumValueDescriptor_Make(&ret, upb_enum_iter_name(&iter), + upb_enum_iter_number(&iter)); + RETURN_ZVAL(&ret, 0, 1); } -PHP_METHOD(Descriptor, getOneofDeclCount) { - Descriptor* desc = UNBOX(Descriptor, getThis()); - DescriptorInternal* intern = desc->intern; - RETURN_LONG(upb_msgdef_numoneofs(intern->msgdef)); +/* + * EnumDescriptor::getValueCount() + * + * Returns the number of values in this enum. + */ +PHP_METHOD(EnumDescriptor, getValueCount) { + EnumDescriptor *intern = (EnumDescriptor*)Z_OBJ_P(getThis()); + RETURN_LONG(upb_enumdef_numvals(intern->enumdef)); } -// ----------------------------------------------------------------------------- -// EnumDescriptor -// ----------------------------------------------------------------------------- +/* + * EnumDescriptor::getPublicDescriptor() + * + * Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not + * have two separate EnumDescriptor classes. We use a single class for both + * the public and private descriptor. + */ +PHP_METHOD(EnumDescriptor, getPublicDescriptor) { + RETURN_ZVAL(getThis(), 1, 0); +} -static zend_function_entry enum_descriptor_methods[] = { - PHP_ME(EnumDescriptor, getValue, NULL, ZEND_ACC_PUBLIC) +static zend_function_entry EnumDescriptor_methods[] = { + PHP_ME(EnumDescriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC) PHP_ME(EnumDescriptor, getValueCount, NULL, ZEND_ACC_PUBLIC) + PHP_ME(EnumDescriptor, getValue, NULL, ZEND_ACC_PUBLIC) ZEND_FE_END }; -DEFINE_CLASS(EnumDescriptor, enum_descriptor, - "Google\\Protobuf\\EnumDescriptor"); +// ----------------------------------------------------------------------------- +// Oneof +// ----------------------------------------------------------------------------- + +typedef struct { + zend_object std; + const upb_oneofdef *oneofdef; +} OneofDescriptor; + +zend_class_entry *OneofDescriptor_class_entry; +static zend_object_handlers OneofDescriptor_object_handlers; + +static void OneofDescriptor_FromOneofDef(zval *val, const upb_oneofdef *o) { + if (o == NULL) { + ZVAL_NULL(val); + return; + } + + if (!ObjCache_Get(o, val)) { + OneofDescriptor* ret = emalloc(sizeof(OneofDescriptor)); + zend_object_std_init(&ret->std, OneofDescriptor_class_entry); + ret->std.handlers = &OneofDescriptor_object_handlers; + ret->oneofdef = o; + ObjCache_Add(o, &ret->std); + + // Prevent this from ever being collected (within a request). + GC_ADDREF(&ret->std); -static void enum_descriptor_free_c(EnumDescriptor *self TSRMLS_DC) { + ZVAL_OBJ(val, &ret->std); + } } -static void enum_descriptor_init_c_instance(EnumDescriptor *self TSRMLS_DC) { - self->intern = NULL; +/* + * OneofDescriptor::getName() + * + * Returns the name of this oneof. + */ +PHP_METHOD(OneofDescriptor, getName) { + OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis()); + RETURN_STRING(upb_oneofdef_name(intern->oneofdef)); } -PHP_METHOD(EnumDescriptor, getValue) { - long index; +/* + * OneofDescriptor::getField() + * + * Returns a field from this oneof. The given index must be in the range + * [0, getFieldCount() - 1]. + */ +PHP_METHOD(OneofDescriptor, getField) { + OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis()); + zend_long index; + zval ret; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == FAILURE) { zend_error(E_USER_ERROR, "Expect integer for index.\n"); return; } - EnumDescriptor *desc = UNBOX(EnumDescriptor, getThis()); - EnumDescriptorInternal *intern = desc->intern; - int field_num = upb_enumdef_numvals(intern->enumdef); + int field_num = upb_oneofdef_numfields(intern->oneofdef); if (index < 0 || index >= field_num) { zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); return; } - upb_enum_iter iter; + upb_oneof_iter iter; int i; - for(upb_enum_begin(&iter, intern->enumdef), i = 0; - !upb_enum_done(&iter) && i < index; - upb_enum_next(&iter), i++); + for(upb_oneof_begin(&iter, intern->oneofdef), i = 0; + !upb_oneof_done(&iter) && i < index; + upb_oneof_next(&iter), i++); + const upb_fielddef *field = upb_oneof_iter_field(&iter); - ZVAL_OBJ(return_value, enum_value_descriptor_type->create_object( - enum_value_descriptor_type TSRMLS_CC)); - EnumValueDescriptor *enum_value_php = - UNBOX(EnumValueDescriptor, return_value); - enum_value_php->name = upb_enum_iter_name(&iter); - enum_value_php->number = upb_enum_iter_number(&iter); + FieldDescriptor_FromFieldDef(&ret, field); + RETURN_ZVAL(&ret, 1, 0); } -PHP_METHOD(EnumDescriptor, getValueCount) { - EnumDescriptor *desc = UNBOX(EnumDescriptor, getThis()); - EnumDescriptorInternal *intern = desc->intern; - RETURN_LONG(upb_enumdef_numvals(intern->enumdef)); +/* + * OneofDescriptor::getFieldCount() + * + * Returns the number of fields in this oneof. + */ +PHP_METHOD(OneofDescriptor, getFieldCount) { + OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis()); + RETURN_LONG(upb_oneofdef_numfields(intern->oneofdef)); } -// ----------------------------------------------------------------------------- -// EnumValueDescriptor -// ----------------------------------------------------------------------------- - -static zend_function_entry enum_value_descriptor_methods[] = { - PHP_ME(EnumValueDescriptor, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValueDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) +static zend_function_entry OneofDescriptor_methods[] = { + PHP_ME(OneofDescriptor, getName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(OneofDescriptor, getField, NULL, ZEND_ACC_PUBLIC) + PHP_ME(OneofDescriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC) ZEND_FE_END }; -DEFINE_CLASS(EnumValueDescriptor, enum_value_descriptor, - "Google\\Protobuf\\EnumValueDescriptor"); - -static void enum_value_descriptor_free_c(EnumValueDescriptor *self TSRMLS_DC) { -} - -static void enum_value_descriptor_init_c_instance(EnumValueDescriptor *self TSRMLS_DC) { - self->name = NULL; - self->number = 0; -} - -PHP_METHOD(EnumValueDescriptor, getName) { - EnumValueDescriptor *intern = UNBOX(EnumValueDescriptor, getThis()); - PHP_PROTO_RETVAL_STRINGL(intern->name, strlen(intern->name), 1); -} - -PHP_METHOD(EnumValueDescriptor, getNumber) { - EnumValueDescriptor *intern = UNBOX(EnumValueDescriptor, getThis()); - RETURN_LONG(intern->number); -} - // ----------------------------------------------------------------------------- // FieldDescriptor // ----------------------------------------------------------------------------- -static zend_function_entry field_descriptor_methods[] = { - PHP_ME(FieldDescriptor, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getLabel, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getType, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, isMap, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getEnumType, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getMessageType, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; +typedef struct { + zend_object std; + const upb_fielddef *fielddef; +} FieldDescriptor; -DEFINE_CLASS(FieldDescriptor, field_descriptor, - "Google\\Protobuf\\FieldDescriptor"); +zend_class_entry *FieldDescriptor_class_entry; +static zend_object_handlers FieldDescriptor_object_handlers; -static void field_descriptor_free_c(FieldDescriptor *self TSRMLS_DC) { -} +static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f) { + if (f == NULL) { + ZVAL_NULL(val); + return; + } -static void field_descriptor_init_c_instance(FieldDescriptor *self TSRMLS_DC) { - self->fielddef = NULL; + if (!ObjCache_Get(f, val)) { + FieldDescriptor* ret = emalloc(sizeof(FieldDescriptor)); + zend_object_std_init(&ret->std, FieldDescriptor_class_entry); + ret->std.handlers = &FieldDescriptor_object_handlers; + ret->fielddef = f; + ObjCache_Add(f, &ret->std); + + // Prevent this from ever being collected (within a request). + GC_ADDREF(&ret->std); + + ZVAL_OBJ(val, &ret->std); + } } upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) { @@ -383,499 +389,496 @@ upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) { return 0; } +/* + * FieldDescriptor::getName() + * + * Returns the name of this field. + */ PHP_METHOD(FieldDescriptor, getName) { - FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis()); - const char* name = upb_fielddef_name(intern->fielddef); - PHP_PROTO_RETVAL_STRINGL(name, strlen(name), 1); + FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); + RETURN_STRING(upb_fielddef_name(intern->fielddef)); } +/* + * FieldDescriptor::getNumber() + * + * Returns the number of this field. + */ PHP_METHOD(FieldDescriptor, getNumber) { - FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis()); + FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); RETURN_LONG(upb_fielddef_number(intern->fielddef)); } +/* + * FieldDescriptor::getLabel() + * + * Returns the label of this field as an integer. + */ PHP_METHOD(FieldDescriptor, getLabel) { - FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis()); + FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); RETURN_LONG(upb_fielddef_label(intern->fielddef)); } +/* + * FieldDescriptor::getType() + * + * Returns the type of this field as an integer. + */ PHP_METHOD(FieldDescriptor, getType) { - FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis()); + FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); RETURN_LONG(upb_fielddef_descriptortype(intern->fielddef)); } +/* + * FieldDescriptor::isMap() + * + * Returns true if this field is a map. + */ PHP_METHOD(FieldDescriptor, isMap) { - FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis()); + FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); RETURN_BOOL(upb_fielddef_ismap(intern->fielddef)); } +/* + * FieldDescriptor::getEnumType() + * + * Returns the EnumDescriptor for this field, which must be an enum. + */ PHP_METHOD(FieldDescriptor, getEnumType) { - FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis()); - if (upb_fielddef_type(intern->fielddef) != UPB_TYPE_ENUM) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, + FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); + const upb_enumdef *e = upb_fielddef_enumsubdef(intern->fielddef); + zval ret; + + if (!e) { + zend_throw_exception_ex(NULL, 0, "Cannot get enum type for non-enum field '%s'", upb_fielddef_name(intern->fielddef)); return; } - const upb_enumdef *enumdef = upb_fielddef_enumsubdef(intern->fielddef); - PHP_PROTO_HASHTABLE_VALUE desc_php = get_def_obj(enumdef); - - if (desc_php == NULL) { - EnumDescriptorInternal* intern = get_enumdef_enumdesc(enumdef); - -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(desc_php); - ZVAL_OBJ(desc_php, enum_descriptor_type->create_object( - enum_descriptor_type TSRMLS_CC)); - Z_DELREF_P(desc_php); -#else - desc_php = - enum_descriptor_type->create_object(enum_descriptor_type TSRMLS_CC); - GC_DELREF(desc_php); -#endif - EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(EnumDescriptor, desc_php); - desc->intern = intern; - add_def_obj(enumdef, desc_php); - add_ce_obj(intern->klass, desc_php); - } -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(desc_php, 1, 0); -#else - GC_ADDREF(desc_php); - RETURN_OBJ(desc_php); -#endif + EnumDescriptor_FromEnumDef(&ret, e); + RETURN_ZVAL(&ret, 1, 0); } +/* + * FieldDescriptor::getMessageType() + * + * Returns the Descriptor for this field, which must be a message. + */ PHP_METHOD(FieldDescriptor, getMessageType) { - FieldDescriptor *intern = UNBOX(FieldDescriptor, getThis()); - if (upb_fielddef_type(intern->fielddef) != UPB_TYPE_MESSAGE) { + FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); + Descriptor* desc = Descriptor_GetFromFieldDef(intern->fielddef); + zval ret; + + if (!desc) { zend_throw_exception_ex( - NULL, 0 TSRMLS_CC, "Cannot get message type for non-message field '%s'", + NULL, 0, "Cannot get message type for non-message field '%s'", upb_fielddef_name(intern->fielddef)); return; } - const upb_msgdef *msgdef = upb_fielddef_msgsubdef(intern->fielddef); - PHP_PROTO_HASHTABLE_VALUE desc_php = get_def_obj(msgdef); - - if (desc_php == NULL) { - DescriptorInternal* intern = get_msgdef_desc(msgdef); - -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(desc_php); - ZVAL_OBJ(desc_php, descriptor_type->create_object( - descriptor_type TSRMLS_CC)); - Z_DELREF_P(desc_php); -#else - desc_php = - descriptor_type->create_object(descriptor_type TSRMLS_CC); - GC_DELREF(desc_php); -#endif - Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php); - desc->intern = intern; - add_def_obj(msgdef, desc_php); - add_ce_obj(intern->klass, desc_php); - } -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(desc_php, 1, 0); -#else - GC_ADDREF(desc_php); - RETURN_OBJ(desc_php); -#endif + ZVAL_OBJ(&ret, &desc->std); + RETURN_ZVAL(&ret, 1, 0); } +static zend_function_entry FieldDescriptor_methods[] = { + PHP_ME(FieldDescriptor, getName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(FieldDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) + PHP_ME(FieldDescriptor, getLabel, NULL, ZEND_ACC_PUBLIC) + PHP_ME(FieldDescriptor, getType, NULL, ZEND_ACC_PUBLIC) + PHP_ME(FieldDescriptor, isMap, NULL, ZEND_ACC_PUBLIC) + PHP_ME(FieldDescriptor, getEnumType, NULL, ZEND_ACC_PUBLIC) + PHP_ME(FieldDescriptor, getMessageType, NULL, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + // ----------------------------------------------------------------------------- -// Oneof +// Descriptor // ----------------------------------------------------------------------------- -static zend_function_entry oneof_descriptor_methods[] = { - PHP_ME(Oneof, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Oneof, getField, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Oneof, getFieldCount, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; +zend_class_entry *Descriptor_class_entry; +static zend_object_handlers Descriptor_object_handlers; -DEFINE_CLASS(Oneof, oneof_descriptor, - "Google\\Protobuf\\OneofDescriptor"); +static void Descriptor_destructor(zend_object* obj) { + // We don't really need to do anything here, we don't allow this to be + // collected before the end of the request. +} + +// C Functions from def.h ////////////////////////////////////////////////////// -static void oneof_descriptor_free_c(Oneof *self TSRMLS_DC) { +// These are documented in the header file. + +void Descriptor_FromClassEntry(zval *val, zend_class_entry *ce) { + if (ce == NULL) { + ZVAL_NULL(val); + return; + } + + if (!ObjCache_Get(ce, val)) { + const upb_msgdef *msgdef = NameMap_GetMessage(ce); + if (!msgdef) { + ZVAL_NULL(val); + return; + } + Descriptor* ret = emalloc(sizeof(Descriptor)); + zend_object_std_init(&ret->std, Descriptor_class_entry); + ret->std.handlers = &Descriptor_object_handlers; + ret->class_entry = ce; + ret->msgdef = msgdef; + ObjCache_Add(ce, &ret->std); + + // Prevent this from ever being collected (within a request). + GC_ADDREF(&ret->std); + + ZVAL_OBJ(val, &ret->std); + } } -static void oneof_descriptor_init_c_instance(Oneof *self TSRMLS_DC) { - self->oneofdef = NULL; +Descriptor* Descriptor_GetFromClassEntry(zend_class_entry *ce) { + zval desc; + Descriptor_FromClassEntry(&desc, ce); + if (Z_TYPE_P(&desc) == IS_NULL) { + return NULL; + } else { + return (Descriptor*)Z_OBJ_P(&desc); + } +} + +Descriptor* Descriptor_GetFromMessageDef(const upb_msgdef *m) { + if (m) { + if (upb_msgdef_mapentry(m)) { + // A bit of a hack, since map entries don't have classes. + Descriptor* ret = emalloc(sizeof(Descriptor)); + zend_object_std_init(&ret->std, Descriptor_class_entry); + ret->std.handlers = &Descriptor_object_handlers; + ret->class_entry = NULL; + ret->msgdef = m; + + // Prevent this from ever being collected (within a request). + GC_ADDREF(&ret->std); + + return ret; + } + + char *classname = + GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m)); + zend_string *str = zend_string_init(classname, strlen(classname), 0); + zend_class_entry *ce = zend_lookup_class(str); // May autoload the class. + + zend_string_release (str); + + if (!ce) { + zend_error(E_ERROR, "Couldn't load generated class %s", classname); + } + + free(classname); + return Descriptor_GetFromClassEntry(ce); + } else { + return NULL; + } } -PHP_METHOD(Oneof, getName) { - Oneof *intern = UNBOX(Oneof, getThis()); - const char *name = upb_oneofdef_name(intern->oneofdef); - PHP_PROTO_RETVAL_STRINGL(name, strlen(name), 1); +Descriptor* Descriptor_GetFromFieldDef(const upb_fielddef *f) { + return Descriptor_GetFromMessageDef(upb_fielddef_msgsubdef(f)); } -PHP_METHOD(Oneof, getField) { - long index; +/* + * Descriptor::getPublicDescriptor() + * + * Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not + * have two separate EnumDescriptor classes. We use a single class for both + * the public and private descriptor. + */ +PHP_METHOD(Descriptor, getPublicDescriptor) { + RETURN_ZVAL(getThis(), 1, 0); +} + +/* + * Descriptor::getFullName() + * + * Returns the full name for this message type. + */ +PHP_METHOD(Descriptor, getFullName) { + Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); + RETURN_STRING(upb_msgdef_fullname(intern->msgdef)); +} + +/* + * Descriptor::getField() + * + * Returns a FieldDescriptor for the given index, which must be in the range + * [0, getFieldCount()-1]. + */ +PHP_METHOD(Descriptor, getField) { + Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); + int count = upb_msgdef_numfields(intern->msgdef); + zval ret; + zend_long index; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == FAILURE) { zend_error(E_USER_ERROR, "Expect integer for index.\n"); return; } - Oneof *intern = UNBOX(Oneof, getThis()); - int field_num = upb_oneofdef_numfields(intern->oneofdef); - if (index < 0 || index >= field_num) { + if (index < 0 || index >= count) { zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); return; } - upb_oneof_iter iter; + upb_msg_field_iter iter; int i; - for(upb_oneof_begin(&iter, intern->oneofdef), i = 0; - !upb_oneof_done(&iter) && i < index; - upb_oneof_next(&iter), i++); - const upb_fielddef *field = upb_oneof_iter_field(&iter); - - PHP_PROTO_HASHTABLE_VALUE field_hashtable_value = get_def_obj(field); - if (field_hashtable_value == NULL) { -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(field_hashtable_value); - ZVAL_OBJ(field_hashtable_value, field_descriptor_type->create_object( - field_descriptor_type TSRMLS_CC)); -#else - field_hashtable_value = - field_descriptor_type->create_object(field_descriptor_type TSRMLS_CC); -#endif - FieldDescriptor *field_php = - UNBOX_HASHTABLE_VALUE(FieldDescriptor, field_hashtable_value); - field_php->fielddef = field; - add_def_obj(field, field_hashtable_value); - } + for(upb_msg_field_begin(&iter, intern->msgdef), i = 0; + !upb_msg_field_done(&iter) && i < index; + upb_msg_field_next(&iter), i++); + const upb_fielddef *field = upb_msg_iter_field(&iter); -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(field_hashtable_value, 1, 0); -#else - GC_ADDREF(field_hashtable_value); - RETURN_OBJ(field_hashtable_value); -#endif + FieldDescriptor_FromFieldDef(&ret, field); + RETURN_ZVAL(&ret, 1, 0); } -PHP_METHOD(Oneof, getFieldCount) { - Oneof *intern = UNBOX(Oneof, getThis()); - RETURN_LONG(upb_oneofdef_numfields(intern->oneofdef)); +/* + * Descriptor::getFieldCount() + * + * Returns the number of fields in this message. + */ +PHP_METHOD(Descriptor, getFieldCount) { + Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); + RETURN_LONG(upb_msgdef_numfields(intern->msgdef)); } -// ----------------------------------------------------------------------------- -// DescriptorPool -// ----------------------------------------------------------------------------- - -static zend_function_entry descriptor_pool_methods[] = { - PHP_ME(DescriptorPool, getGeneratedPool, NULL, - ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(DescriptorPool, getDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(DescriptorPool, getEnumDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; +/* + * Descriptor::getOneofDecl() + * + * Returns a OneofDescriptor for the given index, which must be in the range + * [0, getOneofDeclCount()]. + */ +PHP_METHOD(Descriptor, getOneofDecl) { + Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); + zend_long index; + zval ret; -static zend_function_entry internal_descriptor_pool_methods[] = { - PHP_ME(InternalDescriptorPool, getGeneratedPool, NULL, - ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(InternalDescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == + FAILURE) { + zend_error(E_USER_ERROR, "Expect integer for index.\n"); + return; + } -DEFINE_CLASS(DescriptorPool, descriptor_pool, - "Google\\Protobuf\\DescriptorPool"); -DEFINE_CLASS(InternalDescriptorPool, internal_descriptor_pool, - "Google\\Protobuf\\Internal\\DescriptorPool"); - -// wrapper of generated pool -#if PHP_MAJOR_VERSION < 7 -zval* generated_pool_php; -zval* internal_generated_pool_php; -#else -zend_object *generated_pool_php; -zend_object *internal_generated_pool_php; -#endif -InternalDescriptorPoolImpl *generated_pool; -InternalDescriptorPoolImpl generated_pool_impl; // The actual generated pool - -void init_generated_pool_once(TSRMLS_D) { - if (generated_pool == NULL) { -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(generated_pool_php); - MAKE_STD_ZVAL(internal_generated_pool_php); - ZVAL_OBJ(internal_generated_pool_php, - internal_descriptor_pool_type->create_object( - internal_descriptor_pool_type TSRMLS_CC)); - ZVAL_OBJ(generated_pool_php, descriptor_pool_type->create_object( - descriptor_pool_type TSRMLS_CC)); -#else - internal_generated_pool_php = internal_descriptor_pool_type->create_object( - internal_descriptor_pool_type TSRMLS_CC); - generated_pool_php = - descriptor_pool_type->create_object(descriptor_pool_type TSRMLS_CC); -#endif - generated_pool = &generated_pool_impl; + int field_num = upb_msgdef_numoneofs(intern->msgdef); + if (index < 0 || index >= field_num) { + zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); + return; } -} -static void internal_descriptor_pool_init_c_instance( - InternalDescriptorPool *pool TSRMLS_DC) { - pool->intern = &generated_pool_impl; -} + upb_msg_oneof_iter iter; + int i; + for(upb_msg_oneof_begin(&iter, intern->msgdef), i = 0; + !upb_msg_oneof_done(&iter) && i < index; + upb_msg_oneof_next(&iter), i++); + const upb_oneofdef *oneof = upb_msg_iter_oneof(&iter); -static void internal_descriptor_pool_free_c( - InternalDescriptorPool *pool TSRMLS_DC) { + OneofDescriptor_FromOneofDef(&ret, oneof); + RETURN_ZVAL(&ret, 1, 0); } -void internal_descriptor_pool_impl_init( - InternalDescriptorPoolImpl *pool TSRMLS_DC) { - pool->symtab = upb_symtab_new(); - pool->fill_handler_cache = - upb_handlercache_new(add_handlers_for_message, NULL); - pool->pb_serialize_handler_cache = upb_pb_encoder_newcache(); - pool->json_serialize_handler_cache = upb_json_printer_newcache(false); - pool->json_serialize_handler_preserve_cache = upb_json_printer_newcache(true); - pool->fill_method_cache = upb_pbcodecache_new(pool->fill_handler_cache); - pool->json_fill_method_cache = upb_json_codecache_new(); +/* + * Descriptor::getOneofDeclCount() + * + * Returns the number of oneofs in this message. + */ +PHP_METHOD(Descriptor, getOneofDeclCount) { + Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); + RETURN_LONG(upb_msgdef_numoneofs(intern->msgdef)); } -void internal_descriptor_pool_impl_destroy( - InternalDescriptorPoolImpl *pool TSRMLS_DC) { - upb_symtab_free(pool->symtab); - upb_handlercache_free(pool->fill_handler_cache); - upb_handlercache_free(pool->pb_serialize_handler_cache); - upb_handlercache_free(pool->json_serialize_handler_cache); - upb_handlercache_free(pool->json_serialize_handler_preserve_cache); - upb_pbcodecache_free(pool->fill_method_cache); - upb_json_codecache_free(pool->json_fill_method_cache); +/* + * Descriptor::getClass() + * + * Returns the name of the PHP class for this message. + */ +PHP_METHOD(Descriptor, getClass) { + Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); + const char* classname = ZSTR_VAL(intern->class_entry->name); + RETURN_STRING(classname); } -static void descriptor_pool_init_c_instance(DescriptorPool *pool TSRMLS_DC) { - assert(generated_pool != NULL); - pool->intern = generated_pool; -} -static void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) { -} +static zend_function_entry Descriptor_methods[] = { + PHP_ME(Descriptor, getClass, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getFullName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getField, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getOneofDecl, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getOneofDeclCount, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Descriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; -PHP_METHOD(DescriptorPool, getGeneratedPool) { - init_generated_pool_once(TSRMLS_C); -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(generated_pool_php, 1, 0); -#else - GC_ADDREF(generated_pool_php); - RETURN_OBJ(generated_pool_php); -#endif +// ----------------------------------------------------------------------------- +// DescriptorPool +// ----------------------------------------------------------------------------- + +typedef struct DescriptorPool { + zend_object std; + upb_symtab *symtab; +} DescriptorPool; + +zend_class_entry *DescriptorPool_class_entry; +static zend_object_handlers DescriptorPool_object_handlers; + +static DescriptorPool *GetPool(const zval* this_ptr) { + return (DescriptorPool*)Z_OBJ_P(this_ptr); } -PHP_METHOD(InternalDescriptorPool, getGeneratedPool) { - init_generated_pool_once(TSRMLS_C); -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(internal_generated_pool_php, 1, 0); -#else - GC_ADDREF(internal_generated_pool_php); - RETURN_OBJ(internal_generated_pool_php); -#endif +/** + * Object handler to create an DescriptorPool. + */ +static zend_object* DescriptorPool_create(zend_class_entry *class_type) { + DescriptorPool *intern = emalloc(sizeof(DescriptorPool)); + zend_object_std_init(&intern->std, class_type); + intern->std.handlers = &DescriptorPool_object_handlers; + intern->symtab = upb_symtab_new(); + // Skip object_properties_init(), we don't allow derived classes. + return &intern->std; } -static bool is_reserved(const char *segment, int length) { - bool result; - char* lower = ALLOC_N(char, length + 1); - memset(lower, 0, length + 1); - memcpy(lower, segment, length); - int i = 0; - while(lower[i]) { - lower[i] = (char)tolower(lower[i]); - i++; +/** + * Object handler to free an DescriptorPool. + */ +static void DescriptorPool_destructor(zend_object* obj) { + DescriptorPool* intern = (DescriptorPool*)obj; + if (intern->symtab) { + upb_symtab_free(intern->symtab); } - lower[length] = 0; - result = is_reserved_name(lower); - FREE(lower); - return result; + intern->symtab = NULL; + zend_object_std_dtor(&intern->std); } -static void fill_prefix(const char *segment, int length, - const char *prefix_given, - const char *package_name, - stringsink *classname) { - if (prefix_given != NULL && strcmp(prefix_given, "") != 0) { - stringsink_string(classname, NULL, prefix_given, - strlen(prefix_given), NULL); - } else { - if (is_reserved(segment, length)) { - if (package_name != NULL && - strcmp("google.protobuf", package_name) == 0) { - stringsink_string(classname, NULL, "GPB", 3, NULL); - } else { - stringsink_string(classname, NULL, "PB", 2, NULL); - } - } +void DescriptorPool_CreateWithSymbolTable(zval *zv, upb_symtab *symtab) { + ZVAL_OBJ(zv, DescriptorPool_create(DescriptorPool_class_entry)); + + if (symtab) { + DescriptorPool *intern = GetPool(zv); + upb_symtab_free(intern->symtab); + intern->symtab = symtab; } } -static void fill_segment(const char *segment, int length, - stringsink *classname, bool use_camel) { - if (use_camel && (segment[0] < 'A' || segment[0] > 'Z')) { - char first = segment[0] + ('A' - 'a'); - stringsink_string(classname, NULL, &first, 1, NULL); - stringsink_string(classname, NULL, segment + 1, length - 1, NULL); - } else { - stringsink_string(classname, NULL, segment, length, NULL); - } +upb_symtab *DescriptorPool_Steal(zval *zv) { + DescriptorPool *intern = GetPool(zv); + upb_symtab *ret = intern->symtab; + intern->symtab = NULL; + return ret; } -static void fill_namespace(const char *package, const char *php_namespace, - stringsink *classname) { - if (php_namespace != NULL) { - if (strlen(php_namespace) != 0) { - stringsink_string(classname, NULL, php_namespace, strlen(php_namespace), - NULL); - stringsink_string(classname, NULL, "\\", 1, NULL); - } - } else if (package != NULL) { - int i = 0, j = 0; - size_t package_len = strlen(package); - while (i < package_len) { - j = i; - while (j < package_len && package[j] != '.') { - j++; - } - fill_prefix(package + i, j - i, "", package, classname); - fill_segment(package + i, j - i, classname, true); - stringsink_string(classname, NULL, "\\", 1, NULL); - i = j + 1; - } - } +upb_symtab *DescriptorPool_GetSymbolTable() { + DescriptorPool *intern = GetPool(get_generated_pool()); + return intern->symtab; } -static void fill_classname(const char *fullname, - const char *package, - const char *prefix, - stringsink *classname, - bool use_nested_submsg) { - int classname_start = 0; - if (package != NULL) { - size_t package_len = strlen(package); - classname_start = package_len == 0 ? 0 : package_len + 1; - } - size_t fullname_len = strlen(fullname); - bool is_first_segment = true; - - int i = classname_start, j; - while (i < fullname_len) { - j = i; - while (j < fullname_len && fullname[j] != '.') { - j++; - } - if (use_nested_submsg || (is_first_segment && j == fullname_len)) { - fill_prefix(fullname + i, j - i, prefix, package, classname); - } - is_first_segment = false; - fill_segment(fullname + i, j - i, classname, false); - if (j != fullname_len) { - if (use_nested_submsg) { - stringsink_string(classname, NULL, "\\", 1, NULL); - } else { - stringsink_string(classname, NULL, "_", 1, NULL); - } - } - i = j + 1; - } +/* + * DescriptorPool::getGeneratedPool() + * + * Returns the generated DescriptorPool. + */ +PHP_METHOD(DescriptorPool, getGeneratedPool) { + zval ret; + ZVAL_COPY(&ret, get_generated_pool()); + RETURN_ZVAL(&ret, 0, 1); } -static void fill_classname_for_desc(void *desc, bool is_enum) { - const upb_filedef *file; - const char *fullname; - bool use_nested_submsg; +/* + * DescriptorPool::getDescriptorByClassName() + * + * Returns a Descriptor object for the given PHP class name. + */ +PHP_METHOD(DescriptorPool, getDescriptorByClassName) { + char *classname = NULL; + zend_long classname_len; + zend_class_entry *ce; + zend_string *str; + zval ret; - if (is_enum) { - EnumDescriptorInternal* enumdesc = desc; - file = upb_enumdef_file(enumdesc->enumdef); - fullname = upb_enumdef_fullname(enumdesc->enumdef); - use_nested_submsg = enumdesc->use_nested_submsg; - } else { - DescriptorInternal* msgdesc = desc; - file = upb_msgdef_file(msgdesc->msgdef); - fullname = upb_msgdef_fullname(msgdesc->msgdef); - use_nested_submsg = msgdesc->use_nested_submsg; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname, + &classname_len) == FAILURE) { + return; } - // Prepend '.' to package name to make it absolute. In the 5 additional - // bytes allocated, one for '.', one for trailing 0, and 3 for 'GPB' if - // given message is google.protobuf.Empty. - const char *package = upb_filedef_package(file); - const char *php_namespace = upb_filedef_phpnamespace(file); - const char *prefix = upb_filedef_phpprefix(file); - stringsink namesink; - stringsink_init(&namesink); - - fill_namespace(package, php_namespace, &namesink); - fill_classname(fullname, package, prefix, &namesink, use_nested_submsg); - stringsink_string(&namesink, NULL, "\0", 1, NULL); - - if (is_enum) { - EnumDescriptorInternal* enumdesc = desc; - enumdesc->classname = strdup(namesink.ptr); - } else { - DescriptorInternal* msgdesc = desc; - msgdesc->classname = strdup(namesink.ptr); + str = zend_string_init(classname, strlen(classname), 0); + ce = zend_lookup_class(str); // May autoload the class. + zend_string_release (str); + + if (!ce) { + RETURN_NULL(); } - stringsink_uninit(&namesink); + Descriptor_FromClassEntry(&ret, ce); + RETURN_ZVAL(&ret, 1, 0); } -void register_class(void *desc, bool is_enum TSRMLS_DC) { - const char *classname; - const char *fullname; - zend_class_entry* ret; +/* + * DescriptorPool::getEnumDescriptorByClassName() + * + * Returns a EnumDescriptor object for the given PHP class name. + */ +PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) { + char *classname = NULL; + zend_long classname_len; + zend_class_entry *ce; + zend_string *str; + zval ret; - if (is_enum) { - EnumDescriptorInternal* enumdesc = desc; - if (enumdesc->klass) { - return; - } - classname = enumdesc->classname; - fullname = upb_enumdef_fullname(enumdesc->enumdef); - } else { - DescriptorInternal* msgdesc = desc; - if (msgdesc->klass) { - return; - } - if (!msgdesc->classname) { - return; - } - classname = msgdesc->classname; - fullname = upb_msgdef_fullname(msgdesc->msgdef); + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname, + &classname_len) == FAILURE) { + return; } - PHP_PROTO_CE_DECLARE pce; - if (php_proto_zend_lookup_class(classname, strlen(classname), &pce) == - FAILURE) { - zend_error( - E_ERROR, - "Generated message class %s hasn't been defined (%s)", - classname, fullname); + str = zend_string_init(classname, strlen(classname), 0); + ce = zend_lookup_class(str); // May autoload the class. + zend_string_release (str); + + if (!ce) { + RETURN_NULL(); + } + + EnumDescriptor_FromClassEntry(&ret, ce); + RETURN_ZVAL(&ret, 1, 0); +} + +/* + * DescriptorPool::getEnumDescriptorByProtoName() + * + * Returns a Descriptor object for the given protobuf message name. + */ +PHP_METHOD(DescriptorPool, getDescriptorByProtoName) { + DescriptorPool *intern = GetPool(getThis()); + char *protoname = NULL; + zend_long protoname_len; + const upb_msgdef *m; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &protoname, + &protoname_len) == FAILURE) { return; } - ret = PHP_PROTO_CE_UNREF(pce); - if (is_enum) { - EnumDescriptorInternal* enumdesc = desc; - add_ce_enumdesc(ret, desc); - enumdesc->klass = ret; + + if (*protoname == '.') protoname++; + + m = upb_symtab_lookupmsg(intern->symtab, protoname); + + if (m) { + zval ret; + ZVAL_OBJ(&ret, &Descriptor_GetFromMessageDef(m)->std); + RETURN_ZVAL(&ret, 1, 0); } else { - DescriptorInternal* msgdesc = desc; - add_ce_desc(ret, desc); - msgdesc->klass = ret; - // Map entries don't have existing php class. - if (!upb_msgdef_mapentry(msgdesc->msgdef)) { - if (msgdesc->layout == NULL) { - MessageLayout* layout = create_layout(msgdesc->msgdef); - msgdesc->layout = layout; - } - } + RETURN_NULL(); } } +/* + * depends_on_descriptor() + * + * Returns true if this FileDescriptorProto depends on descriptor.proto. + */ bool depends_on_descriptor(const google_protobuf_FileDescriptorProto* file) { const upb_strview *deps; upb_strview name = upb_strview_makez("google/protobuf/descriptor.proto"); @@ -891,247 +894,192 @@ bool depends_on_descriptor(const google_protobuf_FileDescriptorProto* file) { return false; } -static void internal_add_single_generated_file( - const upb_filedef* file, - InternalDescriptorPoolImpl* pool, - bool use_nested_submsg TSRMLS_DC) { +/* + * add_name_mappings() + * + * Adds the messages and enums in this file to the NameMap. + */ +static void add_name_mappings(const upb_filedef *file) { size_t i; - // For each enum/message, we need its PHP class, upb descriptor and its PHP - // wrapper. These information are needed later for encoding, decoding and type - // checking. However, sometimes we just have one of them. In order to find - // them quickly, here, we store the mapping for them. for (i = 0; i < upb_filedef_msgcount(file); i++) { - const upb_msgdef *msgdef = upb_filedef_msg(file, i); - CREATE_HASHTABLE_VALUE(desc, desc_php, Descriptor, descriptor_type); - desc->intern = SYS_MALLOC(DescriptorInternal); - desc->intern->msgdef = msgdef; - desc->intern->pool = pool; - desc->intern->layout = NULL; - desc->intern->klass = NULL; - desc->intern->use_nested_submsg = use_nested_submsg; - desc->intern->classname = NULL; - - add_def_obj(desc->intern->msgdef, desc_php); - add_msgdef_desc(desc->intern->msgdef, desc->intern); - - // Unlike other messages, MapEntry is shared by all map fields and doesn't - // have generated PHP class. - if (upb_msgdef_mapentry(msgdef)) { - continue; - } - - fill_classname_for_desc(desc->intern, false); - add_class_desc(desc->intern->classname, desc->intern); - add_proto_desc(upb_msgdef_fullname(desc->intern->msgdef), desc->intern); + NameMap_AddMessage(upb_filedef_msg(file, i)); } for (i = 0; i < upb_filedef_enumcount(file); i++) { - const upb_enumdef *enumdef = upb_filedef_enum(file, i); - CREATE_HASHTABLE_VALUE(desc, desc_php, EnumDescriptor, enum_descriptor_type); - desc->intern = SYS_MALLOC(EnumDescriptorInternal); - desc->intern->enumdef = enumdef; - desc->intern->klass = NULL; - desc->intern->use_nested_submsg = use_nested_submsg; - desc->intern->classname = NULL; - - add_def_obj(desc->intern->enumdef, desc_php); - add_enumdef_enumdesc(desc->intern->enumdef, desc->intern); - fill_classname_for_desc(desc->intern, true); - add_class_enumdesc(desc->intern->classname, desc->intern); + NameMap_AddEnum(upb_filedef_enum(file, i)); } } -const bool parse_and_add_descriptor(const char *data, - PHP_PROTO_SIZE data_len, - InternalDescriptorPoolImpl *pool, - upb_arena *arena, - bool use_nested_submsg TSRMLS_DC) { +/* + * add_name_mappings() + * + * Adds the given descriptor data to this DescriptorPool. + */ +static void add_descriptor(DescriptorPool *pool, const char *data, + int data_len, upb_arena *arena) { size_t i, n; google_protobuf_FileDescriptorSet *set; const google_protobuf_FileDescriptorProto* const* files; - const upb_filedef* file; - upb_status status; - set = google_protobuf_FileDescriptorSet_parse( - data, data_len, arena); + set = google_protobuf_FileDescriptorSet_parse(data, data_len, arena); if (!set) { zend_error(E_ERROR, "Failed to parse binary descriptor\n"); - return false; + return; } files = google_protobuf_FileDescriptorSet_file(set, &n); for (i = 0; i < n; i++) { - // Check whether file has already been added. - upb_strview name = google_protobuf_FileDescriptorProto_name(files[i]); - // TODO(teboring): Needs another look up method which takes data and length. - file = upb_symtab_lookupfile2(pool->symtab, name.data, name.size); - if (file != NULL) { + const google_protobuf_FileDescriptorProto* file = files[i]; + upb_strview name = google_protobuf_FileDescriptorProto_name(file); + upb_status status; + const upb_filedef *file_def; + upb_status_clear(&status); + + if (upb_symtab_lookupfile2(pool->symtab, name.data, name.size)) { + // Already added. continue; } // The PHP code generator currently special-cases descriptor.proto. It // doesn't add it as a dependency even if the proto file actually does // depend on it. - if (depends_on_descriptor(files[i]) && - upb_symtab_lookupfile( - pool->symtab, "google/protobuf/descriptor.proto") == - NULL) { - if (!parse_and_add_descriptor((char *)descriptor_proto, - descriptor_proto_len, pool, arena, - use_nested_submsg TSRMLS_CC)) { - return false; - } + if (depends_on_descriptor(file)) { + google_protobuf_FileDescriptorProto_getmsgdef(pool->symtab); } - upb_status_clear(&status); - file = upb_symtab_addfile(pool->symtab, files[i], &status); - check_upb_status(&status, "Unable to load descriptor"); - - internal_add_single_generated_file(file, pool, use_nested_submsg TSRMLS_CC); + file_def = upb_symtab_addfile(pool->symtab, file, &status); + CheckUpbStatus(&status, "Unable to load descriptor"); + add_name_mappings(file_def); } - - return true; -} - -void internal_add_generated_file(const char *data, PHP_PROTO_SIZE data_len, - InternalDescriptorPoolImpl *pool, - bool use_nested_submsg TSRMLS_DC) { - int i; - upb_arena *arena; - - arena = upb_arena_new(); - parse_and_add_descriptor(data, data_len, pool, arena, - use_nested_submsg TSRMLS_CC); - upb_arena_free(arena); - return; } -PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile) { +/* + * DescriptorPool::internalAddGeneratedFile() + * + * Adds the given descriptor data to this DescriptorPool. + */ +PHP_METHOD(DescriptorPool, internalAddGeneratedFile) { + DescriptorPool *intern = GetPool(getThis()); char *data = NULL; - PHP_PROTO_SIZE data_len; + zend_long data_len; zend_bool use_nested_submsg = false; + upb_arena *arena; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", - &data, &data_len, &use_nested_submsg) == - FAILURE) { - return; - } - - InternalDescriptorPool *pool = UNBOX(InternalDescriptorPool, getThis()); - internal_add_generated_file(data, data_len, pool->intern, - use_nested_submsg TSRMLS_CC); -} - -PHP_METHOD(DescriptorPool, getDescriptorByClassName) { - char *classname = NULL; - PHP_PROTO_SIZE classname_len; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname, - &classname_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len, + &use_nested_submsg) != SUCCESS) { return; } - PHP_PROTO_CE_DECLARE pce; - if (php_proto_zend_lookup_class(classname, classname_len, &pce) == - FAILURE) { - RETURN_NULL(); - } - - PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(PHP_PROTO_CE_UNREF(pce)); - if (desc_php == NULL) { - DescriptorInternal* intern = get_ce_desc(PHP_PROTO_CE_UNREF(pce)); - if (intern == NULL) { - RETURN_NULL(); - } - -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(desc_php); - ZVAL_OBJ(desc_php, descriptor_type->create_object( - descriptor_type TSRMLS_CC)); - Z_DELREF_P(desc_php); -#else - desc_php = - descriptor_type->create_object(descriptor_type TSRMLS_CC); - GC_DELREF(desc_php); -#endif - Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, desc_php); - desc->intern = intern; - add_def_obj(intern->msgdef, desc_php); - add_ce_obj(PHP_PROTO_CE_UNREF(pce), desc_php); - } - - zend_class_entry* instance_ce = HASHTABLE_VALUE_CE(desc_php); - - if (!instanceof_function(instance_ce, descriptor_type TSRMLS_CC)) { - RETURN_NULL(); - } - -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(desc_php, 1, 0); -#else - GC_ADDREF(desc_php); - RETURN_OBJ(desc_php); -#endif + arena = upb_arena_new(); + add_descriptor(intern, data, data_len, arena); + upb_arena_free(arena); } -PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) { - char *classname = NULL; - PHP_PROTO_SIZE classname_len; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname, - &classname_len) == FAILURE) { - return; - } - - PHP_PROTO_CE_DECLARE pce; - if (php_proto_zend_lookup_class(classname, classname_len, &pce) == - FAILURE) { - RETURN_NULL(); - } - - zend_class_entry* ce = PHP_PROTO_CE_UNREF(pce); - - PHP_PROTO_HASHTABLE_VALUE desc_php = get_ce_obj(ce); - if (desc_php == NULL) { -#if PHP_MAJOR_VERSION < 7 - EnumDescriptorInternal* intern = get_class_enumdesc(ce->name); -#else - EnumDescriptorInternal* intern = get_class_enumdesc(ZSTR_VAL(ce->name)); -#endif - register_class(intern, true TSRMLS_CC); +static zend_function_entry DescriptorPool_methods[] = { + PHP_ME(DescriptorPool, getGeneratedPool, NULL, + ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) + PHP_ME(DescriptorPool, getDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DescriptorPool, getDescriptorByProtoName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DescriptorPool, getEnumDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; - if (intern == NULL) { - RETURN_NULL(); - } +// ----------------------------------------------------------------------------- +// GPBType +// ----------------------------------------------------------------------------- -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(desc_php); - ZVAL_OBJ(desc_php, enum_descriptor_type->create_object( - enum_descriptor_type TSRMLS_CC)); - Z_DELREF_P(desc_php); -#else - desc_php = - enum_descriptor_type->create_object(enum_descriptor_type TSRMLS_CC); - GC_DELREF(desc_php); -#endif - EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(EnumDescriptor, desc_php); - desc->intern = intern; - add_def_obj(intern->enumdef, desc_php); - add_ce_obj(ce, desc_php); - } +zend_class_entry* gpb_type_type; - zend_class_entry* instance_ce = HASHTABLE_VALUE_CE(desc_php); +static zend_function_entry gpb_type_methods[] = { + ZEND_FE_END +}; - if (!instanceof_function(instance_ce, enum_descriptor_type TSRMLS_CC)) { - RETURN_NULL(); - } +// ----------------------------------------------------------------------------- +// Module Init +// ----------------------------------------------------------------------------- -#if PHP_MAJOR_VERSION < 7 - RETURN_ZVAL(desc_php, 1, 0); -#else - GC_ADDREF(desc_php); - RETURN_OBJ(desc_php); -#endif +void Def_ModuleInit() { + zend_class_entry tmp_ce; + zend_object_handlers *h; + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\OneofDescriptor", + OneofDescriptor_methods); + OneofDescriptor_class_entry = zend_register_internal_class(&tmp_ce); + OneofDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; + OneofDescriptor_class_entry->create_object = CreateHandler_ReturnNull; + h = &OneofDescriptor_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumValueDescriptor", + EnumValueDescriptor_methods); + EnumValueDescriptor_class_entry = zend_register_internal_class(&tmp_ce); + EnumValueDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; + EnumValueDescriptor_class_entry->create_object = CreateHandler_ReturnNull; + h = &EnumValueDescriptor_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumDescriptor", + EnumDescriptor_methods); + EnumDescriptor_class_entry = zend_register_internal_class(&tmp_ce); + EnumDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; + EnumDescriptor_class_entry->create_object = CreateHandler_ReturnNull; + h = &EnumDescriptor_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Descriptor", + Descriptor_methods); + + Descriptor_class_entry = zend_register_internal_class(&tmp_ce); + Descriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; + Descriptor_class_entry->create_object = CreateHandler_ReturnNull; + h = &Descriptor_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = Descriptor_destructor; + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\FieldDescriptor", + FieldDescriptor_methods); + FieldDescriptor_class_entry = zend_register_internal_class(&tmp_ce); + FieldDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; + FieldDescriptor_class_entry->create_object = CreateHandler_ReturnNull; + h = &FieldDescriptor_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\DescriptorPool", + DescriptorPool_methods); + DescriptorPool_class_entry = zend_register_internal_class(&tmp_ce); + DescriptorPool_class_entry->ce_flags |= ZEND_ACC_FINAL; + DescriptorPool_class_entry->create_object = DescriptorPool_create; + h = &DescriptorPool_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = DescriptorPool_destructor; + + // GPBType. +#define STR(str) (str), strlen(str) + zend_class_entry class_type; + INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBType", + gpb_type_methods); + gpb_type_type = zend_register_internal_class(&class_type); + zend_declare_class_constant_long(gpb_type_type, STR("DOUBLE"), 1); + zend_declare_class_constant_long(gpb_type_type, STR("FLOAT"), 2); + zend_declare_class_constant_long(gpb_type_type, STR("INT64"), 3); + zend_declare_class_constant_long(gpb_type_type, STR("UINT64"), 4); + zend_declare_class_constant_long(gpb_type_type, STR("INT32"), 5); + zend_declare_class_constant_long(gpb_type_type, STR("FIXED64"), 6); + zend_declare_class_constant_long(gpb_type_type, STR("FIXED32"), 7); + zend_declare_class_constant_long(gpb_type_type, STR("BOOL"), 8); + zend_declare_class_constant_long(gpb_type_type, STR("STRING"), 9); + zend_declare_class_constant_long(gpb_type_type, STR("GROUP"), 10); + zend_declare_class_constant_long(gpb_type_type, STR("MESSAGE"), 11); + zend_declare_class_constant_long(gpb_type_type, STR("BYTES"), 12); + zend_declare_class_constant_long(gpb_type_type, STR("UINT32"), 13); + zend_declare_class_constant_long(gpb_type_type, STR("ENUM"), 14); + zend_declare_class_constant_long(gpb_type_type, STR("SFIXED32"), 15); + zend_declare_class_constant_long(gpb_type_type, STR("SFIXED64"), 16); + zend_declare_class_constant_long(gpb_type_type, STR("SINT32"), 17); + zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18); +#undef STR } diff --git a/php/ext/google/protobuf2/def.h b/php/ext/google/protobuf/def.h similarity index 100% rename from php/ext/google/protobuf2/def.h rename to php/ext/google/protobuf/def.h diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c deleted file mode 100644 index 8eaa5d22eed8..000000000000 --- a/php/ext/google/protobuf/encode_decode.c +++ /dev/null @@ -1,2283 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. -// -#include -#include - -#include "protobuf.h" -#include "utf8.h" - -/* stringsink *****************************************************************/ - -static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { - stringsink *sink = _sink; - sink->len = 0; - return sink; -} - -size_t stringsink_string(void *_sink, const void *hd, const char *ptr, - size_t len, const upb_bufhandle *handle) { - stringsink *sink = _sink; - size_t new_size = sink->size; - - PHP_PROTO_UNUSED(hd); - PHP_PROTO_UNUSED(handle); - - while (sink->len + len > new_size) { - new_size *= 2; - } - - if (new_size != sink->size) { - sink->ptr = realloc(sink->ptr, new_size); - sink->size = new_size; - } - - memcpy(sink->ptr + sink->len, ptr, len); - sink->len += len; - - return len; -} - -void stringsink_init(stringsink *sink) { - upb_byteshandler_init(&sink->handler); - upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); - upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); - - upb_bytessink_reset(&sink->sink, &sink->handler, sink); - - sink->size = 32; - sink->ptr = malloc(sink->size); - PHP_PROTO_ASSERT(sink->ptr != NULL); - sink->len = 0; -} - -void stringsink_uninit(stringsink *sink) { free(sink->ptr); } - -void stringsink_uninit_opaque(void *sink) { stringsink_uninit(sink); } - -/* stackenv *****************************************************************/ - -// Stack-allocated context during an encode/decode operation. Contains the upb -// environment and its stack-based allocator, an initial buffer for allocations -// to avoid malloc() when possible, and a template for PHP exception messages -// if any error occurs. -#define STACK_ENV_STACKBYTES 4096 -typedef struct { - upb_arena *arena; - upb_status status; - const char *php_error_template; - char allocbuf[STACK_ENV_STACKBYTES]; -} stackenv; - - -static void stackenv_init(stackenv* se, const char* errmsg); -static void stackenv_uninit(stackenv* se); - -static void stackenv_init(stackenv* se, const char* errmsg) { - se->php_error_template = errmsg; - se->arena = upb_arena_new(); - upb_status_clear(&se->status); -} - -static void stackenv_uninit(stackenv* se) { - upb_arena_free(se->arena); - - if (!upb_ok(&se->status)) { - // TODO(teboring): have a way to verify that this is actually a parse error, - // instead of just throwing "parse error" unconditionally. - TSRMLS_FETCH(); - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, se->php_error_template, - upb_status_errmsg(&se->status)); - } -} - -// ----------------------------------------------------------------------------- -// Parsing. -// ----------------------------------------------------------------------------- - -bool is_wrapper_msg(const upb_msgdef* m) { - switch (upb_msgdef_wellknowntype(m)) { - case UPB_WELLKNOWN_DOUBLEVALUE: - case UPB_WELLKNOWN_FLOATVALUE: - case UPB_WELLKNOWN_INT64VALUE: - case UPB_WELLKNOWN_UINT64VALUE: - case UPB_WELLKNOWN_INT32VALUE: - case UPB_WELLKNOWN_UINT32VALUE: - case UPB_WELLKNOWN_STRINGVALUE: - case UPB_WELLKNOWN_BYTESVALUE: - case UPB_WELLKNOWN_BOOLVALUE: - return true; - default: - return false; - } -} - -typedef struct { - void* closure; - void* submsg; - bool is_msg; -} wrapperfields_parseframe_t; - -#define DEREF(msg, ofs, type) *(type*)(((uint8_t *)msg) + ofs) - -// Creates a handlerdata that simply contains the offset for this field. -static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) { - size_t* hd_ofs = (size_t*)malloc(sizeof(size_t)); - PHP_PROTO_ASSERT(hd_ofs != NULL); - *hd_ofs = ofs; - upb_handlers_addcleanup(h, hd_ofs, free); - return hd_ofs; -} - -static const void* newhandlerfielddata( - upb_handlers* h, const upb_fielddef* field) { - const void** hd_field = malloc(sizeof(void*)); - PHP_PROTO_ASSERT(hd_field != NULL); - *hd_field = field; - upb_handlers_addcleanup(h, hd_field, free); - return hd_field; -} - -typedef struct { - void* closure; - stringsink sink; -} stringfields_parseframe_t; - -typedef size_t (*encodeunknown_handlerfunc)(void* _sink, const void* hd, - const char* ptr, size_t len, - const upb_bufhandle* handle); - -typedef struct { - encodeunknown_handlerfunc handler; -} unknownfields_handlerdata_t; - -// Creates a handlerdata for unknown fields. -static const void *newunknownfieldshandlerdata(upb_handlers* h) { - unknownfields_handlerdata_t* hd = - (unknownfields_handlerdata_t*)malloc(sizeof(unknownfields_handlerdata_t)); - PHP_PROTO_ASSERT(hd != NULL); - hd->handler = stringsink_string; - upb_handlers_addcleanup(h, hd, free); - return hd; -} - -typedef struct { - const upb_fielddef *fd; - size_t ofs; - const upb_msgdef *md; -} submsg_handlerdata_t; - -// Creates a handlerdata that contains field and submessage type information. -static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs, - const upb_fielddef* f) { - submsg_handlerdata_t* hd = - (submsg_handlerdata_t*)malloc(sizeof(submsg_handlerdata_t)); - PHP_PROTO_ASSERT(hd != NULL); - hd->fd = f; - hd->ofs = ofs; - hd->md = upb_fielddef_msgsubdef(f); - upb_handlers_addcleanup(h, hd, free); - return hd; -} - -typedef struct { - size_t ofs; // union data slot - size_t case_ofs; // oneof_case field - int property_ofs; // properties table cache - uint32_t oneof_case_num; // oneof-case number to place in oneof_case field - const upb_msgdef *md; // msgdef, for oneof submessage handler - const upb_msgdef *parent_md; // msgdef, for parent submessage -} oneof_handlerdata_t; - -static const void *newoneofhandlerdata(upb_handlers *h, - uint32_t ofs, - uint32_t case_ofs, - int property_ofs, - const upb_msgdef *m, - const upb_fielddef *f) { - oneof_handlerdata_t* hd = - (oneof_handlerdata_t*)malloc(sizeof(oneof_handlerdata_t)); - PHP_PROTO_ASSERT(hd != NULL); - hd->ofs = ofs; - hd->case_ofs = case_ofs; - hd->property_ofs = property_ofs; - hd->parent_md = m; - // We reuse the field tag number as a oneof union discriminant tag. Note that - // we don't expose these numbers to the user, so the only requirement is that - // we have some unique ID for each union case/possibility. The field tag - // numbers are already present and are easy to use so there's no reason to - // create a separate ID space. In addition, using the field tag number here - // lets us easily look up the field in the oneof accessor. - hd->oneof_case_num = upb_fielddef_number(f); - if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) { - hd->md = upb_fielddef_msgsubdef(f); - } else { - hd->md = NULL; - } - upb_handlers_addcleanup(h, hd, free); - return hd; -} - -// A handler that starts a repeated field. Gets the Repeated*Field instance for -// this field (such an instance always exists even in an empty message). -static void *startseq_handler(void* closure, const void* hd) { - MessageHeader* msg = closure; - const upb_fielddef** field = (const upb_fielddef**) hd; - CACHED_VALUE* cache = find_zval_property(msg, *field); - TSRMLS_FETCH(); - repeated_field_ensure_created(*field, cache PHP_PROTO_TSRMLS_CC); - return CACHED_PTR_TO_ZVAL_PTR(cache); -} - -// Handlers that append primitive values to a repeated field. -#define DEFINE_APPEND_HANDLER(type, ctype) \ - static bool append##type##_handler(void* closure, const void* hd, \ - ctype val) { \ - zval* array = (zval*)closure; \ - TSRMLS_FETCH(); \ - RepeatedField* intern = UNBOX(RepeatedField, array); \ - repeated_field_push_native(intern, &val); \ - return true; \ - } - -DEFINE_APPEND_HANDLER(bool, bool) -DEFINE_APPEND_HANDLER(int32, int32_t) -DEFINE_APPEND_HANDLER(uint32, uint32_t) -DEFINE_APPEND_HANDLER(float, float) -DEFINE_APPEND_HANDLER(int64, int64_t) -DEFINE_APPEND_HANDLER(uint64, uint64_t) -DEFINE_APPEND_HANDLER(double, double) - -// Appends a string or 'bytes' string to a repeated field. -static void* appendstr_handler(void *closure, - const void *hd, - size_t size_hint) { - PHP_PROTO_UNUSED(hd); - - stringfields_parseframe_t* frame = - (stringfields_parseframe_t*)malloc(sizeof(stringfields_parseframe_t)); - PHP_PROTO_ASSERT(frame != NULL); - frame->closure = closure; - stringsink_init(&frame->sink); - - return frame; -} - -static bool appendstr_end_handler(void *closure, const void *hd) { - stringfields_parseframe_t* frame = closure; - - zval* array = (zval*)frame->closure; - TSRMLS_FETCH(); - RepeatedField* intern = UNBOX(RepeatedField, array); - -#if PHP_MAJOR_VERSION < 7 - zval* str; - MAKE_STD_ZVAL(str); - PHP_PROTO_ZVAL_STRINGL(str, frame->sink.ptr, frame->sink.len, 1); - repeated_field_push_native(intern, &str); -#else - zend_string* str = zend_string_init(frame->sink.ptr, frame->sink.len, 1); - repeated_field_push_native(intern, &str); -#endif - - stringsink_uninit(&frame->sink); - free(frame); - - return true; -} - -// Handlers that append primitive values to a repeated field. -#define DEFINE_SINGULAR_HANDLER(type, ctype) \ - static bool type##_handler(void* closure, const void* hd, \ - ctype val) { \ - MessageHeader* msg = (MessageHeader*)closure; \ - const size_t *ofs = hd; \ - DEREF(message_data(msg), *ofs, ctype) = val; \ - return true; \ - } - -DEFINE_SINGULAR_HANDLER(bool, bool) -DEFINE_SINGULAR_HANDLER(int32, int32_t) -DEFINE_SINGULAR_HANDLER(uint32, uint32_t) -DEFINE_SINGULAR_HANDLER(float, float) -DEFINE_SINGULAR_HANDLER(int64, int64_t) -DEFINE_SINGULAR_HANDLER(uint64, uint64_t) -DEFINE_SINGULAR_HANDLER(double, double) - -#undef DEFINE_SINGULAR_HANDLER - -#if PHP_MAJOR_VERSION < 7 -static void new_php_string(zval** value_ptr, const char* str, size_t len) { - SEPARATE_ZVAL_IF_NOT_REF(value_ptr); - if (Z_TYPE_PP(value_ptr) == IS_STRING && - !IS_INTERNED(Z_STRVAL_PP(value_ptr))) { - FREE(Z_STRVAL_PP(value_ptr)); - } - ZVAL_STRINGL(*value_ptr, str, len, 1); -} -#else -static void new_php_string(zval* value_ptr, const char* str, size_t len) { - if (Z_TYPE_P(value_ptr) == IS_STRING) { - zend_string_release(Z_STR_P(value_ptr)); - } - ZVAL_NEW_STR(value_ptr, zend_string_init(str, len, 0)); -} -#endif - -// Sets a non-repeated string/bytes field in a message. -static void* str_handler(void *closure, - const void *hd, - size_t size_hint) { - PHP_PROTO_UNUSED(hd); - - stringfields_parseframe_t* frame = - (stringfields_parseframe_t*)malloc(sizeof(stringfields_parseframe_t)); - PHP_PROTO_ASSERT(frame != NULL); - frame->closure = closure; - stringsink_init(&frame->sink); - - return frame; -} - -static bool str_end_handler(void *closure, const void *hd) { - stringfields_parseframe_t* frame = closure; - const upb_fielddef **field = (const upb_fielddef **) hd; - MessageHeader* msg = (MessageHeader*)frame->closure; - - CACHED_VALUE* cached = find_zval_property(msg, *field); - - new_php_string(cached, frame->sink.ptr, frame->sink.len); - - stringsink_uninit(&frame->sink); - free(frame); - - return true; -} - -static bool map_str_end_handler(void *closure, const void *hd) { - stringfields_parseframe_t* frame = closure; - const size_t *ofs = hd; - MessageHeader* msg = (MessageHeader*)frame->closure; - - new_php_string(DEREF(message_data(msg), *ofs, CACHED_VALUE*), - frame->sink.ptr, frame->sink.len); - - stringsink_uninit(&frame->sink); - free(frame); - - return true; -} - -static size_t stringdata_handler(void* closure, const void* hd, - const char* str, size_t len, - const upb_bufhandle* handle) { - stringfields_parseframe_t* frame = closure; - return stringsink_string(&frame->sink, hd, str, len, handle); -} - -// Appends a submessage to a repeated field. -static void *appendsubmsg_handler(void *closure, const void *hd) { - zval* array = (zval*)closure; - TSRMLS_FETCH(); - RepeatedField* intern = UNBOX(RepeatedField, array); - - const submsg_handlerdata_t *submsgdata = hd; - DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; - MessageHeader* submsg; - -#if PHP_MAJOR_VERSION < 7 - zval* val = NULL; - MAKE_STD_ZVAL(val); - ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC)); - repeated_field_push_native(intern, &val); - submsg = UNBOX(MessageHeader, val); -#else - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - repeated_field_push_native(intern, &obj); - submsg = (MessageHeader*)((char*)obj - XtOffsetOf(MessageHeader, std)); -#endif - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); - - return submsg; -} - -// Appends a wrapper submessage to a repeated field. -static void *appendwrappersubmsg_handler(void *closure, const void *hd) { - zval* array = (zval*)closure; - TSRMLS_FETCH(); - RepeatedField* intern = UNBOX(RepeatedField, array); - - const submsg_handlerdata_t *submsgdata = hd; - DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; - MessageHeader* submsg; - wrapperfields_parseframe_t* frame = - (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t)); - -#if PHP_MAJOR_VERSION < 7 - zval* val = NULL; - MAKE_STD_ZVAL(val); - ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC)); - repeated_field_push_native(intern, &val); - submsg = UNBOX(MessageHeader, val); -#else - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - repeated_field_push_native(intern, &obj); - submsg = (MessageHeader*)((char*)obj - XtOffsetOf(MessageHeader, std)); -#endif - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); - - frame->closure = closure; - frame->submsg = submsg; - frame->is_msg = true; - - return frame; -} - -// Sets a non-repeated submessage field in a message. -static void *submsg_handler(void *closure, const void *hd) { - MessageHeader* msg = closure; - const submsg_handlerdata_t* submsgdata = hd; - TSRMLS_FETCH(); - DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; - zval* submsg_php; - MessageHeader* submsg; - - CACHED_VALUE* cached = find_zval_property(msg, submsgdata->fd); - - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) { -#if PHP_MAJOR_VERSION < 7 - zval val; - ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC)); - MessageHeader* intern = UNBOX(MessageHeader, &val); - custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); - REPLACE_ZVAL_VALUE(cached, &val, 1); - zval_dtor(&val); -#else - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - ZVAL_OBJ(cached, obj); - MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj); - custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); -#endif - } - - submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached); - - submsg = UNBOX(MessageHeader, submsg_php); - return submsg; -} - -static void *map_submsg_handler(void *closure, const void *hd) { - MessageHeader* msg = closure; - const submsg_handlerdata_t* submsgdata = hd; - TSRMLS_FETCH(); - DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; - zval* submsg_php; - MessageHeader* submsg; - - CACHED_VALUE* cached = - DEREF(message_data(msg), submsgdata->ofs, CACHED_VALUE*); - - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) { -#if PHP_MAJOR_VERSION < 7 - zval val; - ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC)); - MessageHeader* intern = UNBOX(MessageHeader, &val); - custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); - REPLACE_ZVAL_VALUE(cached, &val, 1); - zval_dtor(&val); -#else - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - ZVAL_OBJ(cached, obj); - MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj); - custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); -#endif - } - - submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached); - - submsg = UNBOX(MessageHeader, submsg_php); - return submsg; -} - -static void *map_wrapper_submsg_handler(void *closure, const void *hd) { - MessageHeader* msg = closure; - const submsg_handlerdata_t* submsgdata = hd; - TSRMLS_FETCH(); - DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; - zval* submsg_php; - MessageHeader* submsg; - wrapperfields_parseframe_t* frame = - (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t)); - - CACHED_VALUE* cached = - DEREF(message_data(msg), submsgdata->ofs, CACHED_VALUE*); - - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) { -#if PHP_MAJOR_VERSION < 7 - zval val; - ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC)); - MessageHeader* intern = UNBOX(MessageHeader, &val); - custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); - REPLACE_ZVAL_VALUE(cached, &val, 1); - zval_dtor(&val); -#else - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - ZVAL_OBJ(cached, obj); - MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj); - custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC); -#endif - } - - submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached); - - submsg = UNBOX(MessageHeader, submsg_php); - frame->closure = closure; - frame->submsg = submsg; - frame->is_msg = true; - return frame; -} - -// Handler data for startmap/endmap handlers. -typedef struct { - const upb_fielddef* fd; - const upb_msgdef* value_md; - upb_fieldtype_t key_field_type; - upb_fieldtype_t value_field_type; -} map_handlerdata_t; - -// Temporary frame for map parsing: at the beginning of a map entry message, a -// submsg handler allocates a frame to hold (i) a reference to the Map object -// into which this message will be inserted and (ii) storage slots to -// temporarily hold the key and value for this map entry until the end of the -// submessage. When the submessage ends, another handler is called to insert the -// value into the map. -typedef struct { - char key_storage[NATIVE_SLOT_MAX_SIZE]; - char value_storage[NATIVE_SLOT_MAX_SIZE]; -} map_parse_frame_data_t; - -PHP_PROTO_WRAP_OBJECT_START(map_parse_frame_t) - map_parse_frame_data_t* data; // Place needs to be consistent with - // MessageHeader. - zval* map; - // In php7, we cannot allocate zval dynamically. So we need to add zval here - // to help decoding. - zval key_zval; - zval value_zval; -PHP_PROTO_WRAP_OBJECT_END -typedef struct map_parse_frame_t map_parse_frame_t; - -static void map_slot_init( - void* memory, upb_fieldtype_t type, zval* cache, - const upb_msgdef* value_msg PHP_PROTO_TSRMLS_DC) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { -#if PHP_MAJOR_VERSION < 7 - // Store zval** in memory in order to be consistent with the layout of - // singular fields. - zval** holder = ALLOC(zval*); - *(zval***)memory = holder; - zval* tmp; - MAKE_STD_ZVAL(tmp); - PHP_PROTO_ZVAL_STRINGL(tmp, "", 0, 1); - *holder = tmp; -#else - *(zval**)memory = cache; - PHP_PROTO_ZVAL_STRINGL(*(zval**)memory, "", 0, 1); -#endif - break; - } - case UPB_TYPE_MESSAGE: { - DescriptorInternal* subdesc = get_msgdef_desc(value_msg); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; - MessageHeader* submsg; -#if PHP_MAJOR_VERSION < 7 - zval** holder = ALLOC(zval*); - zval* tmp; - MAKE_STD_ZVAL(tmp); - ZVAL_OBJ(tmp, subklass->create_object(subklass TSRMLS_CC)); - submsg = UNBOX(MessageHeader, tmp); - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); - *holder = tmp; - *(zval***)memory = holder; -#else - *(zval**)memory = cache; - ZVAL_OBJ(*(zval**)memory, subklass->create_object(subklass TSRMLS_CC)); - submsg = UNBOX(MessageHeader, cache); - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); -#endif - break; - } - default: - native_slot_init(type, memory, NULL); - } -} - -static void map_slot_uninit(void* memory, upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_MESSAGE: - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { -#if PHP_MAJOR_VERSION < 7 - zval** holder = *(zval***)memory; - zval_ptr_dtor(holder); - FREE(holder); -#else - php_proto_zval_ptr_dtor(*(zval**)memory); -#endif - break; - } - default: - break; - } -} - -static void map_slot_key(upb_fieldtype_t type, const void* from, - const char** keyval, - size_t* length) { - if (type == UPB_TYPE_STRING) { -#if PHP_MAJOR_VERSION < 7 - zval* key_php = **(zval***)from; -#else - zval* key_php = *(zval**)from; -#endif - *keyval = Z_STRVAL_P(key_php); - *length = Z_STRLEN_P(key_php); - } else { - *keyval = from; - *length = native_slot_size(type); - } -} - -static void map_slot_value(upb_fieldtype_t type, const void* from, - upb_value* v) { - size_t len; - void* to = upb_value_memory(v); -#ifndef NDEBUG - v->ctype = UPB_CTYPE_UINT64; -#endif - - memset(to, 0, native_slot_size(type)); - - switch (type) { -#if PHP_MAJOR_VERSION < 7 - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: { - *(zval**)to = **(zval***)from; - Z_ADDREF_PP((zval**)to); - break; - } -#else - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - *(zend_string**)to = Z_STR_P(*(zval**)from); - zend_string_addref(*(zend_string**)to); - break; - case UPB_TYPE_MESSAGE: - if (!ZVAL_IS_NULL(*(zval**)from)) { - *(zend_object**)to = Z_OBJ_P(*(zval**)from); - GC_ADDREF(*(zend_object**)to); - } - break; -#endif - default: - len = native_slot_size(type); - memcpy(to, from, len); - } -} - -// Handler to begin a map entry: allocates a temporary frame. This is the -// 'startsubmsg' handler on the msgdef that contains the map field. -static void *startmapentry_handler(void *closure, const void *hd) { - MessageHeader* msg = closure; - const map_handlerdata_t* mapdata = hd; - CACHED_VALUE* cache = find_zval_property(msg, mapdata->fd); - TSRMLS_FETCH(); - map_field_ensure_created(mapdata->fd, cache PHP_PROTO_TSRMLS_CC); - zval* map = CACHED_PTR_TO_ZVAL_PTR(cache); - - map_parse_frame_t* frame = ALLOC(map_parse_frame_t); - frame->data = ALLOC(map_parse_frame_data_t); - frame->map = map; - - map_slot_init(&frame->data->key_storage, mapdata->key_field_type, - &frame->key_zval, NULL PHP_PROTO_TSRMLS_CC); - map_slot_init(&frame->data->value_storage, mapdata->value_field_type, - &frame->value_zval, mapdata->value_md PHP_PROTO_TSRMLS_CC); - - return frame; -} - -// Handler to end a map entry: inserts the value defined during the message into -// the map. This is the 'endmsg' handler on the map entry msgdef. -static bool endmap_handler(void* closure, const void* hd, upb_status* s) { - map_parse_frame_t* frame = closure; - const map_handlerdata_t* mapdata = hd; - - TSRMLS_FETCH(); - Map *map = UNBOX(Map, frame->map); - - const char* keyval = NULL; - upb_value v; - size_t length; - - map_slot_key(map->key_type, &frame->data->key_storage, &keyval, &length); - map_slot_value(map->value_type, &frame->data->value_storage, &v); - - map_index_set(map, keyval, length, v); - - map_slot_uninit(&frame->data->key_storage, mapdata->key_field_type); - map_slot_uninit(&frame->data->value_storage, mapdata->value_field_type); - FREE(frame->data); - FREE(frame); - - return true; -} - -// Allocates a new map_handlerdata_t given the map entry message definition. If -// the offset of the field within the parent message is also given, that is -// added to the handler data as well. Note that this is called *twice* per map -// field: once in the parent message handler setup when setting the startsubmsg -// handler and once in the map entry message handler setup when setting the -// key/value and endmsg handlers. The reason is that there is no easy way to -// pass the handlerdata down to the sub-message handler setup. -static map_handlerdata_t* new_map_handlerdata( - const upb_fielddef* field, - const upb_msgdef* mapentry_def) { - const upb_fielddef* key_field; - const upb_fielddef* value_field; - // TODO(teboring): Use emalloc and efree. - map_handlerdata_t* hd = - (map_handlerdata_t*)malloc(sizeof(map_handlerdata_t)); - PHP_PROTO_ASSERT(hd != NULL); - hd->fd = field; - key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD); - PHP_PROTO_ASSERT(key_field != NULL); - hd->key_field_type = upb_fielddef_type(key_field); - value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD); - PHP_PROTO_ASSERT(value_field != NULL); - hd->value_field_type = upb_fielddef_type(value_field); - if (upb_fielddef_type(value_field) == UPB_TYPE_MESSAGE) { - hd->value_md = upb_fielddef_msgsubdef(value_field); - } else { - hd->value_md = NULL; - } - - return hd; -} - -// Handlers that set primitive values in oneofs. -#define DEFINE_ONEOF_HANDLER(type, ctype) \ - static bool oneof##type##_handler(void* closure, const void* hd, \ - ctype val) { \ - const oneof_handlerdata_t* oneofdata = hd; \ - DEREF(message_data(closure), oneofdata->case_ofs, uint32_t) = \ - oneofdata->oneof_case_num; \ - DEREF(message_data(closure), oneofdata->ofs, ctype) = val; \ - return true; \ - } - -DEFINE_ONEOF_HANDLER(bool, bool) -DEFINE_ONEOF_HANDLER(int32, int32_t) -DEFINE_ONEOF_HANDLER(uint32, uint32_t) -DEFINE_ONEOF_HANDLER(float, float) -DEFINE_ONEOF_HANDLER(int64, int64_t) -DEFINE_ONEOF_HANDLER(uint64, uint64_t) -DEFINE_ONEOF_HANDLER(double, double) - -#undef DEFINE_ONEOF_HANDLER - -static void oneof_cleanup(MessageHeader* msg, - const oneof_handlerdata_t* oneofdata) { - uint32_t old_case_num = - DEREF(message_data(msg), oneofdata->case_ofs, uint32_t); - if (old_case_num == 0) { - return; - } - - const upb_fielddef* old_field = - upb_msgdef_itof(oneofdata->parent_md, old_case_num); - bool need_clean = false; - - switch (upb_fielddef_type(old_field)) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - need_clean = true; - break; - case UPB_TYPE_MESSAGE: - if (oneofdata->oneof_case_num != old_case_num) { - need_clean = true; - } - break; - default: - break; - } - - if (need_clean) { -#if PHP_MAJOR_VERSION < 7 - SEPARATE_ZVAL_IF_NOT_REF( - DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)); - php_proto_zval_ptr_dtor( - *DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)); - MAKE_STD_ZVAL(*DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)); - ZVAL_NULL(*DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)); -#endif - } -} - -// Handlers for string/bytes in a oneof. -static bool oneofstr_end_handler(void *closure, const void *hd) { - stringfields_parseframe_t* frame = closure; - MessageHeader* msg = (MessageHeader*)frame->closure; - const oneof_handlerdata_t *oneofdata = hd; - - oneof_cleanup(msg, oneofdata); - - DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) = - oneofdata->oneof_case_num; - DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) = - OBJ_PROP(&msg->std, oneofdata->property_ofs); - - new_php_string(DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*), - frame->sink.ptr, frame->sink.len); - - stringsink_uninit(&frame->sink); - free(frame); - - return true; -} - -static void *oneofstr_handler(void *closure, - const void *hd, - size_t size_hint) { - PHP_PROTO_UNUSED(hd); - - stringfields_parseframe_t* frame = - (stringfields_parseframe_t*)malloc(sizeof(stringfields_parseframe_t)); - PHP_PROTO_ASSERT(frame != NULL); - frame->closure = closure; - stringsink_init(&frame->sink); - - return frame; -} - -// Handler for a submessage field in a oneof. -static void* oneofsubmsg_handler(void* closure, const void* hd) { - MessageHeader* msg = closure; - const oneof_handlerdata_t *oneofdata = hd; - uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t); - TSRMLS_FETCH(); - DescriptorInternal* subdesc = get_msgdef_desc(oneofdata->md); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; - zval* submsg_php; - MessageHeader* submsg; - - if (oldcase != oneofdata->oneof_case_num) { - oneof_cleanup(msg, oneofdata); - - // Create new message. - DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) = - OBJ_PROP(&msg->std, oneofdata->property_ofs); -#if PHP_MAJOR_VERSION < 7 - zval val; - ZVAL_OBJ(&val, subklass->create_object(subklass TSRMLS_CC)); - REPLACE_ZVAL_VALUE(DEREF(message_data(msg), oneofdata->ofs, zval**), - &val, 1); - zval_dtor(&val); -#else - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - ZVAL_OBJ(DEREF(message_data(msg), oneofdata->ofs, zval*), obj); -#endif - } - - DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) = - oneofdata->oneof_case_num; - - submsg_php = CACHED_PTR_TO_ZVAL_PTR( - DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)); - submsg = UNBOX(MessageHeader, submsg_php); - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); - return submsg; -} - -// Sets a non-repeated wrapper submessage field in a message. -static void* wrapper_submsg_handler(void* closure, const void* hd) { - MessageHeader* msg = closure; - const submsg_handlerdata_t* submsgdata = hd; - TSRMLS_FETCH(); - DescriptorInternal* subdesc = get_msgdef_desc(submsgdata->md); - register_class(subdesc, false TSRMLS_CC); - zval* submsg_php; - MessageHeader* submsg; - wrapperfields_parseframe_t* frame = - (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t)); - - CACHED_VALUE* cached = find_zval_property(msg, submsgdata->fd); - submsg_php = CACHED_PTR_TO_ZVAL_PTR(cached); - frame->closure = closure; - - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_OBJECT) { - submsg = UNBOX(MessageHeader, submsg_php); - frame->submsg = submsg; - frame->is_msg = true; - } else { - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) { - // Needs to initiate the wrapper message - const upb_msgdef* msgdef = subdesc->msgdef; - const upb_fielddef* f = upb_msgdef_itof(msgdef, 1); - native_slot_get_default(upb_fielddef_type(f), cached TSRMLS_CC); - } - // In this case, wrapper message hasn't been created and value will be - // stored in cache directly. - frame->submsg = cached; - frame->is_msg = false; - } - - return frame; -} - -// Handler for a wrapper submessage field in a oneof. -static void* wrapper_oneofsubmsg_handler(void* closure, const void* hd) { - MessageHeader* msg = closure; - const oneof_handlerdata_t *oneofdata = hd; - uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t); - TSRMLS_FETCH(); - DescriptorInternal* subdesc = get_msgdef_desc(oneofdata->md); - register_class(subdesc, false TSRMLS_CC); - wrapperfields_parseframe_t* frame = - (wrapperfields_parseframe_t*)malloc(sizeof(wrapperfields_parseframe_t)); - CACHED_VALUE* cached = OBJ_PROP(&msg->std, oneofdata->property_ofs); - MessageHeader* submsg; - - if (oldcase != oneofdata->oneof_case_num) { - oneof_cleanup(msg, oneofdata); - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_NULL) { - // Needs to initiate the wrapper message - const upb_msgdef* msgdef = subdesc->msgdef; - const upb_fielddef* f = upb_msgdef_itof(msgdef, 1); - native_slot_get_default(upb_fielddef_type(f), cached TSRMLS_CC); - } - frame->submsg = cached; - frame->is_msg = false; - } else if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(cached)) == IS_OBJECT) { - submsg = UNBOX(MessageHeader, CACHED_PTR_TO_ZVAL_PTR(cached)); - frame->submsg = submsg; - frame->is_msg = true; - } else { - // In this case, wrapper message hasn't been created and value will be - // stored in cache directly. - frame->submsg = cached; - frame->is_msg = false; - } - - DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) = - oneofdata->oneof_case_num; - - return frame; -} - -static bool wrapper_submsg_end_handler(void *closure, const void *hd) { - wrapperfields_parseframe_t* frame = closure; - free(frame); - return true; -} - -// Set up handlers for a repeated field. -static void add_handlers_for_repeated_field(upb_handlers *h, - const upb_fielddef *f, - size_t offset) { - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - attr.handler_data = newhandlerfielddata(h, f); - upb_handlers_setstartseq(h, f, startseq_handler, &attr); - - switch (upb_fielddef_type(f)) { - -#define SET_HANDLER(utype, ltype) \ - case utype: \ - upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \ - break; - - SET_HANDLER(UPB_TYPE_BOOL, bool); - SET_HANDLER(UPB_TYPE_INT32, int32); - SET_HANDLER(UPB_TYPE_UINT32, uint32); - SET_HANDLER(UPB_TYPE_ENUM, int32); - SET_HANDLER(UPB_TYPE_FLOAT, float); - SET_HANDLER(UPB_TYPE_INT64, int64); - SET_HANDLER(UPB_TYPE_UINT64, uint64); - SET_HANDLER(UPB_TYPE_DOUBLE, double); - -#undef SET_HANDLER - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - upb_handlers_setstartstr(h, f, appendstr_handler, NULL); - upb_handlers_setstring(h, f, stringdata_handler, NULL); - upb_handlers_setendstr(h, f, appendstr_end_handler, &attr); - break; - } - case UPB_TYPE_MESSAGE: { - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - attr.handler_data = newsubmsghandlerdata(h, 0, f); - if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) { - upb_handlers_setstartsubmsg(h, f, appendwrappersubmsg_handler, &attr); - upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr); - } else { - upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr); - } - break; - } - } -} - -// Set up handlers for a singular field. -static void add_handlers_for_singular_field(upb_handlers *h, - const upb_fielddef *f, - size_t offset, bool is_map) { - switch (upb_fielddef_type(f)) { -#define SET_HANDLER(utype, ltype) \ - case utype: { \ - upb_handlerattr attr = UPB_HANDLERATTR_INIT; \ - attr.handler_data = newhandlerdata(h, offset); \ - upb_handlers_set##ltype(h, f, ltype##_handler, &attr); \ - break; \ - } - - SET_HANDLER(UPB_TYPE_BOOL, bool); - SET_HANDLER(UPB_TYPE_INT32, int32); - SET_HANDLER(UPB_TYPE_UINT32, uint32); - SET_HANDLER(UPB_TYPE_ENUM, int32); - SET_HANDLER(UPB_TYPE_FLOAT, float); - SET_HANDLER(UPB_TYPE_INT64, int64); - SET_HANDLER(UPB_TYPE_UINT64, uint64); - SET_HANDLER(UPB_TYPE_DOUBLE, double); - -#undef SET_HANDLER - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - if (is_map) { - attr.handler_data = newhandlerdata(h, offset); - } else { - attr.handler_data = newhandlerfielddata(h, f); - } - upb_handlers_setstartstr(h, f, str_handler, &attr); - upb_handlers_setstring(h, f, stringdata_handler, &attr); - if (is_map) { - upb_handlers_setendstr(h, f, map_str_end_handler, &attr); - } else { - upb_handlers_setendstr(h, f, str_end_handler, &attr); - } - break; - } - case UPB_TYPE_MESSAGE: { - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - if (is_map) { - attr.handler_data = newsubmsghandlerdata(h, offset, f); - if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) { - upb_handlers_setstartsubmsg(h, f, map_wrapper_submsg_handler, &attr); - upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr); - } else { - upb_handlers_setstartsubmsg(h, f, map_submsg_handler, &attr); - } - } else if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) { - attr.handler_data = newsubmsghandlerdata(h, 0, f); - upb_handlers_setstartsubmsg(h, f, wrapper_submsg_handler, &attr); - upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr); - } else { - attr.handler_data = newsubmsghandlerdata(h, 0, f); - upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr); - } - break; - } - } -} - -// Adds handlers to a map field. -static void add_handlers_for_mapfield(upb_handlers* h, - const upb_fielddef* fielddef, - size_t offset) { - const upb_msgdef* map_msgdef = upb_fielddef_msgsubdef(fielddef); - map_handlerdata_t* hd = new_map_handlerdata(fielddef, map_msgdef); - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - - upb_handlers_addcleanup(h, hd, free); - attr.handler_data = hd; - upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr); -} - -// Adds handlers to a map-entry msgdef. -static void add_handlers_for_mapentry( - const upb_msgdef* msgdef, upb_handlers* h) { - const upb_fielddef* key_field = map_entry_key(msgdef); - const upb_fielddef* value_field = map_entry_value(msgdef); - map_handlerdata_t* hd = new_map_handlerdata(0, msgdef); - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - - upb_handlers_addcleanup(h, hd, free); - attr.handler_data = hd; - upb_handlers_setendmsg(h, endmap_handler, &attr); - - add_handlers_for_singular_field(h, key_field, - offsetof(map_parse_frame_data_t, - key_storage), true); - add_handlers_for_singular_field(h, value_field, - offsetof(map_parse_frame_data_t, - value_storage), true); -} - -// Set up handlers for a oneof field. -static void add_handlers_for_oneof_field(upb_handlers *h, - const upb_msgdef *m, - const upb_fielddef *f, - size_t offset, - size_t oneof_case_offset, - int property_cache_offset) { - - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - attr.handler_data = newoneofhandlerdata(h, offset, oneof_case_offset, - property_cache_offset, m, f); - - switch (upb_fielddef_type(f)) { - -#define SET_HANDLER(utype, ltype) \ - case utype: \ - upb_handlers_set##ltype(h, f, oneof##ltype##_handler, &attr); \ - break; - - SET_HANDLER(UPB_TYPE_BOOL, bool); - SET_HANDLER(UPB_TYPE_INT32, int32); - SET_HANDLER(UPB_TYPE_UINT32, uint32); - SET_HANDLER(UPB_TYPE_ENUM, int32); - SET_HANDLER(UPB_TYPE_FLOAT, float); - SET_HANDLER(UPB_TYPE_INT64, int64); - SET_HANDLER(UPB_TYPE_UINT64, uint64); - SET_HANDLER(UPB_TYPE_DOUBLE, double); - -#undef SET_HANDLER - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - upb_handlers_setstartstr(h, f, oneofstr_handler, &attr); - upb_handlers_setstring(h, f, stringdata_handler, NULL); - upb_handlers_setendstr(h, f, oneofstr_end_handler, &attr); - break; - } - case UPB_TYPE_MESSAGE: { - if (is_wrapper_msg(upb_fielddef_msgsubdef(f))) { - upb_handlers_setstartsubmsg(h, f, wrapper_oneofsubmsg_handler, &attr); - upb_handlers_setendsubmsg(h, f, wrapper_submsg_end_handler, &attr); - } else { - upb_handlers_setstartsubmsg(h, f, oneofsubmsg_handler, &attr); - } - break; - } - } -} - -#define DEFINE_WRAPPER_HANDLER(utype, type, ctype) \ - static bool type##wrapper_handler( \ - void* closure, const void* hd, ctype val) { \ - wrapperfields_parseframe_t* frame = closure; \ - if (frame->is_msg) { \ - MessageHeader* msg = frame->submsg; \ - const size_t *ofs = hd; \ - DEREF(message_data(msg), *ofs, ctype) = val; \ - } else { \ - TSRMLS_FETCH(); \ - native_slot_get(utype, &val, frame->submsg TSRMLS_CC); \ - } \ - return true; \ - } - -DEFINE_WRAPPER_HANDLER(UPB_TYPE_BOOL, bool, bool) -DEFINE_WRAPPER_HANDLER(UPB_TYPE_INT32, int32, int32_t) -DEFINE_WRAPPER_HANDLER(UPB_TYPE_UINT32, uint32, uint32_t) -DEFINE_WRAPPER_HANDLER(UPB_TYPE_FLOAT, float, float) -DEFINE_WRAPPER_HANDLER(UPB_TYPE_INT64, int64, int64_t) -DEFINE_WRAPPER_HANDLER(UPB_TYPE_UINT64, uint64, uint64_t) -DEFINE_WRAPPER_HANDLER(UPB_TYPE_DOUBLE, double, double) - -#undef DEFINE_WRAPPER_HANDLER - -static bool strwrapper_end_handler(void *closure, const void *hd) { - stringfields_parseframe_t* frame = closure; - const upb_fielddef **field = (const upb_fielddef **) hd; - wrapperfields_parseframe_t* wrapper_frame = frame->closure; - MessageHeader* msg; - CACHED_VALUE* cached; - - if (wrapper_frame->is_msg) { - msg = wrapper_frame->submsg; - cached = find_zval_property(msg, *field); - } else { - cached = wrapper_frame->submsg; - } - - new_php_string(cached, frame->sink.ptr, frame->sink.len); - - stringsink_uninit(&frame->sink); - free(frame); - - return true; -} - -static void add_handlers_for_wrapper(const upb_msgdef* msgdef, - upb_handlers* h) { - const upb_fielddef* f = upb_msgdef_itof(msgdef, 1); - DescriptorInternal* desc; - size_t offset; - - TSRMLS_FETCH(); - desc = get_msgdef_desc(msgdef); - offset = desc->layout->fields[upb_fielddef_index(f)].offset; - - switch (upb_msgdef_wellknowntype(msgdef)) { -#define SET_HANDLER(utype, ltype) \ - case utype: { \ - upb_handlerattr attr = UPB_HANDLERATTR_INIT; \ - attr.handler_data = newhandlerdata(h, offset); \ - upb_handlers_set##ltype(h, f, ltype##wrapper_handler, &attr); \ - break; \ - } - - SET_HANDLER(UPB_WELLKNOWN_BOOLVALUE, bool); - SET_HANDLER(UPB_WELLKNOWN_INT32VALUE, int32); - SET_HANDLER(UPB_WELLKNOWN_UINT32VALUE, uint32); - SET_HANDLER(UPB_WELLKNOWN_FLOATVALUE, float); - SET_HANDLER(UPB_WELLKNOWN_INT64VALUE, int64); - SET_HANDLER(UPB_WELLKNOWN_UINT64VALUE, uint64); - SET_HANDLER(UPB_WELLKNOWN_DOUBLEVALUE, double); - -#undef SET_HANDLER - - case UPB_WELLKNOWN_STRINGVALUE: - case UPB_WELLKNOWN_BYTESVALUE: { - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - attr.handler_data = newhandlerfielddata(h, f); - - upb_handlers_setstartstr(h, f, str_handler, &attr); - upb_handlers_setstring(h, f, stringdata_handler, &attr); - upb_handlers_setendstr(h, f, strwrapper_end_handler, &attr); - break; - } - default: - // Cannot reach here. - break; - } -} - -static bool add_unknown_handler(void* closure, const void* hd, const char* buf, - size_t size) { - encodeunknown_handlerfunc handler = - ((unknownfields_handlerdata_t*)hd)->handler; - - MessageHeader* msg = (MessageHeader*)closure; - stringsink* unknown = DEREF(message_data(msg), 0, stringsink*); - if (unknown == NULL) { - DEREF(message_data(msg), 0, stringsink*) = ALLOC(stringsink); - unknown = DEREF(message_data(msg), 0, stringsink*); - stringsink_init(unknown); - } - - handler(unknown, NULL, buf, size, NULL); - - return true; -} - -void add_handlers_for_message(const void* closure, upb_handlers* h) { - const upb_msgdef* msgdef = upb_handlers_msgdef(h); - TSRMLS_FETCH(); - DescriptorInternal* desc = get_msgdef_desc(msgdef); - register_class(desc, false TSRMLS_CC); - upb_msg_field_iter i; - - // If this is a mapentry message type, set up a special set of handlers and - // bail out of the normal (user-defined) message type handling. - if (upb_msgdef_mapentry(msgdef)) { - add_handlers_for_mapentry(msgdef, h); - return; - } - - // If this is a wrapper message type, set up a special set of handlers and - // bail out of the normal (user-defined) message type handling. - if (is_wrapper_msg(msgdef)) { - add_handlers_for_wrapper(msgdef, h); - return; - } - - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - attr.handler_data = newunknownfieldshandlerdata(h); - upb_handlers_setunknown(h, add_unknown_handler, &attr); - - for (upb_msg_field_begin(&i, desc->msgdef); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - size_t offset = desc->layout->fields[upb_fielddef_index(f)].offset; - - if (upb_fielddef_containingoneof(f)) { - size_t oneof_case_offset = - desc->layout->fields[upb_fielddef_index(f)].case_offset; - int property_cache_index = - desc->layout->fields[upb_fielddef_index(f)].cache_index; - add_handlers_for_oneof_field(h, desc->msgdef, f, offset, - oneof_case_offset, property_cache_index); - } else if (is_map_field(f)) { - add_handlers_for_mapfield(h, f, offset); - } else if (upb_fielddef_isseq(f)) { - add_handlers_for_repeated_field(h, f, offset); - } else { - add_handlers_for_singular_field(h, f, offset, false); - } - } -} - -// Constructs the handlers for filling a message's data into an in-memory -// object. -const upb_handlers* get_fill_handlers(DescriptorInternal* desc) { - return upb_handlercache_get(desc->pool->fill_handler_cache, desc->msgdef); -} - -static const upb_pbdecodermethod *msgdef_decodermethod(DescriptorInternal* desc) { - return upb_pbcodecache_get(desc->pool->fill_method_cache, desc->msgdef); -} - -static const upb_json_parsermethod *msgdef_jsonparsermethod(DescriptorInternal* desc) { - return upb_json_codecache_get(desc->pool->json_fill_method_cache, desc->msgdef); -} - -// ----------------------------------------------------------------------------- -// Serializing. -// ----------------------------------------------------------------------------- - -static void putmsg(zval* msg, const DescriptorInternal* desc, upb_sink sink, - int depth, bool is_json TSRMLS_DC); -static void putrawmsg(MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth, bool is_json, - bool open_msg TSRMLS_DC); -static void putwrappervalue( - zval* value, const upb_fielddef* f, - upb_sink sink, int depth, bool is_json TSRMLS_DC); -static void putjsonany(MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth TSRMLS_DC); -static void putjsonlistvalue( - MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth TSRMLS_DC); -static void putjsonstruct( - MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth TSRMLS_DC); - -static void putstr(zval* str, const upb_fielddef* f, upb_sink sink, - bool force_default); - -static void putrawstr(const char* str, int len, const upb_fielddef* f, - upb_sink sink, bool force_default); - -static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink sink, - int depth, bool is_json TSRMLS_DC); -static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f, - upb_sink sink, int depth, bool is_json TSRMLS_DC); - -static void putarray(zval* array, const upb_fielddef* f, upb_sink sink, - int depth, bool is_json TSRMLS_DC); -static void putmap(zval* map, const upb_fielddef* f, upb_sink sink, - int depth, bool is_json TSRMLS_DC); - -static upb_selector_t getsel(const upb_fielddef* f, upb_handlertype_t type) { - upb_selector_t ret; - bool ok = upb_handlers_getselector(f, type, &ret); - PHP_PROTO_ASSERT(ok); - return ret; -} - -static void put_optional_value(const void* memory, int len, - const upb_fielddef* f, - int depth, upb_sink sink, - bool is_json TSRMLS_DC) { - PHP_PROTO_ASSERT(upb_fielddef_label(f) == UPB_LABEL_OPTIONAL); - - switch (upb_fielddef_type(f)) { -#define T(upbtypeconst, upbtype, ctype, default_value) \ - case upbtypeconst: { \ - ctype value = DEREF(memory, 0, ctype); \ - if (is_json || value != default_value) { \ - upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); \ - upb_sink_put##upbtype(sink, sel, value); \ - } \ - } break; - - T(UPB_TYPE_FLOAT, float, float, 0.0) - T(UPB_TYPE_DOUBLE, double, double, 0.0) - T(UPB_TYPE_BOOL, bool, uint8_t, 0) - T(UPB_TYPE_ENUM, int32, int32_t, 0) - T(UPB_TYPE_INT32, int32, int32_t, 0) - T(UPB_TYPE_UINT32, uint32, uint32_t, 0) - T(UPB_TYPE_INT64, int64, int64_t, 0) - T(UPB_TYPE_UINT64, uint64, uint64_t, 0) - -#undef T - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - putrawstr(memory, len, f, sink, is_json); - break; - case UPB_TYPE_MESSAGE: { -#if PHP_MAJOR_VERSION < 7 - MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory); -#else - MessageHeader *submsg = - (MessageHeader*)((char*)(*(zend_object**)memory) - - XtOffsetOf(MessageHeader, std)); -#endif - putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC); - break; - } - default: - PHP_PROTO_ASSERT(false); - } -} - -// Only string/bytes fields are stored as zval. -static const char* raw_value(void* memory, const upb_fielddef* f) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: -#if PHP_MAJOR_VERSION < 7 - return Z_STRVAL_PP((zval**)memory); -#else - return ZSTR_VAL(*(zend_string**)memory); -#endif - break; - default: - return memory; - } -} - -static int raw_value_len(void* memory, int len, const upb_fielddef* f) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: -#if PHP_MAJOR_VERSION < 7 - return Z_STRLEN_PP((zval**)memory); -#else - return ZSTR_LEN(*(zend_string**)memory); -#endif - default: - return len; - } -} - -static void putmap(zval* map, const upb_fielddef* f, upb_sink sink, - int depth, bool is_json TSRMLS_DC) { - upb_sink subsink; - const upb_fielddef* key_field; - const upb_fielddef* value_field; - MapIter it; - int len, size; - - PHP_PROTO_ASSERT(map != NULL); - Map* intern = UNBOX(Map, map); - size = upb_strtable_count(&intern->table); - if (size == 0) return; - - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - - PHP_PROTO_ASSERT(upb_fielddef_type(f) == UPB_TYPE_MESSAGE); - key_field = map_field_key(f); - value_field = map_field_value(f); - - for (map_begin(map, &it TSRMLS_CC); !map_done(&it); map_next(&it)) { - upb_status status; - - upb_sink entry_sink; - upb_sink_startsubmsg(subsink, getsel(f, UPB_HANDLER_STARTSUBMSG), - &entry_sink); - upb_sink_startmsg(entry_sink); - - // Serialize key. - const char *key = map_iter_key(&it, &len); - put_optional_value(key, len, key_field, depth + 1, - entry_sink, is_json TSRMLS_CC); - - // Serialize value. - upb_value value = map_iter_value(&it, &len); - put_optional_value(raw_value(upb_value_memory(&value), value_field), - raw_value_len(upb_value_memory(&value), len, value_field), - value_field, depth + 1, entry_sink, is_json TSRMLS_CC); - - upb_sink_endmsg(entry_sink, &status); - upb_sink_endsubmsg(subsink, entry_sink, getsel(f, UPB_HANDLER_ENDSUBMSG)); - } - - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); -} - -static void putmsg(zval* msg_php, const DescriptorInternal* desc, upb_sink sink, - int depth, bool is_json TSRMLS_DC) { - MessageHeader* msg = UNBOX(MessageHeader, msg_php); - putrawmsg(msg, desc, sink, depth, is_json, true TSRMLS_CC); -} - -static const upb_handlers* msgdef_json_serialize_handlers( - DescriptorInternal* desc, bool preserve_proto_fieldnames); - -static void putjsonany(MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth TSRMLS_DC) { - upb_status status; - const upb_fielddef* type_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_TYPE); - const upb_fielddef* value_field = upb_msgdef_itof(desc->msgdef, UPB_ANY_VALUE); - - zval* type_url_php_str; - const upb_msgdef *payload_type = NULL; - - upb_sink_startmsg(sink); - - /* Handle type url */ - type_url_php_str = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, type_field)); - if (Z_STRLEN_P(type_url_php_str) > 0) { - putstr(type_url_php_str, type_field, sink, false); - } - - { - const char* type_url_str = Z_STRVAL_P(type_url_php_str); - size_t type_url_len = Z_STRLEN_P(type_url_php_str); - if (type_url_len <= 20 || - strncmp(type_url_str, "type.googleapis.com/", 20) != 0) { - zend_error(E_ERROR, "Invalid type url: %s", type_url_str); - } - - /* Resolve type url */ - type_url_str += 20; - type_url_len -= 20; - - payload_type = upb_symtab_lookupmsg2( - generated_pool->symtab, type_url_str, type_url_len); - if (payload_type == NULL) { - zend_error(E_ERROR, "Unknown type: %s", type_url_str); - return; - } - } - - { - zval* value_php_str; - const char* value_str; - size_t value_len; - - value_php_str = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, value_field)); - value_str = Z_STRVAL_P(value_php_str); - value_len = Z_STRLEN_P(value_php_str); - - if (value_len > 0) { - DescriptorInternal* payload_desc = get_msgdef_desc(payload_type); - register_class(payload_desc, false TSRMLS_CC); - zend_class_entry* payload_klass = payload_desc->klass; - zval val; - upb_sink subsink; - bool is_wellknown; - - /* Create message of the payload type. */ - ZVAL_OBJ(&val, payload_klass->create_object(payload_klass TSRMLS_CC)); - MessageHeader* intern = UNBOX(MessageHeader, &val); - custom_data_init(payload_klass, intern PHP_PROTO_TSRMLS_CC); - - merge_from_string(value_str, value_len, payload_desc, intern); - - is_wellknown = - upb_msgdef_wellknowntype(payload_desc->msgdef) != - UPB_WELLKNOWN_UNSPECIFIED; - if (is_wellknown) { - upb_sink_startstr(sink, getsel(value_field, UPB_HANDLER_STARTSTR), 0, - &subsink); - } - - subsink.handlers = - msgdef_json_serialize_handlers(payload_desc, true); - subsink.closure = sink.closure; - putrawmsg(intern, payload_desc, subsink, depth, true, - is_wellknown TSRMLS_CC); - - zval_dtor(&val); - } - } - - upb_sink_endmsg(sink, &status); -} - -static void putjsonlistvalue( - MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth TSRMLS_DC) { - upb_status status; - upb_sink subsink; - const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1); - zval* array; - RepeatedField* intern; - HashTable *ht; - int size; - - upb_sink_startmsg(sink); - - array = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (ZVAL_IS_NULL(array)) { - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); - } else { - intern = UNBOX(RepeatedField, array); - ht = PHP_PROTO_HASH_OF(intern->array); - size = zend_hash_num_elements(ht); - - if (size == 0) { - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); - } else { - putarray(array, f, sink, depth, true TSRMLS_CC); - } - } - - upb_sink_endmsg(sink, &status); -} - -static void putjsonstruct( - MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth TSRMLS_DC) { - upb_status status; - upb_sink subsink; - const upb_fielddef* f = upb_msgdef_itof(desc->msgdef, 1); - zval* map; - Map* intern; - int size; - - upb_sink_startmsg(sink); - - map = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (ZVAL_IS_NULL(map)) { - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); - } else { - intern = UNBOX(Map, map); - size = upb_strtable_count(&intern->table); - - if (size == 0) { - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); - } else { - putmap(map, f, sink, depth, true TSRMLS_CC); - } - } - - upb_sink_endmsg(sink, &status); -} - -static void putrawmsg(MessageHeader* msg, const DescriptorInternal* desc, - upb_sink sink, int depth, bool is_json, - bool open_msg TSRMLS_DC) { - upb_msg_field_iter i; - upb_status status; - - if (is_json && - upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_ANY) { - putjsonany(msg, desc, sink, depth TSRMLS_CC); - return; - } - - if (is_json && - upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_LISTVALUE) { - putjsonlistvalue(msg, desc, sink, depth TSRMLS_CC); - return; - } - - if (is_json && - upb_msgdef_wellknowntype(desc->msgdef) == UPB_WELLKNOWN_STRUCT) { - putjsonstruct(msg, desc, sink, depth TSRMLS_CC); - return; - } - - if (open_msg) { - upb_sink_startmsg(sink); - } - - // Protect against cycles (possible because users may freely reassign message - // and repeated fields) by imposing a maximum recursion depth. - if (depth > ENCODE_MAX_NESTING) { - zend_error(E_ERROR, - "Maximum recursion depth exceeded during encoding."); - } - - for (upb_msg_field_begin(&i, desc->msgdef); !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef* f = upb_msg_iter_field(&i); - uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset; - bool containing_oneof = false; - - if (upb_fielddef_containingoneof(f)) { - uint32_t oneof_case_offset = - desc->layout->fields[upb_fielddef_index(f)].case_offset; - // For a oneof, check that this field is actually present -- skip all the - // below if not. - if (DEREF(message_data(msg), oneof_case_offset, uint32_t) != - upb_fielddef_number(f)) { - continue; - } - // Otherwise, fall through to the appropriate singular-field handler - // below. - containing_oneof = true; - } - - if (is_map_field(f)) { - zval* map = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (!ZVAL_IS_NULL(map)) { - putmap(map, f, sink, depth, is_json TSRMLS_CC); - } - } else if (upb_fielddef_isseq(f)) { - zval* array = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (!ZVAL_IS_NULL(array)) { - putarray(array, f, sink, depth, is_json TSRMLS_CC); - } - } else if (upb_fielddef_isstring(f)) { - zval* str = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (containing_oneof || (is_json && is_wrapper_msg(desc->msgdef)) || - Z_STRLEN_P(str) > 0) { - putstr(str, f, sink, is_json && is_wrapper_msg(desc->msgdef)); - } - } else if (upb_fielddef_issubmsg(f)) { - zval* submsg = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (is_wrapper_msg(upb_fielddef_msgsubdef(f)) && - Z_TYPE_P(submsg) != IS_NULL && Z_TYPE_P(submsg) != IS_OBJECT) { - putwrappervalue(submsg, f, sink, depth, is_json TSRMLS_CC); - } else { - putsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC); - } - } else { - upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); - -#define T(upbtypeconst, upbtype, ctype, default_value) \ - case upbtypeconst: { \ - ctype value = DEREF(message_data(msg), offset, ctype); \ - if (containing_oneof || \ - (is_json && is_wrapper_msg(desc->msgdef)) || \ - value != default_value) { \ - upb_sink_put##upbtype(sink, sel, value); \ - } \ - } break; - - switch (upb_fielddef_type(f)) { - T(UPB_TYPE_FLOAT, float, float, 0.0) - T(UPB_TYPE_DOUBLE, double, double, 0.0) - T(UPB_TYPE_BOOL, bool, uint8_t, 0) - case UPB_TYPE_ENUM: - T(UPB_TYPE_INT32, int32, int32_t, 0) - T(UPB_TYPE_UINT32, uint32, uint32_t, 0) - T(UPB_TYPE_INT64, int64, int64_t, 0) - T(UPB_TYPE_UINT64, uint64, uint64_t, 0) - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - zend_error(E_ERROR, "Internal error."); - } - -#undef T - } - } - - stringsink* unknown = DEREF(message_data(msg), 0, stringsink*); - if (unknown != NULL) { - upb_sink_putunknown(sink, unknown->ptr, unknown->len); - } - - if (open_msg) { - upb_sink_endmsg(sink, &status); - } -} - -static void putstr(zval* str, const upb_fielddef *f, - upb_sink sink, bool force_default) { - upb_sink subsink; - - if (ZVAL_IS_NULL(str)) return; - - PHP_PROTO_ASSERT(Z_TYPE_P(str) == IS_STRING); - - upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), Z_STRLEN_P(str), - &subsink); - - // For oneof string field, we may get here with string length is zero. - if (Z_STRLEN_P(str) > 0 || force_default) { - // Ensure that the string has the correct encoding. We also check at - // field-set time, but the user may have mutated the string object since - // then. - if (upb_fielddef_type(f) == UPB_TYPE_STRING && - !is_structurally_valid_utf8(Z_STRVAL_P(str), Z_STRLEN_P(str))) { - zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); - return; - } - upb_sink_putstring(subsink, getsel(f, UPB_HANDLER_STRING), Z_STRVAL_P(str), - Z_STRLEN_P(str), NULL); - } - - upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR)); -} - -static void putrawstr(const char* str, int len, const upb_fielddef* f, - upb_sink sink, bool force_default) { - upb_sink subsink; - - if (len == 0 && !force_default) return; - - // Ensure that the string has the correct encoding. We also check at field-set - // time, but the user may have mutated the string object since then. - if (upb_fielddef_type(f) == UPB_TYPE_STRING && - !is_structurally_valid_utf8(str, len)) { - zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); - return; - } - - upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), len, &subsink); - upb_sink_putstring(subsink, getsel(f, UPB_HANDLER_STRING), str, len, NULL); - upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR)); -} - -static void putsubmsg(zval* submsg_php, const upb_fielddef* f, upb_sink sink, - int depth, bool is_json TSRMLS_DC) { - if (Z_TYPE_P(submsg_php) == IS_NULL) return; - - MessageHeader *submsg = UNBOX(MessageHeader, submsg_php); - putrawsubmsg(submsg, f, sink, depth, is_json TSRMLS_CC); -} - -static void putwrappervalue( - zval* value, const upb_fielddef* f, - upb_sink sink, int depth, bool is_json TSRMLS_DC) { - upb_sink subsink; - const upb_msgdef* msgdef = upb_fielddef_msgsubdef(f); - const upb_fielddef* value_field = upb_msgdef_itof(msgdef, 1); - upb_selector_t sel = - getsel(value_field, upb_handlers_getprimitivehandlertype(value_field)); - - upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); - -#define T(upbtypeconst, upbtype, ctype, default_value) \ - case upbtypeconst: { \ - ctype value_raw; \ - native_slot_set(upb_fielddef_type(value_field), NULL, \ - &value_raw, value PHP_PROTO_TSRMLS_CC); \ - if ((is_json && is_wrapper_msg(msgdef)) || \ - value_raw != default_value) { \ - upb_sink_put##upbtype(subsink, sel, value_raw); \ - } \ - } break; - - switch (upb_fielddef_type(value_field)) { - T(UPB_TYPE_FLOAT, float, float, 0.0) - T(UPB_TYPE_DOUBLE, double, double, 0.0) - T(UPB_TYPE_BOOL, bool, uint8_t, 0) - T(UPB_TYPE_INT32, int32, int32_t, 0) - T(UPB_TYPE_UINT32, uint32, uint32_t, 0) - T(UPB_TYPE_INT64, int64, int64_t, 0) - T(UPB_TYPE_UINT64, uint64, uint64_t, 0) - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - if ((is_json && is_wrapper_msg(msgdef)) || - Z_STRLEN_P(value) > 0) { - putstr(value, value_field, subsink, is_json && is_wrapper_msg(msgdef)); - } - break; - } - case UPB_TYPE_ENUM: - case UPB_TYPE_MESSAGE: - zend_error(E_ERROR, "Internal error."); - } - -#undef T - - upb_sink_endsubmsg(sink, subsink, getsel(f, UPB_HANDLER_ENDSUBMSG)); -} - -static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f, - upb_sink sink, int depth, bool is_json TSRMLS_DC) { - upb_sink subsink; - - const upb_msgdef* m = upb_fielddef_msgsubdef(f); - DescriptorInternal* subdesc = get_msgdef_desc(m); - - upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); - putrawmsg(submsg, subdesc, subsink, depth + 1, is_json, true TSRMLS_CC); - upb_sink_endsubmsg(sink, subsink, getsel(f, UPB_HANDLER_ENDSUBMSG)); -} - -static void putarray(zval* array, const upb_fielddef* f, upb_sink sink, - int depth, bool is_json TSRMLS_DC) { - upb_sink subsink; - upb_fieldtype_t type = upb_fielddef_type(f); - upb_selector_t sel = 0; - int size, i; - - PHP_PROTO_ASSERT(array != NULL); - RepeatedField* intern = UNBOX(RepeatedField, array); - HashTable *ht = PHP_PROTO_HASH_OF(intern->array); - size = zend_hash_num_elements(ht); - if (size == 0) return; - - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - - if (upb_fielddef_isprimitive(f)) { - sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); - } - - for (i = 0; i < size; i++) { - void* memory = repeated_field_index_native(intern, i TSRMLS_CC); - switch (type) { -#define T(upbtypeconst, upbtype, ctype) \ - case upbtypeconst: \ - upb_sink_put##upbtype(subsink, sel, *((ctype*)memory)); \ - break; - - T(UPB_TYPE_FLOAT, float, float) - T(UPB_TYPE_DOUBLE, double, double) - T(UPB_TYPE_BOOL, bool, int8_t) - case UPB_TYPE_ENUM: - T(UPB_TYPE_INT32, int32, int32_t) - T(UPB_TYPE_UINT32, uint32, uint32_t) - T(UPB_TYPE_INT64, int64, int64_t) - T(UPB_TYPE_UINT64, uint64, uint64_t) - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { -#if PHP_MAJOR_VERSION < 7 - const char* rawstr = Z_STRVAL_P(*(zval**)memory); - int len = Z_STRLEN_P(*(zval**)memory); -#else - const char* rawstr = ZSTR_VAL(*(zend_string**)memory); - int len = ZSTR_LEN(*(zend_string**)memory); -#endif - putrawstr(rawstr, len, f, subsink, - is_json && is_wrapper_msg(upb_fielddef_containingtype(f))); - break; - } - case UPB_TYPE_MESSAGE: { -#if PHP_MAJOR_VERSION < 7 - MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory); -#else - MessageHeader *submsg = - (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) - - XtOffsetOf(MessageHeader, std)); -#endif - putrawsubmsg(submsg, f, subsink, depth, is_json TSRMLS_CC); - break; - } - -#undef T - } - } - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); -} - -static const upb_handlers* msgdef_pb_serialize_handlers(DescriptorInternal* desc) { - return upb_handlercache_get(desc->pool->pb_serialize_handler_cache, - desc->msgdef); -} - -static const upb_handlers* msgdef_json_serialize_handlers( - DescriptorInternal* desc, bool preserve_proto_fieldnames) { - if (preserve_proto_fieldnames) { - return upb_handlercache_get( - desc->pool->json_serialize_handler_preserve_cache, desc->msgdef); - } else { - return upb_handlercache_get(desc->pool->json_serialize_handler_cache, - desc->msgdef); - } -} - -// ----------------------------------------------------------------------------- -// PHP encode/decode methods -// ----------------------------------------------------------------------------- - -void serialize_to_string(zval* val, zval* return_value TSRMLS_DC) { - DescriptorInternal* desc = get_ce_desc(Z_OBJCE_P(val)); - - stringsink sink; - stringsink_init(&sink); - - { - const upb_handlers* serialize_handlers = msgdef_pb_serialize_handlers(desc); - - stackenv se; - upb_pb_encoder* encoder; - - stackenv_init(&se, "Error occurred during encoding: %s"); - encoder = upb_pb_encoder_create(se.arena, serialize_handlers, sink.sink); - - putmsg(val, desc, upb_pb_encoder_input(encoder), 0, false TSRMLS_CC); - - PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1); - - stackenv_uninit(&se); - stringsink_uninit(&sink); - } -} - -PHP_METHOD(Message, serializeToString) { - serialize_to_string(getThis(), return_value TSRMLS_CC); -} - -void merge_from_string(const char* data, int data_len, DescriptorInternal* desc, - MessageHeader* msg) { - const upb_pbdecodermethod* method = msgdef_decodermethod(desc); - const upb_handlers* h = upb_pbdecodermethod_desthandlers(method); - stackenv se; - upb_sink sink; - upb_pbdecoder* decoder; - void* closure; - stackenv_init(&se, "Error occurred during parsing: %s"); - - if (is_wrapper_msg(desc->msgdef)) { - wrapperfields_parseframe_t* frame = - (wrapperfields_parseframe_t*)malloc( - sizeof(wrapperfields_parseframe_t)); - frame->submsg = msg; - frame->is_msg = true; - closure = frame; - } else { - closure = msg; - } - - upb_sink_reset(&sink, h, closure); - decoder = upb_pbdecoder_create(se.arena, method, sink, &se.status); - upb_bufsrc_putbuf(data, data_len, upb_pbdecoder_input(decoder)); - - if (is_wrapper_msg(desc->msgdef)) { - free((wrapperfields_parseframe_t*)closure); - } - - stackenv_uninit(&se); -} - -PHP_METHOD(Message, mergeFromString) { - DescriptorInternal* desc = get_ce_desc(Z_OBJCE_P(getThis())); - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - - char *data = NULL; - PHP_PROTO_SIZE data_len; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) == - FAILURE) { - return; - } - - merge_from_string(data, data_len, desc, msg); -} - -PHP_METHOD(Message, serializeToJsonString) { - DescriptorInternal* desc = get_ce_desc(Z_OBJCE_P(getThis())); - - zend_bool preserve_proto_fieldnames = false; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", - &preserve_proto_fieldnames) == FAILURE) { - return; - } - - stringsink sink; - stringsink_init(&sink); - - { - const upb_handlers* serialize_handlers = - msgdef_json_serialize_handlers(desc, preserve_proto_fieldnames); - upb_json_printer* printer; - stackenv se; - - stackenv_init(&se, "Error occurred during encoding: %s"); - printer = upb_json_printer_create(se.arena, serialize_handlers, sink.sink); - - putmsg(getThis(), desc, upb_json_printer_input(printer), 0, true TSRMLS_CC); - - PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1); - - stackenv_uninit(&se); - stringsink_uninit(&sink); - } -} - -PHP_METHOD(Message, mergeFromJsonString) { - DescriptorInternal* desc = get_ce_desc(Z_OBJCE_P(getThis())); - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - - char *data = NULL; - PHP_PROTO_SIZE data_len; - zend_bool ignore_json_unknown = false; - - if (zend_parse_parameters( - ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &data, &data_len, - &ignore_json_unknown) == - FAILURE) { - return; - } - - // TODO(teboring): Check and respect string encoding. If not UTF-8, we need to - // convert, because string handlers pass data directly to message string - // fields. - - // TODO(teboring): Clear message. - - { - const upb_json_parsermethod* method = msgdef_jsonparsermethod(desc); - stackenv se; - upb_sink sink; - upb_json_parser* parser; - void* closure; - stackenv_init(&se, "Error occurred during parsing: %s"); - - if (is_wrapper_msg(desc->msgdef)) { - wrapperfields_parseframe_t* frame = - (wrapperfields_parseframe_t*)malloc( - sizeof(wrapperfields_parseframe_t)); - frame->submsg = msg; - frame->is_msg = true; - closure = frame; - } else { - closure = msg; - } - - upb_sink_reset(&sink, get_fill_handlers(desc), closure); - parser = upb_json_parser_create(se.arena, method, generated_pool->symtab, - sink, &se.status, ignore_json_unknown); - upb_bufsrc_putbuf(data, data_len, upb_json_parser_input(parser)); - - if (is_wrapper_msg(desc->msgdef)) { - free((wrapperfields_parseframe_t*)closure); - } - stackenv_uninit(&se); - } -} - -// TODO(teboring): refactoring with putrawmsg -static void discard_unknown_fields(MessageHeader* msg) { - upb_msg_field_iter it; - - stringsink* unknown = DEREF(message_data(msg), 0, stringsink*); - if (unknown != NULL) { - stringsink_uninit(unknown); - FREE(unknown); - DEREF(message_data(msg), 0, stringsink*) = NULL; - } - - // Recursively discard unknown fields of submessages. - DescriptorInternal* desc = msg->descriptor; - TSRMLS_FETCH(); - for (upb_msg_field_begin(&it, desc->msgdef); - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - upb_fielddef* f = upb_msg_iter_field(&it); - - if (upb_fielddef_containingoneof(f)) { - uint32_t oneof_case_offset = - desc->layout->fields[upb_fielddef_index(f)].case_offset; - // For a oneof, check that this field is actually present -- skip all the - // below if not. - if (DEREF(message_data(msg), oneof_case_offset, uint32_t) != - upb_fielddef_number(f)) { - continue; - } - // Otherwise, fall through to the appropriate singular-field handler - // below. - } - - if (is_map_field(f)) { - MapIter map_it; - int len; - const upb_fielddef* value_field; - - value_field = map_field_value(f); - if (!upb_fielddef_issubmsg(value_field)) continue; - - zval* map_php = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (ZVAL_IS_NULL(map_php)) continue; - - for (map_begin(map_php, &map_it TSRMLS_CC); - !map_done(&map_it); map_next(&map_it)) { - upb_value value = map_iter_value(&map_it, &len); - const void* memory = raw_value(upb_value_memory(&value), value_field); -#if PHP_MAJOR_VERSION < 7 - MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory); -#else - MessageHeader *submsg = - (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) - - XtOffsetOf(MessageHeader, std)); -#endif - discard_unknown_fields(submsg); - } - } else if (upb_fielddef_isseq(f)) { - if (!upb_fielddef_issubmsg(f)) continue; - - zval* array_php = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (ZVAL_IS_NULL(array_php)) continue; - - int size, i; - RepeatedField* intern = UNBOX(RepeatedField, array_php); - HashTable *ht = PHP_PROTO_HASH_OF(intern->array); - size = zend_hash_num_elements(ht); - if (size == 0) continue; - - for (i = 0; i < size; i++) { - void* memory = repeated_field_index_native(intern, i TSRMLS_CC); -#if PHP_MAJOR_VERSION < 7 - MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory); -#else - MessageHeader *submsg = - (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) - - XtOffsetOf(MessageHeader, std)); -#endif - discard_unknown_fields(submsg); - } - } else if (upb_fielddef_issubmsg(f)) { - zval* submsg_php = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, f)); - if (Z_TYPE_P(submsg_php) == IS_NULL) continue; - MessageHeader* submsg = UNBOX(MessageHeader, submsg_php); - discard_unknown_fields(submsg); - } - } -} - -PHP_METHOD(Message, discardUnknownFields) { - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - discard_unknown_fields(msg); -} diff --git a/php/ext/google/protobuf2/make-preload.php b/php/ext/google/protobuf/make-preload.php similarity index 97% rename from php/ext/google/protobuf2/make-preload.php rename to php/ext/google/protobuf/make-preload.php index c6043e28911f..4b1ce7f676fa 100644 --- a/php/ext/google/protobuf2/make-preload.php +++ b/php/ext/google/protobuf/make-preload.php @@ -8,7 +8,7 @@ $filenames = explode("\n", stream_get_contents($handle)); array_pop($filenames); // empty string after last '\n' $filenames[] = "Google/Protobuf/DescriptorPool.php"; -$output = "../ext/google/protobuf2/bundled_php.c"; +$output = "../ext/google/protobuf/bundled_php.c"; function stripSuffix($str, $suffix) { return substr($str, 0, strlen($str) - strlen($suffix)); diff --git a/php/ext/google/protobuf/map.c b/php/ext/google/protobuf/map.c index 2dded9224e1c..0217c6491e59 100644 --- a/php/ext/google/protobuf/map.c +++ b/php/ext/google/protobuf/map.c @@ -28,390 +28,187 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include +#include "map.h" + #include #include -#include "protobuf.h" -#include "utf8.h" - -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) - ZEND_ARG_INFO(0, index) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, newval) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_void, 0) -ZEND_END_ARG_INFO() +#include -// Utilities +#include "arena.h" +#include "convert.h" +#include "php-upb.h" +#include "protobuf.h" -void* upb_value_memory(upb_value* v) { - return (void*)(&v->val); -} +static void MapFieldIter_make(zval *val, zval *map_field); // ----------------------------------------------------------------------------- -// Basic map operations on top of upb's strtable. -// -// Note that we roll our own `Map` container here because, as for -// `RepeatedField`, we want a strongly-typed container. This is so that any user -// errors due to incorrect map key or value types are raised as close as -// possible to the error site, rather than at some deferred point (e.g., -// serialization). -// -// We build our `Map` on top of upb_strtable so that we're able to take -// advantage of the native_slot storage abstraction, as RepeatedField does. -// (This is not quite a perfect mapping -- see the key conversions below -- but -// gives us full support and error-checking for all value types for free.) +// MapField // ----------------------------------------------------------------------------- -// Map values are stored using the native_slot abstraction (as with repeated -// field values), but keys are a bit special. Since we use a strtable, we need -// to store keys as sequences of bytes such that equality of those bytes maps -// one-to-one to equality of keys. We store strings directly (i.e., they map to -// their own bytes) and integers as native integers (using the native_slot -// abstraction). - -// Note that there is another tradeoff here in keeping string keys as native -// strings rather than PHP strings: traversing the Map requires conversion to -// PHP string values on every traversal, potentially creating more garbage. We -// should consider ways to cache a PHP version of the key if this becomes an -// issue later. - -// Forms a key to use with the underlying strtable from a PHP key value. |buf| -// must point to TABLE_KEY_BUF_LENGTH bytes of temporary space, used to -// construct a key byte sequence if needed. |out_key| and |out_length| provide -// the resulting key data/length. -#define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t) -static bool table_key(Map* self, zval* key, - char* buf, - const char** out_key, - size_t* out_length TSRMLS_DC) { - switch (self->key_type) { - case UPB_TYPE_STRING: - if (!protobuf_convert_to_string(key)) { - return false; - } - if (!is_structurally_valid_utf8(Z_STRVAL_P(key), Z_STRLEN_P(key))) { - zend_error(E_USER_ERROR, "Given key is not UTF8 encoded."); - return false; - } - *out_key = Z_STRVAL_P(key); - *out_length = Z_STRLEN_P(key); - break; - -#define CASE_TYPE(upb_type, type, c_type, php_type) \ - case UPB_TYPE_##upb_type: { \ - c_type type##_value; \ - if (!protobuf_convert_to_##type(key, &type##_value)) { \ - return false; \ - } \ - native_slot_set_by_array(self->key_type, NULL, buf, key TSRMLS_CC); \ - *out_key = buf; \ - *out_length = native_slot_size(self->key_type); \ - break; \ +typedef struct { + zend_object std; + zval arena; + upb_map *map; + upb_fieldtype_t key_type; + upb_fieldtype_t val_type; + const Descriptor* desc; // When values are messages. +} MapField; + +zend_class_entry *MapField_class_entry; +static zend_object_handlers MapField_object_handlers; + +// PHP Object Handlers ///////////////////////////////////////////////////////// + +/** + * MapField_create() + * + * PHP class entry function to allocate and initialize a new MapField + * object. + */ +static zend_object* MapField_create(zend_class_entry *class_type) { + MapField *intern = emalloc(sizeof(MapField)); + zend_object_std_init(&intern->std, class_type); + intern->std.handlers = &MapField_object_handlers; + Arena_Init(&intern->arena); + intern->map = NULL; + // Skip object_properties_init(), we don't allow derived classes. + return &intern->std; +} + +/** + * MapField_dtor() + * + * Object handler to destroy a MapField. This releases all resources + * associated with the message. Note that it is possible to access a destroyed + * object from PHP in rare cases. + */ +static void MapField_destructor(zend_object* obj) { + MapField* intern = (MapField*)obj; + ObjCache_Delete(intern->map); + zval_ptr_dtor(&intern->arena); + zend_object_std_dtor(&intern->std); +} + +static zval *Map_GetPropertyPtrPtr(zval *object, zval *member, int type, + void **cache_slot) { + return NULL; // We don't offer direct references to our properties. +} + +static HashTable *map_get_properties(zval *object TSRMLS_DC) { + return NULL; // We do not have a properties table. +} + +// C Functions from map.h ////////////////////////////////////////////////////// + +// These are documented in the header file. + +void MapField_GetPhpWrapper(zval *val, upb_map *map, const upb_fielddef *f, + zval *arena) { + if (!map) { + ZVAL_NULL(val); + return; } - CASE_TYPE(BOOL, bool, int8_t, BOOL) - CASE_TYPE(INT32, int32, int32_t, LONG) - CASE_TYPE(INT64, int64, int64_t, LONG) - CASE_TYPE(UINT32, uint32, uint32_t, LONG) - CASE_TYPE(UINT64, uint64, uint64_t, LONG) -#undef CASE_TYPE - - default: - // Map constructor should not allow a Map with another key type to be - // constructed. - assert(false); - break; + if (!ObjCache_Get(map, val)) { + const upb_msgdef *ent = upb_fielddef_msgsubdef(f); + const upb_fielddef *key_f = upb_msgdef_itof(ent, 1); + const upb_fielddef *val_f = upb_msgdef_itof(ent, 2); + MapField *intern = emalloc(sizeof(MapField)); + zend_object_std_init(&intern->std, MapField_class_entry); + intern->std.handlers = &MapField_object_handlers; + ZVAL_COPY(&intern->arena, arena); + intern->map = map; + intern->key_type = upb_fielddef_type(key_f); + intern->val_type = upb_fielddef_type(val_f); + intern->desc = Descriptor_GetFromFieldDef(val_f); + // Skip object_properties_init(), we don't allow derived classes. + ObjCache_Add(intern->map, &intern->std); + ZVAL_OBJ(val, &intern->std); } - - return true; -} - -// ----------------------------------------------------------------------------- -// MapField methods -// ----------------------------------------------------------------------------- - -static zend_function_entry map_field_methods[] = { - PHP_ME(MapField, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, count, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(MapField, getIterator, arginfo_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// Forward declare static functions. - -static void map_field_write_dimension(zval *object, zval *key, - zval *value TSRMLS_DC); - -// ----------------------------------------------------------------------------- -// MapField creation/destruction -// ----------------------------------------------------------------------------- - -zend_class_entry* map_field_type; -zend_class_entry* map_field_iter_type; - -zend_object_handlers* map_field_handlers; -zend_object_handlers* map_field_iter_handlers; - -static void map_begin_internal(Map *map, MapIter *iter) { - iter->self = map; - upb_strtable_begin(&iter->it, &map->table); -} - -static HashTable *map_field_get_gc(zval *object, CACHED_VALUE **table, - int *n TSRMLS_DC) { - // TODO(teboring): Unfortunately, zend engine does not support garbage - // collection for custom array. We have to use zend engine's native array - // instead. - *table = NULL; - *n = 0; - return NULL; } -// Define map value element free function. -#if PHP_MAJOR_VERSION < 7 -static inline void php_proto_map_string_release(void *value) { - zval_ptr_dtor(value); -} +upb_map *MapField_GetUpbMap(zval *val, const upb_fielddef *f, upb_arena *arena) { + const upb_msgdef *ent = upb_fielddef_msgsubdef(f); + const upb_fielddef *key_f = upb_msgdef_itof(ent, 1); + const upb_fielddef *val_f = upb_msgdef_itof(ent, 2); + upb_fieldtype_t key_type = upb_fielddef_type(key_f); + upb_fieldtype_t val_type = upb_fielddef_type(val_f); + const Descriptor *desc = Descriptor_GetFromFieldDef(val_f); -static inline void php_proto_map_object_release(void *value) { - zval_ptr_dtor(value); -} -#else -static inline void php_proto_map_string_release(void *value) { - zend_string* object = *(zend_string**)value; - zend_string_release(object); -} -static inline void php_proto_map_object_release(void *value) { - zend_object* object = *(zend_object**)value; - GC_DELREF(object); - if(GC_REFCOUNT(object) == 0) { - zend_objects_store_del(object); - } -} -#endif - -// Define object free method. -PHP_PROTO_OBJECT_FREE_START(Map, map_field) -MapIter it; -int len; -for (map_begin_internal(intern, &it); !map_done(&it); map_next(&it)) { - upb_value value = map_iter_value(&it, &len); - void *mem = upb_value_memory(&value); - switch (intern->value_type) { - case UPB_TYPE_MESSAGE: - php_proto_map_object_release(mem); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - php_proto_map_string_release(mem); - break; - default: - break; - } -} -upb_strtable_uninit(&intern->table); -PHP_PROTO_OBJECT_FREE_END - -PHP_PROTO_OBJECT_EMPTY_DTOR_START(Map, map_field) -PHP_PROTO_OBJECT_DTOR_END - -// Define object create method. -PHP_PROTO_OBJECT_CREATE_START(Map, map_field) -// Table value type is always UINT64: this ensures enough space to store the -// native_slot value. -if (!upb_strtable_init(&intern->table, UPB_CTYPE_UINT64)) { - zend_error(E_USER_ERROR, "Could not allocate table."); -} -PHP_PROTO_OBJECT_CREATE_END(Map, map_field) - -// Init class entry. -PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\MapField", Map, - map_field) -zend_class_implements(map_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess, - zend_ce_aggregate, spl_ce_Countable); -map_field_handlers->write_dimension = map_field_write_dimension; -map_field_handlers->get_gc = map_field_get_gc; -PHP_PROTO_INIT_CLASS_END - -void map_field_ensure_created(const upb_fielddef *field, - CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC) { - if (ZVAL_IS_NULL(CACHED_PTR_TO_ZVAL_PTR(map_field))) { - zval_ptr_dtor(map_field); -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(CACHED_PTR_TO_ZVAL_PTR(map_field)); -#endif - map_field_create_with_field(map_field_type, field, - map_field PHP_PROTO_TSRMLS_CC); + if (Z_ISREF_P(val)) { + ZVAL_DEREF(val); } -} -void map_field_create_with_field(const zend_class_entry *ce, - const upb_fielddef *field, - CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC) { - const upb_fielddef *key_field = map_field_key(field); - const upb_fielddef *value_field = map_field_value(field); - map_field_create_with_type( - ce, upb_fielddef_type(key_field), upb_fielddef_type(value_field), - field_type_class(value_field TSRMLS_CC), map_field PHP_PROTO_TSRMLS_CC); -} + if (Z_TYPE_P(val) == IS_ARRAY) { + upb_map *map = upb_map_new(arena, key_type, val_type); + HashTable *table = HASH_OF(val); + HashPosition pos; -void map_field_create_with_type(const zend_class_entry *ce, - upb_fieldtype_t key_type, - upb_fieldtype_t value_type, - const zend_class_entry *msg_ce, - CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC) { - CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(CACHED_PTR_TO_ZVAL_PTR(map_field), - map_field_type); - Map *intern = UNBOX(Map, CACHED_TO_ZVAL_PTR(*map_field)); - intern->key_type = key_type; - intern->value_type = value_type; - intern->msg_ce = msg_ce; -} + zend_hash_internal_pointer_reset_ex(table, &pos); -// ----------------------------------------------------------------------------- -// MapField Handlers -// ----------------------------------------------------------------------------- + while (true) { + zval php_key; + zval *php_val; + upb_msgval upb_key; + upb_msgval upb_val; -static bool map_field_read_dimension(zval *object, zval *key, int type, - CACHED_VALUE *retval TSRMLS_DC) { - Map *intern = UNBOX(Map, object); - - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_UINT64; -#endif - if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) { - return false; - } + zend_hash_get_current_key_zval_ex(table, &php_key, &pos); + php_val = zend_hash_get_current_data_ex(table, &pos); - if (upb_strtable_lookup2(&intern->table, keyval, length, &v)) { - void* mem = upb_value_memory(&v); - native_slot_get_by_map_value(intern->value_type, mem, retval TSRMLS_CC); - return true; - } else { - zend_error(E_USER_ERROR, "Given key doesn't exist."); - return false; - } -} + if (!php_val) return map; -static void map_index_unset(Map *intern, const char* keyval, int length) { - upb_value old_value; - if (upb_strtable_remove2(&intern->table, keyval, length, &old_value)) { - switch (intern->value_type) { - case UPB_TYPE_MESSAGE: { -#if PHP_MAJOR_VERSION < 7 - zval_ptr_dtor(upb_value_memory(&old_value)); -#else - zend_object* object = *(zend_object**)upb_value_memory(&old_value); - GC_DELREF(object); - if(GC_REFCOUNT(object) == 0) { - zend_objects_store_del(object); - } -#endif - break; - } - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { -#if PHP_MAJOR_VERSION < 7 - zval_ptr_dtor(upb_value_memory(&old_value)); -#else - zend_string* object = *(zend_string**)upb_value_memory(&old_value); - zend_string_release(object); -#endif - break; + if (!Convert_PhpToUpb(&php_key, &upb_key, key_type, NULL, arena) || + !Convert_PhpToUpbAutoWrap(php_val, &upb_val, val_type, desc, arena)) { + return NULL; } - default: - break; - } - } -} - -bool map_index_set(Map *intern, const char* keyval, int length, upb_value v) { - // Replace any existing value by issuing a 'remove' operation first. - map_index_unset(intern, keyval, length); - - if (!upb_strtable_insert2(&intern->table, keyval, length, v)) { - zend_error(E_USER_ERROR, "Could not insert into table"); - return false; - } - - return true; -} - -static void map_field_write_dimension(zval *object, zval *key, - zval *value TSRMLS_DC) { - Map *intern = UNBOX(Map, object); - - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - upb_value v; - void* mem; - if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) { - return; - } - - mem = upb_value_memory(&v); - memset(mem, 0, native_slot_size(intern->value_type)); - if (!native_slot_set_by_map(intern->value_type, intern->msg_ce, mem, - value TSRMLS_CC)) { - return; - } -#ifndef NDEBUG - v.ctype = UPB_CTYPE_UINT64; -#endif - - map_index_set(intern, keyval, length, v); -} -static bool map_field_unset_dimension(zval *object, zval *key TSRMLS_DC) { - Map *intern = UNBOX(Map, object); + upb_map_set(map, upb_key, upb_val, arena); + zend_hash_move_forward_ex(table, &pos); + zval_dtor(&php_key); + } + } else if (Z_TYPE_P(val) == IS_OBJECT && + Z_OBJCE_P(val) == MapField_class_entry) { + MapField *intern = (MapField*)Z_OBJ_P(val); + + if (intern->key_type != key_type || intern->val_type != val_type || + intern->desc != desc) { + php_error_docref(NULL, E_USER_ERROR, "Wrong type for this map field."); + return NULL; + } - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) { - return false; + upb_arena_fuse(arena, Arena_Get(&intern->arena)); + return intern->map; + } else { + php_error_docref(NULL, E_USER_ERROR, "Must be a map"); + return NULL; } -#ifndef NDEBUG - v.ctype = UPB_CTYPE_UINT64; -#endif - - map_index_unset(intern, keyval, length); - - return true; } -// ----------------------------------------------------------------------------- -// PHP MapField Methods -// ----------------------------------------------------------------------------- +// MapField PHP methods //////////////////////////////////////////////////////// +/** + * MapField::__construct() + * + * Constructs an instance of MapField. + * @param long Key type. + * @param long Value type. + * @param string Message/Enum class (message/enum value types only). + */ PHP_METHOD(MapField, __construct) { - long key_type, value_type; + MapField *intern = (MapField*)Z_OBJ_P(getThis()); + upb_arena *arena = Arena_Get(&intern->arena); + zend_long key_type, val_type; zend_class_entry* klass = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|C", &key_type, - &value_type, &klass) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|C", &key_type, &val_type, + &klass) != SUCCESS) { return; } - Map *intern = UNBOX(Map, getThis()); - intern->key_type = to_fieldtype(key_type); - intern->value_type = to_fieldtype(value_type); - intern->msg_ce = klass; + intern->key_type = pbphp_dtype_to_type(key_type); + intern->val_type = pbphp_dtype_to_type(val_type); + intern->desc = Descriptor_GetFromClassEntry(klass); // Check that the key type is an allowed type. switch (intern->key_type) { @@ -427,107 +224,319 @@ PHP_METHOD(MapField, __construct) { default: zend_error(E_USER_ERROR, "Invalid key type for map."); } -} + if (intern->val_type == UPB_TYPE_MESSAGE && klass == NULL) { + php_error_docref(NULL, E_USER_ERROR, + "Message/enum type must have concrete class."); + return; + } + + intern->map = upb_map_new(arena, intern->key_type, intern->val_type); + ObjCache_Add(intern->map, &intern->std); +} + +/** + * MapField::offsetExists() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * isset($map[$idx]); + * empty($map[$idx]); + * + * @param long The index to be checked. + * @return bool True if the element at the given index exists. + */ PHP_METHOD(MapField, offsetExists) { + MapField *intern = (MapField*)Z_OBJ_P(getThis()); zval *key; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == - FAILURE) { + upb_msgval upb_key; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS || + !Convert_PhpToUpb(key, &upb_key, intern->key_type, intern->desc, NULL)) { return; } - Map *intern = UNBOX(Map, getThis()); - - char keybuf[TABLE_KEY_BUF_LENGTH]; - const char* keyval = NULL; - size_t length = 0; - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_UINT64; -#endif - if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) { - RETURN_BOOL(false); - } + RETURN_BOOL(upb_map_get(intern->map, upb_key, NULL)); +} + +/** + * MapField::offsetGet() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * $x = $map[$idx]; + * + * @param long The index of the element to be fetched. + * @return object The stored element at given index. + * @exception Invalid type for index. + * @exception Non-existing index. + */ +PHP_METHOD(MapField, offsetGet) { + MapField *intern = (MapField*)Z_OBJ_P(getThis()); + zval *key; + zval ret; + upb_msgval upb_key, upb_val; - RETURN_BOOL(upb_strtable_lookup2(&intern->table, keyval, length, &v)); -} + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS || + !Convert_PhpToUpb(key, &upb_key, intern->key_type, intern->desc, NULL)) { + return; + } -PHP_METHOD(MapField, offsetGet) { - zval *index; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == - FAILURE) { + if (!upb_map_get(intern->map, upb_key, &upb_val)) { + zend_error(E_USER_ERROR, "Given key doesn't exist."); return; } - map_field_read_dimension(getThis(), index, BP_VAR_R, - ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC); -} + Convert_UpbToPhp(upb_val, &ret, intern->val_type, intern->desc, &intern->arena); + RETURN_ZVAL(&ret, 0, 1); +} + +/** + * MapField::offsetSet() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * $map[$idx] = $x; + * + * @param long The index of the element to be assigned. + * @param object The element to be assigned. + * @exception Invalid type for index. + * @exception Non-existing index. + * @exception Incorrect type of the element. + */ PHP_METHOD(MapField, offsetSet) { - zval *index, *value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == - FAILURE) { + MapField *intern = (MapField*)Z_OBJ_P(getThis()); + upb_arena *arena = Arena_Get(&intern->arena); + zval *key, *val; + upb_msgval upb_key, upb_val; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &key, &val) != SUCCESS || + !Convert_PhpToUpb(key, &upb_key, intern->key_type, NULL, NULL) || + !Convert_PhpToUpb(val, &upb_val, intern->val_type, intern->desc, arena)) { return; } - map_field_write_dimension(getThis(), index, value TSRMLS_CC); + + upb_map_set(intern->map, upb_key, upb_val, arena); } +/** + * MapField::offsetUnset() + * + * Implements the ArrayAccess interface. Invoked when PHP code calls: + * + * unset($map[$idx]); + * + * @param long The index of the element to be removed. + * @exception Invalid type for index. + * @exception The element to be removed is not at the end of the MapField. + */ PHP_METHOD(MapField, offsetUnset) { - zval *index; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == - FAILURE) { + MapField *intern = (MapField*)Z_OBJ_P(getThis()); + zval *key; + upb_msgval upb_key; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS || + !Convert_PhpToUpb(key, &upb_key, intern->key_type, NULL, NULL)) { return; } - map_field_unset_dimension(getThis(), index TSRMLS_CC); + + upb_map_delete(intern->map, upb_key); } +/** + * MapField::count() + * + * Implements the Countable interface. Invoked when PHP code calls: + * + * $len = count($map); + * Return the number of stored elements. + * This will also be called for: count($map) + * @return long The number of stored elements. + */ PHP_METHOD(MapField, count) { - Map *intern = UNBOX(Map, getThis()); + MapField *intern = (MapField*)Z_OBJ_P(getThis()); if (zend_parse_parameters_none() == FAILURE) { return; } - RETURN_LONG(upb_strtable_count(&intern->table)); + RETURN_LONG(upb_map_size(intern->map)); } +/** + * MapField::getIterator() + * + * Implements the IteratorAggregate interface. Invoked when PHP code calls: + * + * foreach ($arr) {} + * + * @return object Beginning iterator. + */ PHP_METHOD(MapField, getIterator) { - CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(return_value, - map_field_iter_type); - - MapIter *iter = UNBOX(MapIter, return_value); - map_begin(getThis(), iter TSRMLS_CC); + zval ret; + MapFieldIter_make(&ret, getThis()); + RETURN_ZVAL(&ret, 0, 1); } +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) + ZEND_ARG_INFO(0, index) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, newval) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_void, 0) +ZEND_END_ARG_INFO() + +static zend_function_entry MapField_methods[] = { + PHP_ME(MapField, __construct, NULL, ZEND_ACC_PUBLIC) + PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(MapField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(MapField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) + PHP_ME(MapField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) + PHP_ME(MapField, count, arginfo_void, ZEND_ACC_PUBLIC) + PHP_ME(MapField, getIterator, arginfo_void, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + // ----------------------------------------------------------------------------- -// Map Iterator +// MapFieldIter // ----------------------------------------------------------------------------- -void map_begin(zval *map_php, MapIter *iter TSRMLS_DC) { - Map *self = UNBOX(Map, map_php); - map_begin_internal(self, iter); +typedef struct { + zend_object std; + zval map_field; + size_t position; +} MapFieldIter; + +zend_class_entry *MapFieldIter_class_entry; +static zend_object_handlers MapFieldIter_object_handlers; + +/** + * MapFieldIter_create() + * + * PHP class entry function to allocate and initialize a new MapFieldIter + * object. + */ +zend_object* MapFieldIter_create(zend_class_entry *class_type) { + MapFieldIter *intern = emalloc(sizeof(MapFieldIter)); + zend_object_std_init(&intern->std, class_type); + intern->std.handlers = &MapFieldIter_object_handlers; + ZVAL_NULL(&intern->map_field); + intern->position = 0; + // Skip object_properties_init(), we don't allow derived classes. + return &intern->std; +} + +/** + * MapFieldIter_dtor() + * + * Object handler to destroy a MapFieldIter. This releases all resources + * associated with the message. Note that it is possible to access a destroyed + * object from PHP in rare cases. + */ +static void map_field_iter_dtor(zend_object* obj) { + MapFieldIter* intern = (MapFieldIter*)obj; + zval_ptr_dtor(&intern->map_field); + zend_object_std_dtor(&intern->std); +} + +/** + * MapFieldIter_make() + * + * Function to create a MapFieldIter directly from C. + */ +static void MapFieldIter_make(zval *val, zval *map_field) { + MapFieldIter *iter; + ZVAL_OBJ(val, + MapFieldIter_class_entry->create_object(MapFieldIter_class_entry)); + iter = (MapFieldIter*)Z_OBJ_P(val); + ZVAL_COPY(&iter->map_field, map_field); } -void map_next(MapIter *iter) { - upb_strtable_next(&iter->it); -} +// ----------------------------------------------------------------------------- +// PHP MapFieldIter Methods +// ----------------------------------------------------------------------------- -bool map_done(MapIter *iter) { - return upb_strtable_done(&iter->it); +/* + * When a user writes: + * + * foreach($arr as $key => $val) {} + * + * PHP translates this into: + * + * $iter = $arr->getIterator(); + * for ($iter->rewind(); $iter->valid(); $iter->next()) { + * $key = $iter->key(); + * $val = $iter->current(); + * } + */ + +/** + * MapFieldIter::rewind() + * + * Implements the Iterator interface. Sets the iterator to the first element. + */ +PHP_METHOD(MapFieldIter, rewind) { + MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); + MapField *map_field = (MapField*)Z_OBJ_P(&intern->map_field); + intern->position = UPB_MAP_BEGIN; + upb_mapiter_next(map_field->map, &intern->position); } -const char *map_iter_key(MapIter *iter, int *len) { - *len = upb_strtable_iter_key(&iter->it).size; - return upb_strtable_iter_key(&iter->it).data; +/** + * MapFieldIter::current() + * + * Implements the Iterator interface. Returns the current value. + */ +PHP_METHOD(MapFieldIter, current) { + MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); + MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); + upb_msgval upb_val = upb_mapiter_value(field->map, intern->position); + zval ret; + Convert_UpbToPhp(upb_val, &ret, field->val_type, field->desc, &field->arena); + RETURN_ZVAL(&ret, 0, 1); +} + +/** + * MapFieldIter::key() + * + * Implements the Iterator interface. Returns the current key. + */ +PHP_METHOD(MapFieldIter, key) { + MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); + MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); + upb_msgval upb_key = upb_mapiter_key(field->map, intern->position); + zval ret; + Convert_UpbToPhp(upb_key, &ret, field->key_type, NULL, NULL); + RETURN_ZVAL(&ret, 0, 1); +} + +/** + * MapFieldIter::next() + * + * Implements the Iterator interface. Advances to the next element. + */ +PHP_METHOD(MapFieldIter, next) { + MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); + MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); + upb_mapiter_next(field->map, &intern->position); } -upb_value map_iter_value(MapIter *iter, int *len) { - *len = native_slot_size(iter->self->value_type); - return upb_strtable_iter_value(&iter->it); +/** + * MapFieldIter::valid() + * + * Implements the Iterator interface. Returns true if this is a valid element. + */ +PHP_METHOD(MapFieldIter, valid) { + MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); + MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); + bool done = upb_mapiter_done(field->map, intern->position); + RETURN_BOOL(!done); } -// ----------------------------------------------------------------------------- -// MapFieldIter methods -// ----------------------------------------------------------------------------- static zend_function_entry map_field_iter_methods[] = { PHP_ME(MapFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC) PHP_ME(MapFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC) @@ -538,65 +547,44 @@ static zend_function_entry map_field_iter_methods[] = { }; // ----------------------------------------------------------------------------- -// MapFieldIter creation/destruction +// Module init. // ----------------------------------------------------------------------------- -// Define object free method. -PHP_PROTO_OBJECT_EMPTY_FREE_START(MapIter, map_field_iter) -PHP_PROTO_OBJECT_FREE_END - -PHP_PROTO_OBJECT_EMPTY_DTOR_START(MapIter, map_field_iter) -PHP_PROTO_OBJECT_DTOR_END - -// Define object create method. -PHP_PROTO_OBJECT_CREATE_START(MapIter, map_field_iter) -intern->self = NULL; -PHP_PROTO_OBJECT_CREATE_END(MapIter, map_field_iter) - -// Init class entry. -PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\MapFieldIter", - MapIter, map_field_iter) -zend_class_implements(map_field_iter_type TSRMLS_CC, 1, zend_ce_iterator); -PHP_PROTO_INIT_CLASS_END - -// ----------------------------------------------------------------------------- -// PHP MapFieldIter Methods -// ----------------------------------------------------------------------------- - -PHP_METHOD(MapFieldIter, rewind) { - MapIter *intern = UNBOX(MapIter, getThis()); - map_begin_internal(intern->self, intern); -} - -PHP_METHOD(MapFieldIter, current) { - MapIter *intern = UNBOX(MapIter, getThis()); - Map *map_field = intern->self; - - int value_length = 0; - upb_value value = map_iter_value(intern, &value_length); - - void* mem = upb_value_memory(&value); - native_slot_get_by_map_value(map_field->value_type, mem, - ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC); -} - -PHP_METHOD(MapFieldIter, key) { - MapIter *intern = UNBOX(MapIter, getThis()); - Map *map_field = intern->self; - - int key_length = 0; - const char* key = map_iter_key(intern, &key_length); - - native_slot_get_by_map_key(map_field->key_type, key, key_length, - ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC); -} - -PHP_METHOD(MapFieldIter, next) { - MapIter *intern = UNBOX(MapIter, getThis()); - map_next(intern); -} - -PHP_METHOD(MapFieldIter, valid) { - MapIter *intern = UNBOX(MapIter, getThis()); - RETURN_BOOL(!map_done(intern)); +/** + * Map_ModuleInit() + * + * Called when the C extension is loaded to register all types. + */ + +void Map_ModuleInit() { + zend_class_entry tmp_ce; + zend_object_handlers *h; + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\MapField", + MapField_methods); + + MapField_class_entry = zend_register_internal_class(&tmp_ce); + zend_class_implements(MapField_class_entry, 3, spl_ce_ArrayAccess, + zend_ce_aggregate, spl_ce_Countable); + MapField_class_entry->ce_flags |= ZEND_ACC_FINAL; + MapField_class_entry->create_object = MapField_create; + + h = &MapField_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = MapField_destructor; + h->get_properties = map_get_properties; + h->get_property_ptr_ptr = Map_GetPropertyPtrPtr; + + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\MapFieldIter", + map_field_iter_methods); + + MapFieldIter_class_entry = zend_register_internal_class(&tmp_ce); + zend_class_implements(MapFieldIter_class_entry, 1, zend_ce_iterator); + MapFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL; + MapFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL; + MapFieldIter_class_entry->create_object = MapFieldIter_create; + + h = &MapFieldIter_object_handlers; + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = map_field_iter_dtor; } diff --git a/php/ext/google/protobuf2/map.h b/php/ext/google/protobuf/map.h similarity index 100% rename from php/ext/google/protobuf2/map.h rename to php/ext/google/protobuf/map.h diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index 036633781db2..20dd37a76e05 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -28,2707 +28,814 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#include "message.h" + +#include #include -#include #include -#include -#if PHP_MAJOR_VERSION < 7 -#include -#else -#include -#endif +// This is not self-contained: it must be after other Zend includes. +#include +#include "arena.h" +#include "array.h" +#include "convert.h" +#include "def.h" +#include "map.h" +#include "php-upb.h" #include "protobuf.h" -#include "utf8.h" - -zend_class_entry* message_type; -zend_object_handlers* message_handlers; -static const char TYPE_URL_PREFIX[] = "type.googleapis.com/"; -static void hex_to_binary(const char* hex, char** binary, int* binary_len); - -static zend_function_entry message_methods[] = { - PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, discardUnknownFields, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, serializeToString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, mergeFromString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, serializeToJsonString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, mergeFromJsonString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, mergeFrom, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, readWrapperValue, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, writeWrapperValue, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, __construct, NULL, ZEND_ACC_PROTECTED) - {NULL, NULL, NULL} -}; - -// Forward declare static functions. - -#if PHP_MAJOR_VERSION < 7 -static void message_set_property(zval* object, zval* member, zval* value, - php_proto_zend_literal key TSRMLS_DC); -static zval* message_get_property(zval* object, zval* member, int type, - const zend_literal* key TSRMLS_DC); -static zval** message_get_property_ptr_ptr(zval* object, zval* member, int type, - php_proto_zend_literal key TSRMLS_DC); -static HashTable* message_get_gc(zval* object, zval*** table, int* n TSRMLS_DC); -#else -#if PHP_VERSION_ID < 70400 -static void message_set_property(zval* object, zval* member, zval* value, - void** cache_slot); -#else -static zval* message_set_property(zval* object, zval* member, zval* value, - void** cache_slot); -#endif -static zval* message_get_property(zval* object, zval* member, int type, - void** cache_slot, zval* rv); -static zval* message_get_property_ptr_ptr(zval* object, zval* member, int type, - void** cache_slot); -static HashTable* message_get_gc(zval* object, zval** table, int* n); -#endif -static HashTable* message_get_properties(zval* object TSRMLS_DC); // ----------------------------------------------------------------------------- -// PHP Message Handlers -// ----------------------------------------------------------------------------- - -// Define object free method. -PHP_PROTO_OBJECT_FREE_START(MessageHeader, message) - if (intern->data) { - if (*(void**)intern->data != NULL) { - stringsink_uninit_opaque(*(void**)intern->data); - FREE(*(void**)intern->data); - } - FREE(intern->data); - } -PHP_PROTO_OBJECT_FREE_END - -PHP_PROTO_OBJECT_EMPTY_DTOR_START(MessageHeader, message) -PHP_PROTO_OBJECT_DTOR_END - -// Define object create method. -PHP_PROTO_OBJECT_CREATE_START(MessageHeader, message) -// Because php call this create func before calling the sub-message's -// constructor defined in PHP, it's possible that the descriptor of this class -// hasn't been added to descriptor pool (when the class is first -// instantiated). In that case, we will defer the initialization of the custom -// data to the parent Message's constructor, which will be called by -// sub-message's constructors after the descriptor has been added. -PHP_PROTO_OBJECT_CREATE_END(MessageHeader, message) - -// Init class entry. -PHP_PROTO_INIT_CLASS_START("Google\\Protobuf\\Internal\\Message", - MessageHeader, message) - message_handlers->write_property = message_set_property; - message_handlers->read_property = message_get_property; - message_handlers->get_property_ptr_ptr = message_get_property_ptr_ptr; - message_handlers->get_properties = message_get_properties; - message_handlers->get_gc = message_get_gc; -PHP_PROTO_INIT_CLASS_END - -static void message_set_property_internal(zval* object, zval* member, - zval* value TSRMLS_DC) { - const upb_fielddef* field; - - MessageHeader* self = UNBOX(MessageHeader, object); - - field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member)); - if (field == NULL) { - zend_error(E_USER_ERROR, "Unknown field: %s", Z_STRVAL_P(member)); +// Message +// ----------------------------------------------------------------------------- + +typedef struct { + zend_object std; + zval arena; + const Descriptor* desc; + upb_msg *msg; +} Message; + +zend_class_entry *message_ce; +static zend_object_handlers message_object_handlers; + +// PHP Object Handlers ///////////////////////////////////////////////////////// + +/** + * Message_create() + * + * PHP class entry function to allocate and initialize a new Message object. + */ +static zend_object* Message_create(zend_class_entry *class_type) { + Message *intern = emalloc(sizeof(Message)); + // XXX(haberman): verify whether we actually want to take this route. + class_type->default_properties_count = 0; + zend_object_std_init(&intern->std, class_type); + intern->std.handlers = &message_object_handlers; + Arena_Init(&intern->arena); + return &intern->std; +} + +/** + * Message_dtor() + * + * Object handler to destroy a Message. This releases all resources associated + * with the message. Note that it is possible to access a destroyed object from + * PHP in rare cases. + */ +static void Message_dtor(zend_object* obj) { + Message* intern = (Message*)obj; + ObjCache_Delete(intern->msg); + zval_dtor(&intern->arena); + zend_object_std_dtor(&intern->std); +} + +/** + * get_field() + * + * Helper function to look up a field given a member name (as a string). + */ +static const upb_fielddef *get_field(Message *msg, zval *member) { + const upb_msgdef *m = msg->desc->msgdef; + const upb_fielddef *f = + upb_msgdef_ntof(m, Z_STRVAL_P(member), Z_STRLEN_P(member)); + + if (!f) { + zend_throw_exception_ex(NULL, 0, "No such property %s.", + ZSTR_VAL(msg->desc->class_entry->name)); + } + + return f; +} + +/** + * Message_read_property() + * + * Object handler for reading a property in PHP. Called when PHP code does: + * + * $x = $message->foobar; + * + * Note that all properties of generated messages are private, so this should + * only be possible to invoke from generated code, which has accessors like: + * + * public function getOptionalInt32() + * { + * return $this->optional_int32; + * } + * + * We lookup the field and return the scalar, RepeatedField, or MapField for + * this field. + */ +static zval *Message_read_property(zval *obj, zval *member, int type, + void **cache_slot, zval *rv) { + Message* intern = (Message*)Z_OBJ_P(obj); + const upb_fielddef *f = get_field(intern, member); + upb_arena *arena = Arena_Get(&intern->arena); + + if (!f) return NULL; + + if (upb_fielddef_ismap(f)) { + upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena); + MapField_GetPhpWrapper(rv, msgval.map, f, &intern->arena); + } else if (upb_fielddef_isseq(f)) { + upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena); + RepeatedField_GetPhpWrapper(rv, msgval.array, f, &intern->arena); + } else { + upb_msgval msgval = upb_msg_get(intern->msg, f); + const Descriptor *subdesc = Descriptor_GetFromFieldDef(f); + Convert_UpbToPhp(msgval, rv, upb_fielddef_type(f), subdesc, &intern->arena); + } + + return rv; +} + +/** + * Message_write_property() + * + * Object handler for writing a property in PHP. Called when PHP code does: + * + * $message->foobar = $x; + * + * Note that all properties of generated messages are private, so this should + * only be possible to invoke from generated code, which has accessors like: + * + * public function setOptionalInt32($var) + * { + * GPBUtil::checkInt32($var); + * $this->optional_int32 = $var; + * + * return $this; + * } + * + * The C extension version of checkInt32() doesn't actually check anything, so + * we perform all checking and conversion in this function. + */ +static void Message_write_property(zval *obj, zval *member, zval *val, + void **cache_slot) { + Message* intern = (Message*)Z_OBJ_P(obj); + const upb_fielddef *f = get_field(intern, member); + upb_arena *arena = Arena_Get(&intern->arena); + upb_msgval msgval; + + if (!f) return; + + if (upb_fielddef_ismap(f)) { + msgval.map_val = MapField_GetUpbMap(val, f, arena); + if (!msgval.map_val) return; + } else if (upb_fielddef_isseq(f)) { + msgval.array_val = RepeatedField_GetUpbArray(val, f, arena); + if (!msgval.array_val) return; + } else { + upb_fieldtype_t type = upb_fielddef_type(f); + const Descriptor *subdesc = Descriptor_GetFromFieldDef(f); + bool ok = Convert_PhpToUpb(val, &msgval, type, subdesc, arena); + if (!ok) return; } - layout_set(self->descriptor->layout, self, field, value TSRMLS_CC); + upb_msg_set(intern->msg, f, msgval, arena); } -#if PHP_MAJOR_VERSION < 7 -static void message_set_property(zval* object, zval* member, zval* value, - php_proto_zend_literal key TSRMLS_DC) { -#elif PHP_VERSION_ID < 70400 -static void message_set_property(zval* object, zval* member, zval* value, - void** cache_slot) { -#else -static zval* message_set_property(zval* object, zval* member, zval* value, - void** cache_slot) { -#endif - if (Z_TYPE_P(member) != IS_STRING) { - zend_error(E_USER_ERROR, "Unexpected type for field name"); -#if PHP_VERSION_ID < 70400 - return; -#else - return value; -#endif - } - -#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - if (Z_OBJCE_P(object) != EG(scope)) { -#else - if (Z_OBJCE_P(object) != zend_get_executed_scope()) { -#endif - // User cannot set property directly (e.g., $m->a = 1) - zend_error(E_USER_ERROR, "Cannot access private property."); -#if PHP_VERSION_ID < 70400 - return; -#else - return value; -#endif - } +/** + * Message_get_property_ptr_ptr() + * + * Object handler for the get_property_ptr_ptr event in PHP. This returns a + * reference to our internal properties. We don't support this, so we return + * NULL. + */ +static zval *Message_get_property_ptr_ptr(zval *object, zval *member, int type, + void **cache_slot) { + return NULL; // We do not have a properties table. +} - message_set_property_internal(object, member, value TSRMLS_CC); -#if PHP_VERSION_ID >= 70400 - return value; -#endif +/** + * Message_get_properties() + * + * Object handler for the get_properties event in PHP. This returns a HashTable + * of our internal properties. We don't support this, so we return NULL. + */ +static HashTable* Message_get_properties(zval* object TSRMLS_DC) { + return NULL; // We don't offer direct references to our properties. } -static zval* message_get_property_internal(zval* object, - zval* member TSRMLS_DC) { - MessageHeader* self = UNBOX(MessageHeader, object); - const upb_fielddef* field; - field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member)); - if (field == NULL) { - return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL; - } +// C Functions from message.h. ///////////////////////////////////////////////// - zend_property_info* property_info; -#if PHP_MAJOR_VERSION < 7 - property_info = - zend_get_property_info(Z_OBJCE_P(object), member, true TSRMLS_CC); -#else - property_info = - zend_get_property_info(Z_OBJCE_P(object), Z_STR_P(member), true); -#endif - return layout_get( - self->descriptor->layout, self, field, - OBJ_PROP(Z_OBJ_P(object), property_info->offset) TSRMLS_CC); -} +// These are documented in the header file. -static void message_get_oneof_property_internal(zval* object, zval* member, - zval* return_value TSRMLS_DC) { - MessageHeader* self = UNBOX(MessageHeader, object); - const upb_fielddef* field; - field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member)); - if (field == NULL) { +void Message_GetPhpWrapper(zval *val, const Descriptor *desc, upb_msg *msg, + zval *arena) { + if (!msg) { + ZVAL_NULL(val); return; } - layout_get(self->descriptor->layout, self, field, - ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC); + if (!ObjCache_Get(msg, val)) { + Message *intern = emalloc(sizeof(Message)); + // XXX(haberman): verify whether we actually want to take this route. + desc->class_entry->default_properties_count = 0; + zend_object_std_init(&intern->std, desc->class_entry); + intern->std.handlers = &message_object_handlers; + ZVAL_COPY(&intern->arena, arena); + intern->desc = desc; + intern->msg = msg; + ZVAL_OBJ(val, &intern->std); + ObjCache_Add(intern->msg, &intern->std); + } } -#if PHP_MAJOR_VERSION < 7 -static zval* message_get_property(zval* object, zval* member, int type, - const zend_literal* key TSRMLS_DC) { -#else -static zval* message_get_property(zval* object, zval* member, int type, - void** cache_slot, zval* rv) { -#endif - if (Z_TYPE_P(member) != IS_STRING) { - zend_error(E_USER_ERROR, "Property name has to be a string."); - return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL; - } +bool Message_GetUpbMessage(zval *val, const Descriptor *desc, upb_arena *arena, + upb_msg **msg) { + PBPHP_ASSERT(desc); -#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - if (Z_OBJCE_P(object) != EG(scope)) { -#else - if (Z_OBJCE_P(object) != zend_get_executed_scope()) { -#endif - // User cannot get property directly (e.g., $a = $m->a) - zend_error(E_USER_ERROR, "Cannot access private property."); - return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL; + if (Z_ISREF_P(val)) { + ZVAL_DEREF(val); } - return message_get_property_internal(object, member TSRMLS_CC); -} - -#if PHP_MAJOR_VERSION < 7 -static zval** message_get_property_ptr_ptr(zval* object, zval* member, int type, - php_proto_zend_literal key - TSRMLS_DC) { -#else -static zval* message_get_property_ptr_ptr(zval* object, zval* member, int type, - void** cache_slot) { -#endif - return NULL; -} - -static HashTable* message_get_properties(zval* object TSRMLS_DC) { - return NULL; -} + if (Z_TYPE_P(val) == IS_NULL) { + *msg = NULL; + return true; + } -static HashTable* message_get_gc(zval* object, CACHED_VALUE** table, - int* n TSRMLS_DC) { - zend_object* zobj = Z_OBJ_P(object); - *table = zobj->properties_table; - *n = zobj->ce->default_properties_count; - return NULL; -} + if (Z_TYPE_P(val) == IS_OBJECT && + instanceof_function(Z_OBJCE_P(val), desc->class_entry)) { + Message *intern = (Message*)Z_OBJ_P(val); + upb_arena_fuse(arena, Arena_Get(&intern->arena)); + *msg = intern->msg; + return true; + } else { + zend_throw_exception_ex(NULL, 0, "Given value is not an instance of %s.", + ZSTR_VAL(desc->class_entry->name)); + return false; + } +} + +// Message PHP methods ///////////////////////////////////////////////////////// + +/** + * Message_InitFromPhp() + * + * Helper method to handle the initialization of a message from a PHP value, eg. + * + * $m = new TestMessage([ + * 'optional_int32' => -42, + * 'optional_bool' => true, + * 'optional_string' => 'a', + * 'optional_enum' => TestEnum::ONE, + * 'optional_message' => new Sub([ + * 'a' => 33 + * ]), + * 'repeated_int32' => [-42, -52], + * 'repeated_enum' => [TestEnum::ZERO, TestEnum::ONE], + * 'repeated_message' => [new Sub(['a' => 34]), + * new Sub(['a' => 35])], + * 'map_int32_int32' => [-62 => -62], + * 'map_int32_enum' => [1 => TestEnum::ONE], + * 'map_int32_message' => [1 => new Sub(['a' => 36])], + * ]); + * + * The initializer must be an array. + */ +bool Message_InitFromPhp(upb_msg *msg, const upb_msgdef *m, zval *init, + upb_arena *arena) { + HashTable* table = HASH_OF(init); + HashPosition pos; + + if (Z_ISREF_P(init)) { + ZVAL_DEREF(init); + } + + if (Z_TYPE_P(init) != IS_ARRAY) { + zend_throw_exception_ex(NULL, 0, + "Initializer for a message %s must be an array.", + upb_msgdef_fullname(m)); + return false; + } + + zend_hash_internal_pointer_reset_ex(table, &pos); + + while (true) { // Iterate over key/value pairs. + zval key; + zval *val; + const upb_fielddef *f; + upb_msgval msgval; + + zend_hash_get_current_key_zval_ex(table, &key, &pos); + val = zend_hash_get_current_data_ex(table, &pos); + + if (!val) return true; // Finished iteration. + + if (Z_ISREF_P(val)) { + ZVAL_DEREF(val); + } -// ----------------------------------------------------------------------------- -// C Message Utilities -// ----------------------------------------------------------------------------- + f = upb_msgdef_ntof(m, Z_STRVAL_P(&key), Z_STRLEN_P(&key)); -void* message_data(MessageHeader* msg) { - return msg->data; -} + if (!f) { + zend_throw_exception_ex(NULL, 0, + "No such field %s", Z_STRVAL_P(&key)); + return false; + } -void custom_data_init(const zend_class_entry* ce, - MessageHeader* intern PHP_PROTO_TSRMLS_DC) { - DescriptorInternal* desc = get_ce_desc(ce); - intern->data = ALLOC_N(uint8_t, desc->layout->size); - // We wrap first so that everything in the message object is GC-rooted in - // case a collection happens during object creation in layout_init(). - intern->descriptor = desc; - layout_init(desc->layout, message_data(intern), - &intern->std PHP_PROTO_TSRMLS_CC); -} + if (upb_fielddef_ismap(f)) { + msgval.map_val = MapField_GetUpbMap(val, f, arena); + if (!msgval.map_val) return false; + } else if (upb_fielddef_isseq(f)) { + msgval.array_val = RepeatedField_GetUpbArray(val, f, arena); + if (!msgval.array_val) return false; + } else { + const Descriptor *desc = Descriptor_GetFromFieldDef(f); + upb_fieldtype_t type = upb_fielddef_type(f); + if (!Convert_PhpToUpbAutoWrap(val, &msgval, type, desc, arena)) { + return false; + } + } -#define INIT_MESSAGE_WITH_ARRAY \ - { \ - zval* array_wrapper = NULL; \ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, \ - "|a!", &array_wrapper) == FAILURE) { \ - return; \ - } \ - Message_construct(getThis(), array_wrapper); \ + upb_msg_set(msg, f, msgval, arena); + zend_hash_move_forward_ex(table, &pos); + zval_dtor(&key); } - -// ----------------------------------------------------------------------------- -// PHP Methods -// ----------------------------------------------------------------------------- - -static void append_wrapper_message( - zend_class_entry* subklass, RepeatedField* intern, zval* value TSRMLS_DC) { - MessageHeader* submsg; - const upb_fielddef* field; -#if PHP_MAJOR_VERSION < 7 - zval* val = NULL; - MAKE_STD_ZVAL(val); - ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC)); - repeated_field_push_native(intern, &val); - submsg = UNBOX(MessageHeader, val); -#else - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - repeated_field_push_native(intern, &obj); - submsg = (MessageHeader*)((char*)obj - XtOffsetOf(MessageHeader, std)); -#endif - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); - - field = upb_msgdef_itof(submsg->descriptor->msgdef, 1); - layout_set(submsg->descriptor->layout, submsg, field, value TSRMLS_CC); -} - -static void set_wrapper_message_as_map_value( - zend_class_entry* subklass, zval* map, zval* key, zval* value TSRMLS_DC) { - MessageHeader* submsg; - const upb_fielddef* field; -#if PHP_MAJOR_VERSION < 7 - zval* val = NULL; - MAKE_STD_ZVAL(val); - ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC)); - map_field_handlers->write_dimension( - map, key, val TSRMLS_CC); - submsg = UNBOX(MessageHeader, val); -#else - zval val; - zend_object* obj = subklass->create_object(subklass TSRMLS_CC); - ZVAL_OBJ(&val, obj); - map_field_handlers->write_dimension(map, key, &val TSRMLS_CC); - submsg = (MessageHeader*)((char*)obj - XtOffsetOf(MessageHeader, std)); -#endif - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); - - field = upb_msgdef_itof(submsg->descriptor->msgdef, 1); - layout_set(submsg->descriptor->layout, submsg, field, value TSRMLS_CC); } -void Message_construct(zval* msg, zval* array_wrapper) { - TSRMLS_FETCH(); - zend_class_entry* ce = Z_OBJCE_P(msg); - MessageHeader* intern = NULL; - - if (!class_added(ce)) { -#if PHP_MAJOR_VERSION < 7 - DescriptorInternal* desc = get_class_desc(ce->name); -#else - DescriptorInternal* desc = get_class_desc(ZSTR_VAL(ce->name)); -#endif - register_class(desc, false TSRMLS_CC); - } +/** + * Message::__construct() + * + * Constructor for Message. + * @param array Map of initial values ['k' = val] + */ +PHP_METHOD(Message, __construct) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + const Descriptor* desc = Descriptor_GetFromClassEntry(Z_OBJCE_P(getThis())); + const upb_msgdef *msgdef = desc->msgdef; + upb_arena *arena = Arena_Get(&intern->arena); + zval *init_arr = NULL; - intern = UNBOX(MessageHeader, msg); - custom_data_init(ce, intern PHP_PROTO_TSRMLS_CC); + intern->desc = desc; + intern->msg = upb_msg_new(msgdef, arena); + ObjCache_Add(intern->msg, &intern->std); - if (array_wrapper == NULL) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &init_arr) == FAILURE) { return; } - HashTable* array = Z_ARRVAL_P(array_wrapper); - HashPosition pointer; - zval key; - void* value; - const upb_fielddef* field; - - for (zend_hash_internal_pointer_reset_ex(array, &pointer); - php_proto_zend_hash_get_current_data_ex(array, (void**)&value, - &pointer) == SUCCESS; - zend_hash_move_forward_ex(array, &pointer)) { - zend_hash_get_current_key_zval_ex(array, &key, &pointer); - field = upb_msgdef_ntofz(intern->descriptor->msgdef, Z_STRVAL_P(&key)); -#if PHP_MAJOR_VERSION >= 7 - if (Z_ISREF_P((CACHED_VALUE*)value)) { - value = Z_REFVAL_P((CACHED_VALUE*)value); - } -#endif - if (field == NULL) { - zend_error(E_USER_ERROR, "Unknown field: %s", Z_STRVAL_P(&key)); - } - if (upb_fielddef_ismap(field)) { - PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg)); - zval* submap = message_get_property_internal(msg, &key TSRMLS_CC); - PHP_PROTO_FAKE_SCOPE_END; - HashTable* subtable = HASH_OF( - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value)); - HashPosition subpointer; - zval subkey; - void* memory; - bool is_wrapper = false; - zend_class_entry* subklass = NULL; - const upb_msgdef* mapentry = upb_fielddef_msgsubdef(field); - const upb_fielddef *value_field = upb_msgdef_itof(mapentry, 2); - - if (upb_fielddef_issubmsg(value_field)) { - const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(value_field); - is_wrapper = is_wrapper_msg(submsgdef); - - if (is_wrapper) { - DescriptorInternal* subdesc = get_msgdef_desc(submsgdef); - register_class(subdesc, false TSRMLS_CC); - subklass = subdesc->klass; - } - } - - for (zend_hash_internal_pointer_reset_ex(subtable, &subpointer); - php_proto_zend_hash_get_current_data_ex(subtable, (void**)&memory, - &subpointer) == SUCCESS; - zend_hash_move_forward_ex(subtable, &subpointer)) { - zend_hash_get_current_key_zval_ex(subtable, &subkey, &subpointer); - if (is_wrapper && - Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory)) != IS_OBJECT) { - set_wrapper_message_as_map_value( - subklass, submap, &subkey, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC); - } else { - map_field_handlers->write_dimension( - submap, &subkey, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC); - } - zval_dtor(&subkey); - } - } else if (upb_fielddef_isseq(field)) { - PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg)); - zval* subarray = message_get_property_internal(msg, &key TSRMLS_CC); - PHP_PROTO_FAKE_SCOPE_END; - HashTable* subtable = HASH_OF( - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value)); - HashPosition subpointer; - void* memory; - bool is_wrapper = false; - zend_class_entry* subklass = NULL; - - if (upb_fielddef_issubmsg(field)) { - const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); - is_wrapper = is_wrapper_msg(submsgdef); - - if (is_wrapper) { - DescriptorInternal* subdesc = get_msgdef_desc(submsgdef); - register_class(subdesc, false TSRMLS_CC); - subklass = subdesc->klass; - } - } - - for (zend_hash_internal_pointer_reset_ex(subtable, &subpointer); - php_proto_zend_hash_get_current_data_ex(subtable, (void**)&memory, - &subpointer) == SUCCESS; - zend_hash_move_forward_ex(subtable, &subpointer)) { - if (is_wrapper && - Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory)) != IS_OBJECT) { - RepeatedField* intern = UNBOX(RepeatedField, subarray); - append_wrapper_message( - subklass, intern, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC); - } else { - repeated_field_handlers->write_dimension( - subarray, NULL, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC); - } - } - } else if (upb_fielddef_issubmsg(field)) { - const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); - DescriptorInternal* desc = get_msgdef_desc(submsgdef); - register_class(desc, false TSRMLS_CC); - - CACHED_VALUE* cached = NULL; - if (upb_fielddef_containingoneof(field)) { - void* memory = slot_memory(intern->descriptor->layout, - message_data(intern), field); - uint32_t* oneof_case = slot_oneof_case(intern->descriptor->layout, - message_data(intern), field); - int property_cache_index = - intern->descriptor->layout->fields[upb_fielddef_index(field)] - .cache_index; - cached = OBJ_PROP(Z_OBJ_P(msg), property_cache_index); - *(CACHED_VALUE**)(memory) = cached; - *oneof_case = upb_fielddef_number(field); - } else { - zend_property_info* property_info; - PHP_PROTO_FAKE_SCOPE_BEGIN(Z_OBJCE_P(msg)); -#if PHP_MAJOR_VERSION < 7 - property_info = - zend_get_property_info(Z_OBJCE_P(msg), &key, true TSRMLS_CC); -#else - property_info = - zend_get_property_info(Z_OBJCE_P(msg), Z_STR_P(&key), true); -#endif - PHP_PROTO_FAKE_SCOPE_END; - cached = OBJ_PROP(Z_OBJ_P(msg), property_info->offset); - } -#if PHP_MAJOR_VERSION < 7 - SEPARATE_ZVAL_IF_NOT_REF(cached); -#endif - zval* submsg = CACHED_PTR_TO_ZVAL_PTR(cached); - ZVAL_OBJ(submsg, desc->klass->create_object(desc->klass TSRMLS_CC)); - Message_construct(submsg, NULL); - MessageHeader* to = UNBOX(MessageHeader, submsg); - const upb_filedef *file = upb_msgdef_file(submsgdef); - if (!strcmp(upb_filedef_name(file), "google/protobuf/wrappers.proto") && - Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value)) != IS_OBJECT) { - const upb_fielddef *value_field = upb_msgdef_itof(submsgdef, 1); - layout_set(to->descriptor->layout, to, - value_field, CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value) - TSRMLS_CC); - } else { - MessageHeader* from = - UNBOX(MessageHeader, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value)); - if(from->descriptor != to->descriptor) { - zend_error(E_USER_ERROR, - "Cannot merge messages with different class."); - return; - } - - layout_merge(from->descriptor->layout, from, to TSRMLS_CC); - } - } else { - message_set_property_internal(msg, &key, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value) TSRMLS_CC); - } - zval_dtor(&key); + if (init_arr) { + Message_InitFromPhp(intern->msg, desc->msgdef, init_arr, arena); } } -// At the first time the message is created, the class entry hasn't been -// modified. As a result, the first created instance will be a normal zend -// object. Here, we manually modify it to our message in such a case. -PHP_METHOD(Message, __construct) { - INIT_MESSAGE_WITH_ARRAY; +/** + * Message::discardUnknownFields() + * + * Discards any unknown fields for this message or any submessages. + */ +PHP_METHOD(Message, discardUnknownFields) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + upb_msg_discardunknown(intern->msg, intern->desc->msgdef, 64); } +/** + * Message::clear() + * + * Clears all fields of this message. + */ PHP_METHOD(Message, clear) { - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - DescriptorInternal* desc = msg->descriptor; - register_class(desc, false TSRMLS_CC); - zend_class_entry* ce = desc->klass; - - zend_object_std_dtor(&msg->std TSRMLS_CC); - object_properties_init(&msg->std, ce); - - layout_init(desc->layout, message_data(msg), &msg->std TSRMLS_CC); + Message* intern = (Message*)Z_OBJ_P(getThis()); + upb_msg_clear(intern->msg, intern->desc->msgdef); } +/** + * Message::mergeFrom() + * + * Merges from the given message, which must be of the same class as us. + * @param object Message to merge from. + */ PHP_METHOD(Message, mergeFrom) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + Message* from; + upb_arena *arena = Arena_Get(&intern->arena); + const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef); zval* value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &value, - message_type) == FAILURE) { + char *pb; + size_t size; + bool ok; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &value, + intern->desc->class_entry) == FAILURE) { return; } - MessageHeader* from = UNBOX(MessageHeader, value); - MessageHeader* to = UNBOX(MessageHeader, getThis()); + from = (Message*)Z_OBJ_P(value); - if(from->descriptor != to->descriptor) { - zend_error(E_USER_ERROR, "Cannot merge messages with different class."); - return; - } + // Should be guaranteed since we passed the class type to + // zend_parse_parameters(). + PBPHP_ASSERT(from->desc == intern->desc); - layout_merge(from->descriptor->layout, from, to TSRMLS_CC); -} + // TODO(haberman): use a temp arena for this once we can make upb_decode() + // copy strings. + pb = upb_encode(from->msg, l, arena, &size); -PHP_METHOD(Message, readWrapperValue) { - char* member; - PHP_PROTO_SIZE length; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &member, - &length) == FAILURE) { + if (!pb) { + zend_throw_exception_ex(NULL, 0, "Max nesting exceeded"); return; } - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - const upb_fielddef* field = - upb_msgdef_ntofz(msg->descriptor->msgdef, member); - - if (upb_fielddef_containingoneof(field)) { - uint32_t* oneof_case = - slot_oneof_case(msg->descriptor->layout, message_data(msg), field); - if (*oneof_case != upb_fielddef_number(field)) { - RETURN_NULL(); - } - } + ok = upb_decode(pb, size, intern->msg, l, arena); + PBPHP_ASSERT(ok); +} - zval* cached_zval = - CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, field)); +/** + * Message::mergeFromString() + * + * Merges from the given string. + * @param string Binary protobuf data to merge. + */ +PHP_METHOD(Message, mergeFromString) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + char *data = NULL; + char *data_copy = NULL; + zend_long data_len; + const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef); + upb_arena *arena = Arena_Get(&intern->arena); - if (Z_TYPE_P(cached_zval) == IS_NULL) { - RETURN_NULL(); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data, &data_len) == + FAILURE) { + return; } - if (Z_TYPE_P(cached_zval) == IS_OBJECT) { - const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); - const upb_fielddef* value_field = upb_msgdef_itof(submsgdef, 1); - MessageHeader* submsg = UNBOX(MessageHeader, cached_zval); - CACHED_VALUE* cached_value = find_zval_property(submsg, value_field); - layout_get(submsg->descriptor->layout, submsg, value_field, - cached_value TSRMLS_CC); - RETURN_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cached_value), 1, 0); - } else { - RETURN_ZVAL(cached_zval, 1, 0); - } -} + // TODO(haberman): avoid this copy when we can make the decoder copy. + data_copy = upb_arena_malloc(arena, data_len); + memcpy(data_copy, data, data_len); -PHP_METHOD(Message, writeWrapperValue) { - char* member; - PHP_PROTO_SIZE length; - zval* value; - if (zend_parse_parameters( - ZEND_NUM_ARGS() TSRMLS_CC, "sz", &member, &length, &value) == - FAILURE) { + if (!upb_decode(data_copy, data_len, intern->msg, l, arena)) { + zend_throw_exception_ex(NULL, 0, "Error occurred during parsing"); return; } +} - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - const upb_fielddef* field = upb_msgdef_ntofz(msg->descriptor->msgdef, member); +/** + * Message::serializeToString() + * + * Serializes this message instance to protobuf data. + * @return string Serialized protobuf data. + */ +PHP_METHOD(Message, serializeToString) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef); + upb_arena *tmp_arena = upb_arena_new(); + char *data; + size_t size; - zval* cached_zval = - CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, field)); + data = upb_encode(intern->msg, l, tmp_arena, &size); - if (Z_TYPE_P(value) == IS_NULL) { - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - layout_set(msg->descriptor->layout, msg, - field, value TSRMLS_CC); + if (!data) { + zend_throw_exception_ex(NULL, 0, "Error occurred during serialization"); + upb_arena_free(tmp_arena); return; } - { - // Type Checking - const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); - const upb_fielddef* value_field = upb_msgdef_itof(submsgdef, 1); - upb_fieldtype_t type = upb_fielddef_type(value_field); - switch(type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - if (!protobuf_convert_to_string(value)) { - return; - } - if (type == UPB_TYPE_STRING && - !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) { - zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); - return; - } - } - break; -#define CASE_TYPE(upb_type, type, c_type) \ - case UPB_TYPE_##upb_type: { \ - c_type type##_value; \ - if (!protobuf_convert_to_##type(value, &type##_value)) { \ - return; \ - } \ - break; \ - } - CASE_TYPE(INT32, int32, int32_t) - CASE_TYPE(UINT32, uint32, uint32_t) - CASE_TYPE(ENUM, int32, int32_t) - CASE_TYPE(INT64, int64, int64_t) - CASE_TYPE(UINT64, uint64, uint64_t) - CASE_TYPE(FLOAT, float, float) - CASE_TYPE(DOUBLE, double, double) - CASE_TYPE(BOOL, bool, int8_t) - -#undef CASE_TYPE - case UPB_TYPE_MESSAGE: - zend_error(E_ERROR, "No wrapper for message."); - break; - } + RETVAL_STRINGL(data, size); + upb_arena_free(tmp_arena); +} + +/** + * Message::mergeFromJsonString() + * + * Merges the JSON data parsed from the given string. + * @param string Serialized JSON data. + */ +PHP_METHOD(Message, mergeFromJsonString) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + char *data = NULL; + char *data_copy = NULL; + zend_long data_len; + upb_arena *arena = Arena_Get(&intern->arena); + upb_status status; + zend_bool ignore_json_unknown = false; + int options = 0; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len, + &ignore_json_unknown) == FAILURE) { + return; } - if (upb_fielddef_containingoneof(field)) { - uint32_t* oneof_case = - slot_oneof_case(msg->descriptor->layout, message_data(msg), field); - if (*oneof_case != upb_fielddef_number(field)) { - zval null_value; - ZVAL_NULL(&null_value); - layout_set(msg->descriptor->layout, msg, field, &null_value TSRMLS_CC); - cached_zval = CACHED_PTR_TO_ZVAL_PTR(find_zval_property(msg, field)); - ZVAL_ZVAL(cached_zval, value, 1, 0); - return; - } + // TODO(haberman): avoid this copy when we can make the decoder copy. + data_copy = upb_arena_malloc(arena, data_len + 1); + memcpy(data_copy, data, data_len); + data_copy[data_len] = '\0'; + + if (ignore_json_unknown) { + options |= UPB_JSONDEC_IGNOREUNKNOWN; } - if (Z_TYPE_P(cached_zval) == IS_OBJECT) { - const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); - const upb_fielddef* value_field = upb_msgdef_itof(submsgdef, 1); - MessageHeader* submsg = UNBOX(MessageHeader, cached_zval); - layout_set(submsg->descriptor->layout, submsg, - value_field, value TSRMLS_CC); - } else { - ZVAL_ZVAL(cached_zval, value, 1, 0); + upb_status_clear(&status); + if (!upb_json_decode(data_copy, data_len, intern->msg, intern->desc->msgdef, + DescriptorPool_GetSymbolTable(), options, arena, + &status)) { + zend_throw_exception_ex(NULL, 0, "Error occurred during parsing: %s", + upb_status_errmsg(&status)); + return; } } -PHP_METHOD(Message, readOneof) { - PHP_PROTO_LONG index; +/** + * Message::serializeToJsonString() + * + * Serializes this object to JSON. + * @return string Serialized JSON data. + */ +PHP_METHOD(Message, serializeToJsonString) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + size_t size; + int options = 0; + char buf[1024]; + zend_bool preserve_proto_fieldnames = false; + upb_status status; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", + &preserve_proto_fieldnames) == FAILURE) { return; } - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - - const upb_fielddef* field = upb_msgdef_itof(msg->descriptor->msgdef, index); + if (preserve_proto_fieldnames) { + options |= UPB_JSONENC_PROTONAMES; + } - // Unlike singular fields, oneof fields share cached property. So we cannot - // let layout_get modify the cached property. Instead, we pass in the return - // value directly. - layout_get(msg->descriptor->layout, msg, field, - ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC); -} + upb_status_clear(&status); + size = upb_json_encode(intern->msg, intern->desc->msgdef, + DescriptorPool_GetSymbolTable(), options, buf, + sizeof(buf), &status); -PHP_METHOD(Message, writeOneof) { - PHP_PROTO_LONG index; - zval* value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &index, &value) == - FAILURE) { + if (!upb_ok(&status)) { + zend_throw_exception_ex(NULL, 0, + "Error occurred during JSON serialization: %s", + upb_status_errmsg(&status)); return; } - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - - const upb_fielddef* field = upb_msgdef_itof(msg->descriptor->msgdef, index); - - layout_set(msg->descriptor->layout, msg, field, value TSRMLS_CC); -} - -PHP_METHOD(Message, whichOneof) { - char* oneof_name; - PHP_PROTO_SIZE length; + if (size >= sizeof(buf)) { + char *buf2 = malloc(size + 1); + upb_json_encode(intern->msg, intern->desc->msgdef, + DescriptorPool_GetSymbolTable(), options, buf2, size + 1, + &status); + RETVAL_STRINGL(buf2, size); + free(buf2); + } else { + RETVAL_STRINGL(buf, size); + } +} + +/** + * Message::readWrapperValue() + * + * Returns an unboxed value for the given field. This is called from generated + * methods for wrapper fields, eg. + * + * public function getDoubleValueUnwrapped() + * { + * return $this->readWrapperValue("double_value"); + * } + * + * @return Unwrapped field value or null. + */ +PHP_METHOD(Message, readWrapperValue) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + char* member; + const upb_fielddef *f; + zend_long size; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &oneof_name, - &length) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &member, &size) == FAILURE) { return; } - MessageHeader* msg = UNBOX(MessageHeader, getThis()); - - const upb_oneofdef* oneof = - upb_msgdef_ntoo(msg->descriptor->msgdef, oneof_name, length); - const char* oneof_case_name = layout_get_oneof_case( - msg->descriptor->layout, message_data(msg), oneof TSRMLS_CC); - PHP_PROTO_RETURN_STRING(oneof_case_name, 1); -} - -// ----------------------------------------------------------------------------- -// Well Known Types Support -// ----------------------------------------------------------------------------- + f = upb_msgdef_ntof(intern->desc->msgdef, member, size); -#define PHP_PROTO_FIELD_ACCESSORS(UPPER_CLASS, LOWER_CLASS, UPPER_FIELD, \ - LOWER_FIELD) \ - PHP_METHOD(UPPER_CLASS, get##UPPER_FIELD) { \ - zval member; \ - PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1); \ - PHP_PROTO_FAKE_SCOPE_BEGIN(LOWER_CLASS##_type); \ - zval* value = message_get_property_internal(getThis(), &member TSRMLS_CC); \ - PHP_PROTO_FAKE_SCOPE_END; \ - zval_dtor(&member); \ - PHP_PROTO_RETVAL_ZVAL(value); \ - } \ - PHP_METHOD(UPPER_CLASS, set##UPPER_FIELD) { \ - zval* value = NULL; \ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == \ - FAILURE) { \ - return; \ - } \ - zval member; \ - PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1); \ - message_set_property_internal(getThis(), &member, value TSRMLS_CC); \ - zval_dtor(&member); \ - PHP_PROTO_RETVAL_ZVAL(getThis()); \ - } - -#define PHP_PROTO_ONEOF_FIELD_ACCESSORS(UPPER_CLASS, LOWER_CLASS, UPPER_FIELD, \ - LOWER_FIELD) \ - PHP_METHOD(UPPER_CLASS, get##UPPER_FIELD) { \ - zval member; \ - PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1); \ - PHP_PROTO_FAKE_SCOPE_BEGIN(LOWER_CLASS##_type); \ - message_get_oneof_property_internal(getThis(), &member, \ - return_value TSRMLS_CC); \ - PHP_PROTO_FAKE_SCOPE_END; \ - zval_dtor(&member); \ - } \ - PHP_METHOD(UPPER_CLASS, set##UPPER_FIELD) { \ - zval* value = NULL; \ - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == \ - FAILURE) { \ - return; \ - } \ - zval member; \ - PHP_PROTO_ZVAL_STRING(&member, LOWER_FIELD, 1); \ - message_set_property_internal(getThis(), &member, value TSRMLS_CC); \ - zval_dtor(&member); \ - PHP_PROTO_RETVAL_ZVAL(getThis()); \ + if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) { + zend_throw_exception_ex(NULL, 0, "Message %s has no field %s", + upb_msgdef_fullname(intern->desc->msgdef), member); + return; } -#define PHP_PROTO_ONEOF_ACCESSORS(UPPER_CLASS, LOWER_CLASS, UPPER_FIELD, \ - LOWER_FIELD) \ - PHP_METHOD(UPPER_CLASS, get##UPPER_FIELD) { \ - MessageHeader* msg = UNBOX(MessageHeader, getThis()); \ - PHP_PROTO_FAKE_SCOPE_BEGIN(LOWER_CLASS##_type); \ - const upb_oneofdef* oneof = upb_msgdef_ntoo( \ - msg->descriptor->msgdef, LOWER_FIELD, strlen(LOWER_FIELD)); \ - const char* oneof_case_name = layout_get_oneof_case( \ - msg->descriptor->layout, message_data(msg), oneof TSRMLS_CC); \ - PHP_PROTO_FAKE_SCOPE_END; \ - PHP_PROTO_RETURN_STRING(oneof_case_name, 1); \ + if (upb_msg_has(intern->msg, f)) { + const upb_msg *wrapper = upb_msg_get(intern->msg, f).msg_val; + const upb_msgdef *m = upb_fielddef_msgsubdef(f); + const upb_fielddef *val_f = upb_msgdef_itof(m, 1); + const upb_fieldtype_t val_type = upb_fielddef_type(val_f); + upb_msgval msgval = upb_msg_get(wrapper, val_f); + zval ret; + Convert_UpbToPhp(msgval, &ret, val_type, NULL, &intern->arena); + RETURN_ZVAL(&ret, 1, 0); + } else { + RETURN_NULL(); } - -// Forward declare file init functions -static void init_file_any(TSRMLS_D); -static void init_file_api(TSRMLS_D); -static void init_file_duration(TSRMLS_D); -static void init_file_field_mask(TSRMLS_D); -static void init_file_empty(TSRMLS_D); -static void init_file_source_context(TSRMLS_D); -static void init_file_struct(TSRMLS_D); -static void init_file_timestamp(TSRMLS_D); -static void init_file_type(TSRMLS_D); -static void init_file_wrappers(TSRMLS_D); - -// Define file init functions -static void init_file_any(TSRMLS_D) { - if (is_inited_file_any) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0acd010a19676f6f676c652f70726f746f6275662f616e792e70726f746f" - "120f676f6f676c652e70726f746f62756622260a03416e7912100a087479" - "70655f75726c180120012809120d0a0576616c756518022001280c426f0a" - "13636f6d2e676f6f676c652e70726f746f6275664208416e7950726f746f" - "50015a256769746875622e636f6d2f676f6c616e672f70726f746f627566" - "2f7074797065732f616e79a20203475042aa021e476f6f676c652e50726f" - "746f6275662e57656c6c4b6e6f776e5479706573620670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_any = true; -} - -static void init_file_api(TSRMLS_D) { - if (is_inited_file_api) return; - init_file_source_context(TSRMLS_C); - init_file_type(TSRMLS_C); - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0aee050a19676f6f676c652f70726f746f6275662f6170692e70726f746f" - "120f676f6f676c652e70726f746f6275661a24676f6f676c652f70726f74" - "6f6275662f736f757263655f636f6e746578742e70726f746f1a1a676f6f" - "676c652f70726f746f6275662f747970652e70726f746f2281020a034170" - "69120c0a046e616d6518012001280912280a076d6574686f647318022003" - "280b32172e676f6f676c652e70726f746f6275662e4d6574686f6412280a" - "076f7074696f6e7318032003280b32172e676f6f676c652e70726f746f62" - "75662e4f7074696f6e120f0a0776657273696f6e18042001280912360a0e" - "736f757263655f636f6e7465787418052001280b321e2e676f6f676c652e" - "70726f746f6275662e536f75726365436f6e7465787412260a066d697869" - "6e7318062003280b32162e676f6f676c652e70726f746f6275662e4d6978" - "696e12270a0673796e74617818072001280e32172e676f6f676c652e7072" - "6f746f6275662e53796e74617822d5010a064d6574686f64120c0a046e61" - "6d6518012001280912180a10726571756573745f747970655f75726c1802" - "2001280912190a11726571756573745f73747265616d696e671803200128" - "0812190a11726573706f6e73655f747970655f75726c180420012809121a" - "0a12726573706f6e73655f73747265616d696e6718052001280812280a07" - "6f7074696f6e7318062003280b32172e676f6f676c652e70726f746f6275" - "662e4f7074696f6e12270a0673796e74617818072001280e32172e676f6f" - "676c652e70726f746f6275662e53796e74617822230a054d6978696e120c" - "0a046e616d65180120012809120c0a04726f6f7418022001280942750a13" - "636f6d2e676f6f676c652e70726f746f627566420841706950726f746f50" - "015a2b676f6f676c652e676f6c616e672e6f72672f67656e70726f746f2f" - "70726f746f6275662f6170693b617069a20203475042aa021e476f6f676c" - "652e50726f746f6275662e57656c6c4b6e6f776e5479706573620670726f" - "746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_api = true; -} - -static void init_file_duration(TSRMLS_D) { - if (is_inited_file_duration) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0ae3010a1e676f6f676c652f70726f746f6275662f6475726174696f6e2e" - "70726f746f120f676f6f676c652e70726f746f627566222a0a0844757261" - "74696f6e120f0a077365636f6e6473180120012803120d0a056e616e6f73" - "180220012805427c0a13636f6d2e676f6f676c652e70726f746f62756642" - "0d4475726174696f6e50726f746f50015a2a6769746875622e636f6d2f67" - "6f6c616e672f70726f746f6275662f7074797065732f6475726174696f6e" - "f80101a20203475042aa021e476f6f676c652e50726f746f6275662e5765" - "6c6c4b6e6f776e5479706573620670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_duration = true; -} - -static void init_file_field_mask(TSRMLS_D) { - if (is_inited_file_field_mask) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0ae3010a20676f6f676c652f70726f746f6275662f6669656c645f6d6173" - "6b2e70726f746f120f676f6f676c652e70726f746f627566221a0a094669" - "656c644d61736b120d0a0570617468731801200328094289010a13636f6d" - "2e676f6f676c652e70726f746f627566420e4669656c644d61736b50726f" - "746f50015a39676f6f676c652e676f6c616e672e6f72672f67656e70726f" - "746f2f70726f746f6275662f6669656c645f6d61736b3b6669656c645f6d" - "61736ba20203475042aa021e476f6f676c652e50726f746f6275662e5765" - "6c6c4b6e6f776e5479706573620670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_field_mask = true; -} - -static void init_file_empty(TSRMLS_D) { - if (is_inited_file_empty) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0ab7010a1b676f6f676c652f70726f746f6275662f656d7074792e70726f" - "746f120f676f6f676c652e70726f746f62756622070a05456d7074794276" - "0a13636f6d2e676f6f676c652e70726f746f627566420a456d7074795072" - "6f746f50015a276769746875622e636f6d2f676f6c616e672f70726f746f" - "6275662f7074797065732f656d707479f80101a20203475042aa021e476f" - "6f676c652e50726f746f6275662e57656c6c4b6e6f776e54797065736206" - "70726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_empty = true; -} - -static void init_file_source_context(TSRMLS_D) { - if (is_inited_file_source_context) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0afb010a24676f6f676c652f70726f746f6275662f736f757263655f636f" - "6e746578742e70726f746f120f676f6f676c652e70726f746f6275662222" - "0a0d536f75726365436f6e7465787412110a0966696c655f6e616d651801" - "200128094295010a13636f6d2e676f6f676c652e70726f746f6275664212" - "536f75726365436f6e7465787450726f746f50015a41676f6f676c652e67" - "6f6c616e672e6f72672f67656e70726f746f2f70726f746f6275662f736f" - "757263655f636f6e746578743b736f757263655f636f6e74657874a20203" - "475042aa021e476f6f676c652e50726f746f6275662e57656c6c4b6e6f77" - "6e5479706573620670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_source_context = true; -} - -static void init_file_struct(TSRMLS_D) { - if (is_inited_file_struct) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0a81050a1c676f6f676c652f70726f746f6275662f7374727563742e7072" - "6f746f120f676f6f676c652e70726f746f6275662284010a065374727563" - "7412330a066669656c647318012003280b32232e676f6f676c652e70726f" - "746f6275662e5374727563742e4669656c6473456e7472791a450a0b4669" - "656c6473456e747279120b0a036b657918012001280912250a0576616c75" - "6518022001280b32162e676f6f676c652e70726f746f6275662e56616c75" - "653a02380122ea010a0556616c756512300a0a6e756c6c5f76616c756518" - "012001280e321a2e676f6f676c652e70726f746f6275662e4e756c6c5661" - "6c7565480012160a0c6e756d6265725f76616c7565180220012801480012" - "160a0c737472696e675f76616c7565180320012809480012140a0a626f6f" - "6c5f76616c75651804200128084800122f0a0c7374727563745f76616c75" - "6518052001280b32172e676f6f676c652e70726f746f6275662e53747275" - "6374480012300a0a6c6973745f76616c756518062001280b321a2e676f6f" - "676c652e70726f746f6275662e4c69737456616c7565480042060a046b69" - "6e6422330a094c69737456616c756512260a0676616c7565731801200328" - "0b32162e676f6f676c652e70726f746f6275662e56616c75652a1b0a094e" - "756c6c56616c7565120e0a0a4e554c4c5f56414c554510004281010a1363" - "6f6d2e676f6f676c652e70726f746f627566420b53747275637450726f74" - "6f50015a316769746875622e636f6d2f676f6c616e672f70726f746f6275" - "662f7074797065732f7374727563743b7374727563747062f80101a20203" - "475042aa021e476f6f676c652e50726f746f6275662e57656c6c4b6e6f77" - "6e5479706573620670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_struct = true; -} - -static void init_file_timestamp(TSRMLS_D) { - if (is_inited_file_timestamp) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0ae7010a1f676f6f676c652f70726f746f6275662f74696d657374616d70" - "2e70726f746f120f676f6f676c652e70726f746f627566222b0a0954696d" - "657374616d70120f0a077365636f6e6473180120012803120d0a056e616e" - "6f73180220012805427e0a13636f6d2e676f6f676c652e70726f746f6275" - "66420e54696d657374616d7050726f746f50015a2b6769746875622e636f" - "6d2f676f6c616e672f70726f746f6275662f7074797065732f74696d6573" - "74616d70f80101a20203475042aa021e476f6f676c652e50726f746f6275" - "662e57656c6c4b6e6f776e5479706573620670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_timestamp = true; } -static void init_file_type(TSRMLS_D) { - if (is_inited_file_type) return; - init_file_any(TSRMLS_C); - init_file_source_context(TSRMLS_C); - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0aba0c0a1a676f6f676c652f70726f746f6275662f747970652e70726f74" - "6f120f676f6f676c652e70726f746f6275661a19676f6f676c652f70726f" - "746f6275662f616e792e70726f746f1a24676f6f676c652f70726f746f62" - "75662f736f757263655f636f6e746578742e70726f746f22d7010a045479" - "7065120c0a046e616d6518012001280912260a066669656c647318022003" - "280b32162e676f6f676c652e70726f746f6275662e4669656c64120e0a06" - "6f6e656f667318032003280912280a076f7074696f6e7318042003280b32" - "172e676f6f676c652e70726f746f6275662e4f7074696f6e12360a0e736f" - "757263655f636f6e7465787418052001280b321e2e676f6f676c652e7072" - "6f746f6275662e536f75726365436f6e7465787412270a0673796e746178" - "18062001280e32172e676f6f676c652e70726f746f6275662e53796e7461" - "7822d5050a054669656c6412290a046b696e6418012001280e321b2e676f" - "6f676c652e70726f746f6275662e4669656c642e4b696e6412370a0b6361" - "7264696e616c69747918022001280e32222e676f6f676c652e70726f746f" - "6275662e4669656c642e43617264696e616c697479120e0a066e756d6265" - "72180320012805120c0a046e616d6518042001280912100a08747970655f" - "75726c18062001280912130a0b6f6e656f665f696e646578180720012805" - "120e0a067061636b656418082001280812280a076f7074696f6e73180920" - "03280b32172e676f6f676c652e70726f746f6275662e4f7074696f6e1211" - "0a096a736f6e5f6e616d65180a2001280912150a0d64656661756c745f76" - "616c7565180b2001280922c8020a044b696e6412100a0c545950455f554e" - "4b4e4f574e1000120f0a0b545950455f444f55424c451001120e0a0a5459" - "50455f464c4f41541002120e0a0a545950455f494e5436341003120f0a0b" - "545950455f55494e5436341004120e0a0a545950455f494e543332100512" - "100a0c545950455f46495845443634100612100a0c545950455f46495845" - "4433321007120d0a09545950455f424f4f4c1008120f0a0b545950455f53" - "5452494e471009120e0a0a545950455f47524f5550100a12100a0c545950" - "455f4d455353414745100b120e0a0a545950455f4259544553100c120f0a" - "0b545950455f55494e543332100d120d0a09545950455f454e554d100e12" - "110a0d545950455f5346495845443332100f12110a0d545950455f534649" - "58454436341010120f0a0b545950455f53494e5433321011120f0a0b5459" - "50455f53494e543634101222740a0b43617264696e616c69747912170a13" - "43415244494e414c4954595f554e4b4e4f574e100012180a144341524449" - "4e414c4954595f4f5054494f4e414c100112180a1443415244494e414c49" - "54595f5245515549524544100212180a1443415244494e414c4954595f52" - "45504541544544100322ce010a04456e756d120c0a046e616d6518012001" - "2809122d0a09656e756d76616c756518022003280b321a2e676f6f676c65" - "2e70726f746f6275662e456e756d56616c756512280a076f7074696f6e73" - "18032003280b32172e676f6f676c652e70726f746f6275662e4f7074696f" - "6e12360a0e736f757263655f636f6e7465787418042001280b321e2e676f" - "6f676c652e70726f746f6275662e536f75726365436f6e7465787412270a" - "0673796e74617818052001280e32172e676f6f676c652e70726f746f6275" - "662e53796e74617822530a09456e756d56616c7565120c0a046e616d6518" - "0120012809120e0a066e756d62657218022001280512280a076f7074696f" - "6e7318032003280b32172e676f6f676c652e70726f746f6275662e4f7074" - "696f6e223b0a064f7074696f6e120c0a046e616d6518012001280912230a" - "0576616c756518022001280b32142e676f6f676c652e70726f746f627566" - "2e416e792a2e0a0653796e74617812110a0d53594e5441585f50524f544f" - "32100012110a0d53594e5441585f50524f544f331001427d0a13636f6d2e" - "676f6f676c652e70726f746f62756642095479706550726f746f50015a2f" - "676f6f676c652e676f6c616e672e6f72672f67656e70726f746f2f70726f" - "746f6275662f70747970653b7074797065f80101a20203475042aa021e47" - "6f6f676c652e50726f746f6275662e57656c6c4b6e6f776e547970657362" - "0670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_type = true; -} - -static void init_file_wrappers(TSRMLS_D) { - if (is_inited_file_wrappers) return; - init_generated_pool_once(TSRMLS_C); - const char* generated_file = - "0abf030a1e676f6f676c652f70726f746f6275662f77726170706572732e" - "70726f746f120f676f6f676c652e70726f746f627566221c0a0b446f7562" - "6c6556616c7565120d0a0576616c7565180120012801221b0a0a466c6f61" - "7456616c7565120d0a0576616c7565180120012802221b0a0a496e743634" - "56616c7565120d0a0576616c7565180120012803221c0a0b55496e743634" - "56616c7565120d0a0576616c7565180120012804221b0a0a496e74333256" - "616c7565120d0a0576616c7565180120012805221c0a0b55496e74333256" - "616c7565120d0a0576616c756518012001280d221a0a09426f6f6c56616c" - "7565120d0a0576616c7565180120012808221c0a0b537472696e6756616c" - "7565120d0a0576616c7565180120012809221b0a0a427974657356616c75" - "65120d0a0576616c756518012001280c427c0a13636f6d2e676f6f676c65" - "2e70726f746f627566420d577261707065727350726f746f50015a2a6769" - "746875622e636f6d2f676f6c616e672f70726f746f6275662f7074797065" - "732f7772617070657273f80101a20203475042aa021e476f6f676c652e50" - "726f746f6275662e57656c6c4b6e6f776e5479706573620670726f746f33"; - char* binary; - int binary_len; - hex_to_binary(generated_file, &binary, &binary_len); - internal_add_generated_file(binary, binary_len, - generated_pool, true TSRMLS_CC); - FREE(binary); - is_inited_file_wrappers = true; -} - -// ----------------------------------------------------------------------------- -// Define enum -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// Field_Cardinality -// ----------------------------------------------------------------------------- - -static zend_function_entry field_cardinality_methods[] = { - PHP_ME(Field_Cardinality, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Field_Cardinality, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - {NULL, NULL, NULL} -}; +/** + * Message::writeWrapperValue() + * + * Sets the given wrapper field to the given unboxed value. This is called from + * generated methods for wrapper fields, eg. + * + * + * public function setDoubleValueUnwrapped($var) + * { + * $this->writeWrapperValue("double_value", $var); + * return $this; + * } + * + * @param Unwrapped field value or null. + */ +PHP_METHOD(Message, writeWrapperValue) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + upb_arena *arena = Arena_Get(&intern->arena); + char* member; + const upb_fielddef *f; + upb_msgval msgval; + zend_long size; + zval* val; -zend_class_entry* field_cardinality_type; - -// Init class entry. -PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Cardinality", - Field_Cardinality, field_cardinality) - zend_declare_class_constant_long(field_cardinality_type, - "CARDINALITY_UNKNOWN", 19, 0 TSRMLS_CC); - zend_declare_class_constant_long(field_cardinality_type, - "CARDINALITY_OPTIONAL", 20, 1 TSRMLS_CC); - zend_declare_class_constant_long(field_cardinality_type, - "CARDINALITY_REQUIRED", 20, 2 TSRMLS_CC); - zend_declare_class_constant_long(field_cardinality_type, - "CARDINALITY_REPEATED", 20, 3 TSRMLS_CC); - const char *alias = "Google\\Protobuf\\Field_Cardinality"; -#if PHP_VERSION_ID < 70300 - zend_register_class_alias_ex(alias, strlen(alias), field_cardinality_type TSRMLS_CC); -#else - zend_register_class_alias_ex(alias, strlen(alias), field_cardinality_type, 1); -#endif -PHP_PROTO_INIT_ENUMCLASS_END - -PHP_METHOD(Field_Cardinality, name) { - PHP_PROTO_LONG value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &member, &size, &val) == FAILURE) { return; } - switch (value) { - case 0: - PHP_PROTO_RETURN_STRING("CARDINALITY_UNKNOWN", 1); - case 1: - PHP_PROTO_RETURN_STRING("CARDINALITY_OPTIONAL", 1); - case 2: - PHP_PROTO_RETURN_STRING("CARDINALITY_REQUIRED", 1); - case 3: - PHP_PROTO_RETURN_STRING("CARDINALITY_REPEATED", 1); - default: - zend_throw_exception_ex( - NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\Field_Cardinality has no name " -#if PHP_MAJOR_VERSION < 7 - "defined for value %d.", -#else - "defined for value " ZEND_LONG_FMT ".", -#endif - value); - } -} -PHP_METHOD(Field_Cardinality, value) { - char *name = NULL; - PHP_PROTO_SIZE name_len; + f = upb_msgdef_ntof(intern->desc->msgdef, member, size); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == - FAILURE) { + if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) { + zend_throw_exception_ex(NULL, 0, "Message %s has no field %s", + upb_msgdef_fullname(intern->desc->msgdef), member); return; } - if (strncmp(name, "CARDINALITY_UNKNOWN", name_len) == 0) RETURN_LONG(0); - if (strncmp(name, "CARDINALITY_OPTIONAL", name_len) == 0) RETURN_LONG(1); - if (strncmp(name, "CARDINALITY_REQUIRED", name_len) == 0) RETURN_LONG(2); - if (strncmp(name, "CARDINALITY_REPEATED", name_len) == 0) RETURN_LONG(3); - - zend_throw_exception_ex( - NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\Field_Cardinality has no value " - "defined for name %s.", - name); -} + if (Z_ISREF_P(val)) { + ZVAL_DEREF(val); + } -// ----------------------------------------------------------------------------- -// Field_Kind -// ----------------------------------------------------------------------------- + if (Z_TYPE_P(val) == IS_NULL) { + upb_msg_clearfield(intern->msg, f); + } else { + const upb_msgdef *m = upb_fielddef_msgsubdef(f); + const upb_fielddef *val_f = upb_msgdef_itof(m, 1); + upb_fieldtype_t val_type = upb_fielddef_type(val_f); + upb_msg *wrapper; -static zend_function_entry field_kind_methods[] = { - PHP_ME(Field_Kind, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Field_Kind, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - {NULL, NULL, NULL} -}; + if (!Convert_PhpToUpb(val, &msgval, val_type, NULL, arena)) { + return; // Error is already set. + } -zend_class_entry* field_kind_type; - -// Init class entry. -PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Field\\Kind", - Field_Kind, field_kind) - zend_declare_class_constant_long(field_kind_type, - "TYPE_UNKNOWN", 12, 0 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_DOUBLE", 11, 1 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_FLOAT", 10, 2 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_INT64", 10, 3 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_UINT64", 11, 4 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_INT32", 10, 5 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_FIXED64", 12, 6 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_FIXED32", 12, 7 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_BOOL", 9, 8 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_STRING", 11, 9 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_GROUP", 10, 10 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_MESSAGE", 12, 11 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_BYTES", 10, 12 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_UINT32", 11, 13 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_ENUM", 9, 14 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_SFIXED32", 13, 15 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_SFIXED64", 13, 16 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_SINT32", 11, 17 TSRMLS_CC); - zend_declare_class_constant_long(field_kind_type, - "TYPE_SINT64", 11, 18 TSRMLS_CC); - const char *alias = "Google\\Protobuf\\Field_Kind"; -#if PHP_VERSION_ID < 70300 - zend_register_class_alias_ex(alias, strlen(alias), field_kind_type TSRMLS_CC); -#else - zend_register_class_alias_ex(alias, strlen(alias), field_kind_type, 1); -#endif -PHP_PROTO_INIT_ENUMCLASS_END - -PHP_METHOD(Field_Kind, name) { - PHP_PROTO_LONG value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == - FAILURE) { - return; - } - switch (value) { - case 0: - PHP_PROTO_RETURN_STRING("TYPE_UNKNOWN", 1); - case 1: - PHP_PROTO_RETURN_STRING("TYPE_DOUBLE", 1); - case 2: - PHP_PROTO_RETURN_STRING("TYPE_FLOAT", 1); - case 3: - PHP_PROTO_RETURN_STRING("TYPE_INT64", 1); - case 4: - PHP_PROTO_RETURN_STRING("TYPE_UINT64", 1); - case 5: - PHP_PROTO_RETURN_STRING("TYPE_INT32", 1); - case 6: - PHP_PROTO_RETURN_STRING("TYPE_FIXED64", 1); - case 7: - PHP_PROTO_RETURN_STRING("TYPE_FIXED32", 1); - case 8: - PHP_PROTO_RETURN_STRING("TYPE_BOOL", 1); - case 9: - PHP_PROTO_RETURN_STRING("TYPE_STRING", 1); - case 10: - PHP_PROTO_RETURN_STRING("TYPE_GROUP", 1); - case 11: - PHP_PROTO_RETURN_STRING("TYPE_MESSAGE", 1); - case 12: - PHP_PROTO_RETURN_STRING("TYPE_BYTES", 1); - case 13: - PHP_PROTO_RETURN_STRING("TYPE_UINT32", 1); - case 14: - PHP_PROTO_RETURN_STRING("TYPE_ENUM", 1); - case 15: - PHP_PROTO_RETURN_STRING("TYPE_SFIXED32", 1); - case 16: - PHP_PROTO_RETURN_STRING("TYPE_SFIXED64", 1); - case 17: - PHP_PROTO_RETURN_STRING("TYPE_SINT32", 1); - case 18: - PHP_PROTO_RETURN_STRING("TYPE_SINT64", 1); - default: - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\Field_Kind has no name " -#if PHP_MAJOR_VERSION < 7 - "defined for value %d.", -#else - "defined for value " ZEND_LONG_FMT ".", -#endif - value); + wrapper = upb_msg_mutable(intern->msg, f, arena).msg; + upb_msg_set(wrapper, val_f, msgval, arena); } } -PHP_METHOD(Field_Kind, value) { - char *name = NULL; - PHP_PROTO_SIZE name_len; +/** + * Message::whichOneof() + * + * Given a oneof name, returns the name of the field that is set for this oneof, + * or otherwise the empty string. + * + * @return string The field name in this oneof that is currently set. + */ +PHP_METHOD(Message, whichOneof) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + const upb_oneofdef* oneof; + const upb_fielddef* field; + char* name; + zend_long len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == - FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &len) == FAILURE) { return; } - if (strncmp(name, "TYPE_UNKNOWN", name_len) == 0) RETURN_LONG(0); - if (strncmp(name, "TYPE_DOUBLE", name_len) == 0) RETURN_LONG(1); - if (strncmp(name, "TYPE_FLOAT", name_len) == 0) RETURN_LONG(2); - if (strncmp(name, "TYPE_INT64", name_len) == 0) RETURN_LONG(3); - if (strncmp(name, "TYPE_UINT64", name_len) == 0) RETURN_LONG(4); - if (strncmp(name, "TYPE_INT32", name_len) == 0) RETURN_LONG(5); - if (strncmp(name, "TYPE_FIXED64", name_len) == 0) RETURN_LONG(6); - if (strncmp(name, "TYPE_FIXED32", name_len) == 0) RETURN_LONG(7); - if (strncmp(name, "TYPE_BOOL", name_len) == 0) RETURN_LONG(8); - if (strncmp(name, "TYPE_STRING", name_len) == 0) RETURN_LONG(9); - if (strncmp(name, "TYPE_GROUP", name_len) == 0) RETURN_LONG(10); - if (strncmp(name, "TYPE_MESSAGE", name_len) == 0) RETURN_LONG(11); - if (strncmp(name, "TYPE_BYTES", name_len) == 0) RETURN_LONG(12); - if (strncmp(name, "TYPE_UINT32", name_len) == 0) RETURN_LONG(13); - if (strncmp(name, "TYPE_ENUM", name_len) == 0) RETURN_LONG(14); - if (strncmp(name, "TYPE_SFIXED32", name_len) == 0) RETURN_LONG(15); - if (strncmp(name, "TYPE_SFIXED64", name_len) == 0) RETURN_LONG(16); - if (strncmp(name, "TYPE_SINT32", name_len) == 0) RETURN_LONG(17); - if (strncmp(name, "TYPE_SINT64", name_len) == 0) RETURN_LONG(18); - - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\Field_Kind has no value " - "defined for name %s.", - name); -} - -// ----------------------------------------------------------------------------- -// NullValue -// ----------------------------------------------------------------------------- - -static zend_function_entry null_value_methods[] = { - PHP_ME(NullValue, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(NullValue, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* null_value_type; + oneof = upb_msgdef_ntoo(intern->desc->msgdef, name, len); -// Init class entry. -PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\NullValue", - NullValue, null_value) - zend_declare_class_constant_long(null_value_type, - "NULL_VALUE", 10, 0 TSRMLS_CC); -PHP_PROTO_INIT_ENUMCLASS_END - -PHP_METHOD(NullValue, name) { - PHP_PROTO_LONG value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == - FAILURE) { + if (!oneof) { + zend_throw_exception_ex(NULL, 0, "Message %s has no oneof %s", + upb_msgdef_fullname(intern->desc->msgdef), name); return; } - switch (value) { - case 0: - PHP_PROTO_RETURN_STRING("NULL_VALUE", 1); - default: - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\NullValue has no name " -#if PHP_MAJOR_VERSION < 7 - "defined for value %d.", -#else - "defined for value " ZEND_LONG_FMT ".", -#endif - value); - } + + field = upb_msg_whichoneof(intern->msg, oneof); + RETURN_STRING(field ? upb_fielddef_name(field) : ""); } -PHP_METHOD(NullValue, value) { - char *name = NULL; - PHP_PROTO_SIZE name_len; +/** + * Message::readOneof() + * + * Returns the contents of the given oneof field, given a field number. Called + * from generated code methods such as: + * + * public function getDoubleValueOneof() + * { + * return $this->readOneof(10); + * } + * + * @return object The oneof's field value. + */ +PHP_METHOD(Message, readOneof) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + zend_long field_num; + const upb_fielddef* f; + zval ret; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == - FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &field_num) == FAILURE) { return; } - if (strncmp(name, "NULL_VALUE", name_len) == 0) RETURN_LONG(0); - - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\NullValue has no value " - "defined for name %s.", - name); -} - -// ----------------------------------------------------------------------------- -// Syntax -// ----------------------------------------------------------------------------- - -static zend_function_entry syntax_methods[] = { - PHP_ME(Syntax, name, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Syntax, value, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - {NULL, NULL, NULL} -}; + f = upb_msgdef_itof(intern->desc->msgdef, field_num); -zend_class_entry* syntax_type; + if (!f || !upb_fielddef_realcontainingoneof(f)) { + php_error_docref(NULL, E_USER_ERROR, + "Internal error, no such oneof field %d\n", + (int)field_num); + } -// Init class entry. -PHP_PROTO_INIT_ENUMCLASS_START("Google\\Protobuf\\Syntax", - Syntax, syntax) - zend_declare_class_constant_long(syntax_type, - "SYNTAX_PROTO2", 13, 0 TSRMLS_CC); - zend_declare_class_constant_long(syntax_type, - "SYNTAX_PROTO3", 13, 1 TSRMLS_CC); -PHP_PROTO_INIT_ENUMCLASS_END + { + upb_msgval msgval = upb_msg_get(intern->msg, f); + const Descriptor *subdesc = Descriptor_GetFromFieldDef(f); + Convert_UpbToPhp(msgval, &ret, upb_fielddef_type(f), subdesc, + &intern->arena); + } + + RETURN_ZVAL(&ret, 1, 0); +} + +/** + * Message::writeOneof() + * + * Sets the contents of the given oneof field, given a field number. Called + * from generated code methods such as: + * + * public function setDoubleValueOneof($var) + * { + * GPBUtil::checkMessage($var, \Google\Protobuf\DoubleValue::class); + * $this->writeOneof(10, $var); + * + * return $this; + * } + * + * The C extension version of GPBUtil::check*() does nothing, so we perform + * all type checking and conversion here. + * + * @param integer The field number we are setting. + * @param object The field value we want to set. + */ +PHP_METHOD(Message, writeOneof) { + Message* intern = (Message*)Z_OBJ_P(getThis()); + zend_long field_num; + const upb_fielddef* f; + upb_arena *arena = Arena_Get(&intern->arena); + upb_msgval msgval; + zval* val; -PHP_METHOD(Syntax, name) { - PHP_PROTO_LONG value; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &value) == + if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &field_num, &val) == FAILURE) { return; } - switch (value) { - case 0: - PHP_PROTO_RETURN_STRING("SYNTAX_PROTO2", 1); - case 1: - PHP_PROTO_RETURN_STRING("SYNTAX_PROTO3", 1); - default: - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\Syntax has no name " -#if PHP_MAJOR_VERSION < 7 - "defined for value %d.", -#else - "defined for value " ZEND_LONG_FMT ".", -#endif - value); - } -} -PHP_METHOD(Syntax, value) { - char *name = NULL; - PHP_PROTO_SIZE name_len; + f = upb_msgdef_itof(intern->desc->msgdef, field_num); - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == - FAILURE) { + if (!Convert_PhpToUpb(val, &msgval, upb_fielddef_type(f), + Descriptor_GetFromFieldDef(f), arena)) { return; } - if (strncmp(name, "SYNTAX_PROTO2", name_len) == 0) RETURN_LONG(0); - if (strncmp(name, "SYNTAX_PROTO3", name_len) == 0) RETURN_LONG(1); - - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Enum Google\\Protobuf\\Syntax has no value " - "defined for name %s.", - name); + upb_msg_set(intern->msg, f, msgval, arena); } -// ----------------------------------------------------------------------------- -// Define message -// ----------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------- -// Any -// ----------------------------------------------------------------------------- - -static zend_function_entry any_methods[] = { - PHP_ME(Any, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Any, getTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Any, setTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Any, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Any, setValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Any, pack, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Any, unpack, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Any, is, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} +static zend_function_entry Message_methods[] = { + PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Message, discardUnknownFields, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Message, serializeToString, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Message, mergeFromString, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Message, serializeToJsonString, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Message, mergeFromJsonString, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Message, mergeFrom, NULL, ZEND_ACC_PUBLIC) + PHP_ME(Message, readWrapperValue, NULL, ZEND_ACC_PROTECTED) + PHP_ME(Message, writeWrapperValue, NULL, ZEND_ACC_PROTECTED) + PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED) + PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED) + PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED) + PHP_ME(Message, __construct, NULL, ZEND_ACC_PROTECTED) + ZEND_FE_END }; -zend_class_entry* any_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Any", Any, any) - zend_declare_property_string(any_type, "type_url", strlen("type_url"), - "" ,ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(any_type, "value", strlen("value"), - "" ,ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -static void hex_to_binary(const char* hex, char** binary, int* binary_len) { - int i; - int hex_len = strlen(hex); - *binary_len = hex_len / 2; - *binary = ALLOC_N(char, *binary_len); - for (i = 0; i < *binary_len; i++) { - char value = 0; - if (hex[i * 2] >= '0' && hex[i * 2] <= '9') { - value += (hex[i * 2] - '0') * 16; - } else { - value += (hex[i * 2] - 'a' + 10) * 16; - } - if (hex[i * 2 + 1] >= '0' && hex[i * 2 + 1] <= '9') { - value += hex[i * 2 + 1] - '0'; - } else { - value += hex[i * 2 + 1] - 'a' + 10; - } - (*binary)[i] = value; - } -} +/** + * Message_ModuleInit() + * + * Called when the C extension is loaded to register all types. + */ +void Message_ModuleInit() { + zend_class_entry tmp_ce; + zend_object_handlers *h = &message_object_handlers; -PHP_METHOD(Any, __construct) { - init_file_any(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} + INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\Message", + Message_methods); -PHP_PROTO_FIELD_ACCESSORS(Any, any, TypeUrl, "type_url") -PHP_PROTO_FIELD_ACCESSORS(Any, any, Value, "value") - -PHP_METHOD(Any, unpack) { - // Get type url. - zval type_url_member; - PHP_PROTO_ZVAL_STRING(&type_url_member, "type_url", 1); - PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); - zval* type_url_php = php_proto_message_read_property( - getThis(), &type_url_member PHP_PROTO_TSRMLS_CC); - zval_dtor(&type_url_member); - PHP_PROTO_FAKE_SCOPE_END; - - // Get fully-qualified name from type url. - size_t url_prefix_len = strlen(TYPE_URL_PREFIX); - const char* type_url = Z_STRVAL_P(type_url_php); - size_t type_url_len = Z_STRLEN_P(type_url_php); - - if (url_prefix_len > type_url_len || - strncmp(TYPE_URL_PREFIX, type_url, url_prefix_len) != 0) { - zend_throw_exception( - NULL, "Type url needs to be type.googleapis.com/fully-qualified", - 0 TSRMLS_CC); - return; - } + message_ce = zend_register_internal_class(&tmp_ce); + message_ce->create_object = Message_create; - const char* fully_qualified_name = type_url + url_prefix_len; - DescriptorInternal* desc = get_proto_desc(fully_qualified_name); - if (desc == NULL) { - zend_throw_exception( - NULL, "Specified message in any hasn't been added to descriptor pool", - 0 TSRMLS_CC); - return; - } - register_class(desc, false TSRMLS_CC); - zend_class_entry* klass = desc->klass; - ZVAL_OBJ(return_value, klass->create_object(klass TSRMLS_CC)); - MessageHeader* msg = UNBOX(MessageHeader, return_value); - custom_data_init(klass, msg PHP_PROTO_TSRMLS_CC); - - // Get value. - zval value_member; - PHP_PROTO_ZVAL_STRING(&value_member, "value", 1); - PHP_PROTO_FAKE_SCOPE_RESTART(any_type); - zval* value = php_proto_message_read_property( - getThis(), &value_member PHP_PROTO_TSRMLS_CC); - zval_dtor(&value_member); - PHP_PROTO_FAKE_SCOPE_END; - - merge_from_string(Z_STRVAL_P(value), Z_STRLEN_P(value), desc, msg); + memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); + h->dtor_obj = Message_dtor; + h->read_property = Message_read_property; + h->write_property = Message_write_property; + h->get_properties = Message_get_properties; + h->get_property_ptr_ptr = Message_get_property_ptr_ptr; } - -PHP_METHOD(Any, pack) { - zval* val; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &val) == - FAILURE) { - return; - } - - if (!instanceof_function(Z_OBJCE_P(val), message_type TSRMLS_CC)) { - zend_error(E_USER_ERROR, "Given value is not an instance of Message."); - return; - } - - // Set value by serialized data. - zval data; - serialize_to_string(val, &data TSRMLS_CC); - - zval member; - PHP_PROTO_ZVAL_STRING(&member, "value", 1); - - PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); - message_handlers->write_property(getThis(), &member, &data, - NULL PHP_PROTO_TSRMLS_CC); - zval_dtor(&data); - zval_dtor(&member); - PHP_PROTO_FAKE_SCOPE_END; - - // Set type url. - DescriptorInternal* desc = get_ce_desc(Z_OBJCE_P(val)); - const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef); - size_t type_url_len = - strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1; - char* type_url = ALLOC_N(char, type_url_len); - sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name); - zval type_url_php; - PHP_PROTO_ZVAL_STRING(&type_url_php, type_url, 1); - PHP_PROTO_ZVAL_STRING(&member, "type_url", 1); - - PHP_PROTO_FAKE_SCOPE_RESTART(any_type); - message_handlers->write_property(getThis(), &member, &type_url_php, - NULL PHP_PROTO_TSRMLS_CC); - zval_dtor(&type_url_php); - zval_dtor(&member); - PHP_PROTO_FAKE_SCOPE_END; - FREE(type_url); -} - -PHP_METHOD(Any, is) { - zend_class_entry *klass = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &klass) == - FAILURE) { - return; - } - - DescriptorInternal* desc = get_ce_desc(klass); - if (desc == NULL) { - RETURN_BOOL(false); - } - - // Create corresponded type url. - const char* fully_qualified_name = upb_msgdef_fullname(desc->msgdef); - size_t type_url_len = - strlen(TYPE_URL_PREFIX) + strlen(fully_qualified_name) + 1; - char* type_url = ALLOC_N(char, type_url_len); - sprintf(type_url, "%s%s", TYPE_URL_PREFIX, fully_qualified_name); - - // Fetch stored type url. - zval member; - PHP_PROTO_ZVAL_STRING(&member, "type_url", 1); - PHP_PROTO_FAKE_SCOPE_BEGIN(any_type); - zval* value = - php_proto_message_read_property(getThis(), &member PHP_PROTO_TSRMLS_CC); - zval_dtor(&member); - PHP_PROTO_FAKE_SCOPE_END; - - // Compare two type url. - bool is = strcmp(type_url, Z_STRVAL_P(value)) == 0; - FREE(type_url); - - RETURN_BOOL(is); -} - -// ----------------------------------------------------------------------------- -// Duration -// ----------------------------------------------------------------------------- - -static zend_function_entry duration_methods[] = { - PHP_ME(Duration, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Duration, getSeconds, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Duration, setSeconds, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Duration, getNanos, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Duration, setNanos, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* duration_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Duration", - Duration, duration) - zend_declare_property_long(duration_type, "seconds", strlen("seconds"), - 0 ,ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(duration_type, "nanos", strlen("nanos"), - 0 ,ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Duration, __construct) { - init_file_duration(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Duration, duration, Seconds, "seconds") -PHP_PROTO_FIELD_ACCESSORS(Duration, duration, Nanos, "nanos") - -// ----------------------------------------------------------------------------- -// Timestamp -// ----------------------------------------------------------------------------- - -static zend_function_entry timestamp_methods[] = { - PHP_ME(Timestamp, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Timestamp, fromDateTime, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Timestamp, toDateTime, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Timestamp, getSeconds, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Timestamp, setSeconds, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Timestamp, getNanos, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Timestamp, setNanos, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* timestamp_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Timestamp", - Timestamp, timestamp) - zend_declare_property_long(timestamp_type, "seconds", strlen("seconds"), - 0 ,ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(timestamp_type, "nanos", strlen("nanos"), - 0 ,ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -static PHP_METHOD(Timestamp, __construct) { - init_file_timestamp(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Timestamp, timestamp, Seconds, "seconds") -PHP_PROTO_FIELD_ACCESSORS(Timestamp, timestamp, Nanos, "nanos") - -PHP_METHOD(Timestamp, fromDateTime) { - zval* datetime; - - PHP_PROTO_CE_DECLARE date_interface_ce; - if (php_proto_zend_lookup_class("\\DatetimeInterface", 18, - &date_interface_ce) == FAILURE) { - zend_error(E_ERROR, "Make sure date extension is enabled."); - return; - } - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &datetime, - PHP_PROTO_CE_UNREF(date_interface_ce)) == FAILURE) { - zend_error(E_USER_ERROR, "Expect DatetimeInterface."); - return; - } - - int64_t timestamp_seconds; - { - zval retval; - zval function_name; - -#if PHP_MAJOR_VERSION < 7 - INIT_ZVAL(retval); - INIT_ZVAL(function_name); -#endif - - PHP_PROTO_ZVAL_STRING(&function_name, "date_timestamp_get", 1); - - if (call_user_function(EG(function_table), NULL, &function_name, &retval, 1, - ZVAL_PTR_TO_CACHED_PTR(datetime) TSRMLS_CC) == FAILURE) { - zend_error(E_ERROR, "Cannot get timestamp from DateTime."); - return; - } - - protobuf_convert_to_int64(&retval, ×tamp_seconds); - - zval_dtor(&retval); - zval_dtor(&function_name); - } - - int64_t timestamp_micros; - { - zval retval; - zval function_name; - zval format_string; - -#if PHP_MAJOR_VERSION < 7 - INIT_ZVAL(retval); - INIT_ZVAL(function_name); - INIT_ZVAL(format_string); -#endif - - PHP_PROTO_ZVAL_STRING(&function_name, "date_format", 1); - PHP_PROTO_ZVAL_STRING(&format_string, "u", 1); - - CACHED_VALUE params[2] = { - ZVAL_PTR_TO_CACHED_VALUE(datetime), - ZVAL_TO_CACHED_VALUE(format_string), - }; - - if (call_user_function(EG(function_table), NULL, &function_name, &retval, - ARRAY_SIZE(params), params TSRMLS_CC) == FAILURE) { - zend_error(E_ERROR, "Cannot format DateTime."); - return; - } - - protobuf_convert_to_int64(&retval, ×tamp_micros); - - zval_dtor(&retval); - zval_dtor(&function_name); - zval_dtor(&format_string); - } - - // Set seconds - MessageHeader* self = UNBOX(MessageHeader, getThis()); - const upb_fielddef* field = - upb_msgdef_ntofz(self->descriptor->msgdef, "seconds"); - void* storage = message_data(self); - void* memory = slot_memory(self->descriptor->layout, storage, field); - *(int64_t*)memory = timestamp_seconds; - - // Set nanos - field = upb_msgdef_ntofz(self->descriptor->msgdef, "nanos"); - storage = message_data(self); - memory = slot_memory(self->descriptor->layout, storage, field); - *(int32_t*)memory = timestamp_micros * 1000; - - RETURN_NULL(); -} - -PHP_METHOD(Timestamp, toDateTime) { - // Get seconds - MessageHeader* self = UNBOX(MessageHeader, getThis()); - const upb_fielddef* field = - upb_msgdef_ntofz(self->descriptor->msgdef, "seconds"); - void* storage = message_data(self); - void* memory = slot_memory(self->descriptor->layout, storage, field); - int64_t seconds = *(int64_t*)memory; - - // Get nanos - field = upb_msgdef_ntofz(self->descriptor->msgdef, "nanos"); - memory = slot_memory(self->descriptor->layout, storage, field); - int32_t nanos = *(int32_t*)memory; - - // Get formatted time string. - char formatted_time[32]; - snprintf(formatted_time, sizeof(formatted_time), "%" PRId64 ".%06" PRId32, - seconds, nanos / 1000); - - // Create Datetime object. - zval datetime; - zval function_name; - zval format_string; - zval formatted_time_php; - -#if PHP_MAJOR_VERSION < 7 - INIT_ZVAL(function_name); - INIT_ZVAL(format_string); - INIT_ZVAL(formatted_time_php); -#endif - - PHP_PROTO_ZVAL_STRING(&function_name, "date_create_from_format", 1); - PHP_PROTO_ZVAL_STRING(&format_string, "U.u", 1); - PHP_PROTO_ZVAL_STRING(&formatted_time_php, formatted_time, 1); - - CACHED_VALUE params[2] = { - ZVAL_TO_CACHED_VALUE(format_string), - ZVAL_TO_CACHED_VALUE(formatted_time_php), - }; - - if (call_user_function(EG(function_table), NULL, &function_name, &datetime, - ARRAY_SIZE(params), params TSRMLS_CC) == FAILURE) { - zend_error(E_ERROR, "Cannot create DateTime."); - return; - } - - zval_dtor(&function_name); - zval_dtor(&format_string); - zval_dtor(&formatted_time_php); - -#if PHP_MAJOR_VERSION < 7 - zval* datetime_ptr = &datetime; - PHP_PROTO_RETVAL_ZVAL(datetime_ptr); -#else - ZVAL_OBJ(return_value, Z_OBJ(datetime)); -#endif -} - -// ----------------------------------------------------------------------------- -// Api -// ----------------------------------------------------------------------------- - -static zend_function_entry api_methods[] = { - PHP_ME(Api, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, getMethods, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, setMethods, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, getOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, setOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, getVersion, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, setVersion, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, getSourceContext, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, setSourceContext, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, getMixins, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, setMixins, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, getSyntax, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Api, setSyntax, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* api_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Api", - Api, api) - zend_declare_property_string(api_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(api_type, "methods", strlen("methods"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(api_type, "options", strlen("options"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(api_type, "version", strlen("version"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(api_type, "source_context", strlen("source_context"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(api_type, "mixins", strlen("mixins"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(api_type, "syntax", strlen("syntax"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Api, __construct) { - init_file_api(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Api, api, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(Api, api, Methods, "methods") -PHP_PROTO_FIELD_ACCESSORS(Api, api, Options, "options") -PHP_PROTO_FIELD_ACCESSORS(Api, api, Version, "version") -PHP_PROTO_FIELD_ACCESSORS(Api, api, SourceContext, "source_context") -PHP_PROTO_FIELD_ACCESSORS(Api, api, Mixins, "mixins") -PHP_PROTO_FIELD_ACCESSORS(Api, api, Syntax, "syntax") - -// ----------------------------------------------------------------------------- -// BoolValue -// ----------------------------------------------------------------------------- - -static zend_function_entry bool_value_methods[] = { - PHP_ME(BoolValue, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(BoolValue, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(BoolValue, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* bool_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\BoolValue", - BoolValue, bool_value) - zend_declare_property_bool(bool_value_type, "value", strlen("value"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(BoolValue, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(BoolValue, bool_value, Value, "value") - -// ----------------------------------------------------------------------------- -// BytesValue -// ----------------------------------------------------------------------------- - -static zend_function_entry bytes_value_methods[] = { - PHP_ME(BytesValue, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(BytesValue, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(BytesValue, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* bytes_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\BytesValue", - BytesValue, bytes_value) - zend_declare_property_string(bytes_value_type, "value", strlen("value"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(BytesValue, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(BytesValue, bytes_value, Value, "value") - -// ----------------------------------------------------------------------------- -// DoubleValue -// ----------------------------------------------------------------------------- - -static zend_function_entry double_value_methods[] = { - PHP_ME(DoubleValue, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(DoubleValue, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(DoubleValue, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* double_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\DoubleValue", - DoubleValue, double_value) - zend_declare_property_double(double_value_type, "value", strlen("value"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(DoubleValue, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(DoubleValue, double_value, Value, "value") - -// ----------------------------------------------------------------------------- -// Enum -// ----------------------------------------------------------------------------- - -static zend_function_entry enum_methods[] = { - PHP_ME(Enum, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, getEnumvalue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, setEnumvalue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, getOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, setOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, getSourceContext, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, setSourceContext, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, getSyntax, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Enum, setSyntax, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* enum_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Enum", - Enum, enum) - zend_declare_property_string(enum_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(enum_type, "enumvalue", strlen("enumvalue"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(enum_type, "options", strlen("options"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(enum_type, "source_context", strlen("source_context"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(enum_type, "syntax", strlen("syntax"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Enum, __construct) { - init_file_type(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Enumvalue, "enumvalue") -PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Options, "options") -PHP_PROTO_FIELD_ACCESSORS(Enum, enum, SourceContext, "source_context") -PHP_PROTO_FIELD_ACCESSORS(Enum, enum, Syntax, "syntax") - -// ----------------------------------------------------------------------------- -// EnumValue -// ----------------------------------------------------------------------------- - -static zend_function_entry enum_value_methods[] = { - PHP_ME(EnumValue, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValue, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValue, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValue, getNumber, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValue, setNumber, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValue, getOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValue, setOptions, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* enum_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\EnumValue", - EnumValue, enum_value) - zend_declare_property_string(enum_value_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(enum_value_type, "number", strlen("number"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(enum_value_type, "options", strlen("options"), - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(EnumValue, __construct) { - init_file_type(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(EnumValue, enum_value, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(EnumValue, enum_value, Number, "number") -PHP_PROTO_FIELD_ACCESSORS(EnumValue, enum_value, Options, "options") - -// ----------------------------------------------------------------------------- -// FieldMask -// ----------------------------------------------------------------------------- - -static zend_function_entry field_mask_methods[] = { - PHP_ME(FieldMask, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldMask, getPaths, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldMask, setPaths, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* field_mask_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\FieldMask", - FieldMask, field_mask) - zend_declare_property_null(field_mask_type, "paths", strlen("paths"), - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(FieldMask, __construct) { - init_file_field_mask(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(FieldMask, field_mask, Paths, "paths") - -// ----------------------------------------------------------------------------- -// Field -// ----------------------------------------------------------------------------- - -static zend_function_entry field_methods[] = { - PHP_ME(Field, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getKind, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setKind, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getCardinality, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setCardinality, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getNumber, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setNumber, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getOneofIndex, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setOneofIndex, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getPacked, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setPacked, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getJsonName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setJsonName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, getDefaultValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Field, setDefaultValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* field_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Field", - Field, field) - zend_declare_property_long(field_type, "kind", strlen("kind"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(field_type, "cardinality", strlen("cardinality"), - 0, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(field_type, "number", strlen("number"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(field_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(field_type, "type_url", strlen("type_url"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(field_type, "oneof_index", strlen("oneof_index"), - 0, ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_bool(field_type, "packed", strlen("packed"), false, - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(field_type, "options", strlen("options"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(field_type, "json_name", strlen("json_name"), - "", ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(field_type, "default_value", - strlen("default_value"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Field, __construct) { - init_file_type(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Field, field, Kind, "kind") -PHP_PROTO_FIELD_ACCESSORS(Field, field, Cardinality, "cardinality") -PHP_PROTO_FIELD_ACCESSORS(Field, field, Number, "number") -PHP_PROTO_FIELD_ACCESSORS(Field, field, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(Field, field, TypeUrl, "type_url") -PHP_PROTO_FIELD_ACCESSORS(Field, field, OneofIndex, "oneof_index") -PHP_PROTO_FIELD_ACCESSORS(Field, field, Packed, "packed") -PHP_PROTO_FIELD_ACCESSORS(Field, field, Options, "options") -PHP_PROTO_FIELD_ACCESSORS(Field, field, JsonName, "json_name") -PHP_PROTO_FIELD_ACCESSORS(Field, field, DefaultValue, "default_value") - -// ----------------------------------------------------------------------------- -// FloatValue -// ----------------------------------------------------------------------------- - -static zend_function_entry float_value_methods[] = { - PHP_ME(FloatValue, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FloatValue, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FloatValue, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* float_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\FloatValue", - FloatValue, float_value) - zend_declare_property_double(float_value_type, "value", strlen("value"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(FloatValue, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(FloatValue, float_value, Value, "value") - -// ----------------------------------------------------------------------------- -// GPBEmpty -// ----------------------------------------------------------------------------- - -static zend_function_entry empty_methods[] = { - PHP_ME(GPBEmpty, __construct, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* empty_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\GPBEmpty", - GPBEmpty, empty) -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(GPBEmpty, __construct) { - init_file_empty(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - - -// ----------------------------------------------------------------------------- -// Int32Value -// ----------------------------------------------------------------------------- - -static zend_function_entry int32_value_methods[] = { - PHP_ME(Int32Value, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Int32Value, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Int32Value, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* int32_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Int32Value", - Int32Value, int32_value) - zend_declare_property_long(int32_value_type, "value", strlen("value"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Int32Value, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Int32Value, int32_value, Value, "value") - -// ----------------------------------------------------------------------------- -// Int64Value -// ----------------------------------------------------------------------------- - -static zend_function_entry int64_value_methods[] = { - PHP_ME(Int64Value, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Int64Value, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Int64Value, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* int64_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Int64Value", - Int64Value, int64_value) - zend_declare_property_long(int64_value_type, "value", strlen("value"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Int64Value, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Int64Value, int64_value, Value, "value") - -// ----------------------------------------------------------------------------- -// ListValue -// ----------------------------------------------------------------------------- - -static zend_function_entry list_value_methods[] = { - PHP_ME(ListValue, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(ListValue, getValues, NULL, ZEND_ACC_PUBLIC) - PHP_ME(ListValue, setValues, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* list_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\ListValue", - ListValue, list_value) - zend_declare_property_null(list_value_type, "values", strlen("values"), - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(ListValue, __construct) { - init_file_struct(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(ListValue, list_value, Values, "values") - -// ----------------------------------------------------------------------------- -// Method -// ----------------------------------------------------------------------------- - -static zend_function_entry method_methods[] = { - PHP_ME(Method, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, getRequestTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, setRequestTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, getRequestStreaming, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, setRequestStreaming, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, getResponseTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, setResponseTypeUrl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, getResponseStreaming, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, setResponseStreaming, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, getOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, setOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, getSyntax, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Method, setSyntax, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* method_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Method", - Method, method) - zend_declare_property_string(method_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(method_type, "request_type_url", - strlen("request_type_url"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_bool(method_type, "request_streaming", - strlen("request_streaming"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(method_type, "response_type_url", - strlen("response_type_url"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_bool(method_type, "response_streaming", - strlen("response_streaming"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(method_type, "options", strlen("options"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(method_type, "syntax", strlen("syntax"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Method, __construct) { - init_file_api(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Method, method, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(Method, method, RequestTypeUrl, "request_type_url") -PHP_PROTO_FIELD_ACCESSORS(Method, method, RequestStreaming, "request_streaming") -PHP_PROTO_FIELD_ACCESSORS(Method, method, ResponseTypeUrl, "response_type_url") -PHP_PROTO_FIELD_ACCESSORS(Method, method, ResponseStreaming, "response_streaming") -PHP_PROTO_FIELD_ACCESSORS(Method, method, Options, "options") -PHP_PROTO_FIELD_ACCESSORS(Method, method, Syntax, "syntax") - -// ----------------------------------------------------------------------------- -// Mixin -// ----------------------------------------------------------------------------- - -static zend_function_entry mixin_methods[] = { - PHP_ME(Mixin, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Mixin, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Mixin, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Mixin, getRoot, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Mixin, setRoot, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* mixin_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Mixin", - Mixin, mixin) - zend_declare_property_string(mixin_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(mixin_type, "root", strlen("root"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Mixin, __construct) { - init_file_api(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Mixin, mixin, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(Mixin, mixin, Root, "root") - -// ----------------------------------------------------------------------------- -// Option -// ----------------------------------------------------------------------------- - -static zend_function_entry option_methods[] = { - PHP_ME(Option, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Option, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Option, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Option, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Option, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* option_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Option", - Option, option) - zend_declare_property_string(option_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(option_type, "value", strlen("value"), - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Option, __construct) { - init_file_type(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Option, option, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(Option, option, Value, "value") - -// ----------------------------------------------------------------------------- -// SourceContext -// ----------------------------------------------------------------------------- - -static zend_function_entry source_context_methods[] = { - PHP_ME(SourceContext, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(SourceContext, getFileName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(SourceContext, setFileName, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* source_context_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\SourceContext", - SourceContext, source_context) - zend_declare_property_string(source_context_type, "file_name", - strlen("file_name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(SourceContext, __construct) { - init_file_source_context(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(SourceContext, source_context, FileName, "file_name") - -// ----------------------------------------------------------------------------- -// StringValue -// ----------------------------------------------------------------------------- - -static zend_function_entry string_value_methods[] = { - PHP_ME(StringValue, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(StringValue, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(StringValue, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* string_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\StringValue", - StringValue, string_value) - zend_declare_property_string(string_value_type, "value", strlen("value"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(StringValue, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(StringValue, string_value, Value, "value") - -// ----------------------------------------------------------------------------- -// Struct -// ----------------------------------------------------------------------------- - -static zend_function_entry struct_methods[] = { - PHP_ME(Struct, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Struct, getFields, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Struct, setFields, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* struct_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Struct", - Struct, struct) - zend_declare_property_null(struct_type, "fields", strlen("fields"), - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Struct, __construct) { - init_file_struct(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Struct, struct, Fields, "fields") - -// ----------------------------------------------------------------------------- -// Type -// ----------------------------------------------------------------------------- - -static zend_function_entry type_methods[] = { - PHP_ME(Type, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, setName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, getFields, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, setFields, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, getOneofs, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, setOneofs, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, getOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, setOptions, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, getSourceContext, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, setSourceContext, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, getSyntax, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Type, setSyntax, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* type_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Type", - Type, type) - zend_declare_property_string(type_type, "name", strlen("name"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(type_type, "fields", strlen("fields"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_string(type_type, "oneofs", strlen("oneofs"), "", - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(type_type, "options", strlen("options"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_null(type_type, "source_context", strlen("source_context"), - ZEND_ACC_PRIVATE TSRMLS_CC); - zend_declare_property_long(type_type, "syntax", strlen("syntax"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Type, __construct) { - init_file_type(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(Type, type, Name, "name") -PHP_PROTO_FIELD_ACCESSORS(Type, type, Fields, "fields") -PHP_PROTO_FIELD_ACCESSORS(Type, type, Oneofs, "oneofs") -PHP_PROTO_FIELD_ACCESSORS(Type, type, Options, "options") -PHP_PROTO_FIELD_ACCESSORS(Type, type, SourceContext, "source_context") -PHP_PROTO_FIELD_ACCESSORS(Type, type, Syntax, "syntax") - -// ----------------------------------------------------------------------------- -// UInt32Value -// ----------------------------------------------------------------------------- - -static zend_function_entry u_int32_value_methods[] = { - PHP_ME(UInt32Value, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(UInt32Value, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(UInt32Value, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* u_int32_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\UInt32Value", - UInt32Value, u_int32_value) - zend_declare_property_long(u_int32_value_type, "value", strlen("value"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(UInt32Value, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(UInt32Value, u_int32_value, Value, "value") - -// ----------------------------------------------------------------------------- -// UInt64Value -// ----------------------------------------------------------------------------- - -static zend_function_entry u_int64_value_methods[] = { - PHP_ME(UInt64Value, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(UInt64Value, getValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(UInt64Value, setValue, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* u_int64_value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\UInt64Value", - UInt64Value, u_int64_value) - zend_declare_property_long(u_int64_value_type, "value", strlen("value"), 0, - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(UInt64Value, __construct) { - init_file_wrappers(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_FIELD_ACCESSORS(UInt64Value, u_int64_value, Value, "value") - -// ----------------------------------------------------------------------------- -// Value -// ----------------------------------------------------------------------------- - -static zend_function_entry value_methods[] = { - PHP_ME(Value, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, getNullValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, setNullValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, getNumberValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, setNumberValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, getStringValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, setStringValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, getBoolValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, setBoolValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, getStructValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, setStructValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, getListValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, setListValue, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Value, getKind, NULL, ZEND_ACC_PUBLIC) - {NULL, NULL, NULL} -}; - -zend_class_entry* value_type; - -// Init class entry. -PHP_PROTO_INIT_SUBMSGCLASS_START("Google\\Protobuf\\Value", - Value, value) - zend_declare_property_null(value_type, "kind", strlen("kind"), - ZEND_ACC_PRIVATE TSRMLS_CC); -PHP_PROTO_INIT_SUBMSGCLASS_END - -PHP_METHOD(Value, __construct) { - init_file_struct(TSRMLS_C); - INIT_MESSAGE_WITH_ARRAY; -} - -PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, NullValue, "null_value") -PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, NumberValue, "number_value") -PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, StringValue, "string_value") -PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, BoolValue, "bool_value") -PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, StructValue, "struct_value") -PHP_PROTO_ONEOF_FIELD_ACCESSORS(Value, value, ListValue, "list_value") -PHP_PROTO_ONEOF_ACCESSORS(Value, value, Kind, "kind") - -// ----------------------------------------------------------------------------- -// GPBMetadata files for well known types -// ----------------------------------------------------------------------------- - -#define DEFINE_GPBMETADATA_FILE(LOWERNAME, CAMELNAME, CLASSNAME) \ - zend_class_entry* gpb_metadata_##LOWERNAME##_type; \ - static zend_function_entry gpb_metadata_##LOWERNAME##_methods[] = { \ - PHP_ME(GPBMetadata_##CAMELNAME, initOnce, NULL, \ - ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) \ - ZEND_FE_END \ - }; \ - void gpb_metadata_##LOWERNAME##_init(TSRMLS_D) { \ - zend_class_entry class_type; \ - INIT_CLASS_ENTRY(class_type, CLASSNAME, \ - gpb_metadata_##LOWERNAME##_methods); \ - gpb_metadata_##LOWERNAME##_type = \ - zend_register_internal_class(&class_type TSRMLS_CC); \ - } \ - PHP_METHOD(GPBMetadata_##CAMELNAME, initOnce) { \ - init_file_##LOWERNAME(TSRMLS_C); \ - } - -DEFINE_GPBMETADATA_FILE(any, Any, "GPBMetadata\\Google\\Protobuf\\Any"); -DEFINE_GPBMETADATA_FILE(api, Api, "GPBMetadata\\Google\\Protobuf\\Api"); -DEFINE_GPBMETADATA_FILE(duration, Duration, - "GPBMetadata\\Google\\Protobuf\\Duration"); -DEFINE_GPBMETADATA_FILE(field_mask, FieldMask, - "GPBMetadata\\Google\\Protobuf\\FieldMask"); -DEFINE_GPBMETADATA_FILE(empty, Empty, - "GPBMetadata\\Google\\Protobuf\\GPBEmpty"); -DEFINE_GPBMETADATA_FILE(source_context, SourceContext, - "GPBMetadata\\Google\\Protobuf\\SourceContext"); -DEFINE_GPBMETADATA_FILE(struct, Struct, - "GPBMetadata\\Google\\Protobuf\\Struct"); -DEFINE_GPBMETADATA_FILE(timestamp, Timestamp, - "GPBMetadata\\Google\\Protobuf\\Timestamp"); -DEFINE_GPBMETADATA_FILE(type, Type, "GPBMetadata\\Google\\Protobuf\\Type"); -DEFINE_GPBMETADATA_FILE(wrappers, Wrappers, - "GPBMetadata\\Google\\Protobuf\\Wrappers"); - -#undef DEFINE_GPBMETADATA_FILE diff --git a/php/ext/google/protobuf2/message.h b/php/ext/google/protobuf/message.h similarity index 100% rename from php/ext/google/protobuf2/message.h rename to php/ext/google/protobuf/message.h diff --git a/php/ext/google/protobuf2/names.c b/php/ext/google/protobuf/names.c similarity index 100% rename from php/ext/google/protobuf2/names.c rename to php/ext/google/protobuf/names.c diff --git a/php/ext/google/protobuf2/names.h b/php/ext/google/protobuf/names.h similarity index 100% rename from php/ext/google/protobuf2/names.h rename to php/ext/google/protobuf/names.h diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index 01a4b86d671d..b8ae8bae7135 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -25,20 +25,26 @@ + + - + + + + + - + + + + + + + - - - - - - diff --git a/php/ext/google/protobuf2/php-upb.c b/php/ext/google/protobuf/php-upb.c similarity index 100% rename from php/ext/google/protobuf2/php-upb.c rename to php/ext/google/protobuf/php-upb.c diff --git a/php/ext/google/protobuf2/php-upb.h b/php/ext/google/protobuf/php-upb.h similarity index 100% rename from php/ext/google/protobuf2/php-upb.h rename to php/ext/google/protobuf/php-upb.h diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c index e9ac93594931..15c8f9bd72e9 100644 --- a/php/ext/google/protobuf/protobuf.c +++ b/php/ext/google/protobuf/protobuf.c @@ -30,481 +30,281 @@ #include "protobuf.h" -#include - -static PHP_GINIT_FUNCTION(protobuf); -static PHP_GSHUTDOWN_FUNCTION(protobuf); -static PHP_RINIT_FUNCTION(protobuf); -static PHP_RSHUTDOWN_FUNCTION(protobuf); -static PHP_MINIT_FUNCTION(protobuf); -static PHP_MSHUTDOWN_FUNCTION(protobuf); - -ZEND_DECLARE_MODULE_GLOBALS(protobuf) - -// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor -// instances. -static HashTable* upb_def_to_php_obj_map; -static upb_inttable upb_def_to_desc_map_persistent; -static upb_inttable upb_def_to_enumdesc_map_persistent; -// Global map from message/enum's php class entry to corresponding wrapper -// Descriptor/EnumDescriptor instances. -static HashTable* ce_to_php_obj_map; -static upb_strtable ce_to_desc_map_persistent; -static upb_strtable ce_to_enumdesc_map_persistent; -// Global map from message/enum's proto fully-qualified name to corresponding -// wrapper Descriptor/EnumDescriptor instances. -static upb_strtable proto_to_desc_map_persistent; -static upb_strtable class_to_desc_map_persistent; - -upb_strtable reserved_names; +#include +#include + +#include "arena.h" +#include "array.h" +#include "bundled_php.h" +#include "convert.h" +#include "def.h" +#include "map.h" +#include "message.h" +#include "names.h" // ----------------------------------------------------------------------------- -// Global maps. +// Module "globals" // ----------------------------------------------------------------------------- -static void add_to_table(HashTable* t, const void* def, void* value) { - zval* pDest = NULL; - php_proto_zend_hash_index_update_mem(t, (zend_ulong)def, &value, - sizeof(zval*), (void**)&pDest); -} +// Despite the name, module "globals" are really thread-locals: +// * PROTOBUF_G(var) accesses the thread-local variable for 'var'. Either: +// * PROTOBUF_G(var) -> protobuf_globals.var (Non-ZTS / non-thread-safe) +// * PROTOBUF_G(var) -> (ZTS / thread-safe builds) -static void* get_from_table(const HashTable* t, const void* def) { - void** value; - if (php_proto_zend_hash_index_find_mem(t, (zend_ulong)def, (void**)&value) == - FAILURE) { - return NULL; - } - return *value; -} +#define PROTOBUF_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(protobuf, v) -void add_def_obj(const void* def, PHP_PROTO_HASHTABLE_VALUE value) { -#if PHP_MAJOR_VERSION < 7 - Z_ADDREF_P(value); -#else - GC_ADDREF(value); -#endif - add_to_table(upb_def_to_php_obj_map, def, value); -} +ZEND_BEGIN_MODULE_GLOBALS(protobuf) + // Set by the user to make the descriptor pool persist between requests. + zend_bool keep_descriptor_pool_after_request; -PHP_PROTO_HASHTABLE_VALUE get_def_obj(const void* def) { - return (PHP_PROTO_HASHTABLE_VALUE)get_from_table(upb_def_to_php_obj_map, def); -} + // Currently we make the generated pool a "global", which means that if a user + // does explicitly create threads within their request, the other threads will + // get different results from DescriptorPool::getGeneratedPool(). We require + // that all descriptors are loaded from the main thread. + zval generated_pool; -void add_msgdef_desc(const upb_msgdef* m, DescriptorInternal* desc) { - upb_inttable_insertptr(&upb_def_to_desc_map_persistent, - m, upb_value_ptr(desc)); -} + // A upb_symtab that we are saving for the next request so that we don't have + // to rebuild it from scratch. When keep_descriptor_pool_after_request==true, + // we steal the upb_symtab from the global DescriptorPool object just before + // destroying it. + upb_symtab *saved_symtab; -DescriptorInternal* get_msgdef_desc(const upb_msgdef* m) { - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_PTR; -#endif - if (!upb_inttable_lookupptr(&upb_def_to_desc_map_persistent, m, &v)) { - return NULL; - } else { - return upb_value_getptr(v); - } -} - -void add_enumdef_enumdesc(const upb_enumdef* e, EnumDescriptorInternal* desc) { - upb_inttable_insertptr(&upb_def_to_enumdesc_map_persistent, - e, upb_value_ptr(desc)); -} - -EnumDescriptorInternal* get_enumdef_enumdesc(const upb_enumdef* e) { - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_PTR; -#endif - if (!upb_inttable_lookupptr(&upb_def_to_enumdesc_map_persistent, e, &v)) { - return NULL; - } else { - return upb_value_getptr(v); - } -} + // Object cache (see interface in protobuf.h). + HashTable object_cache; -void add_ce_obj(const void* ce, PHP_PROTO_HASHTABLE_VALUE value) { -#if PHP_MAJOR_VERSION < 7 - Z_ADDREF_P(value); -#else - GC_ADDREF(value); -#endif - add_to_table(ce_to_php_obj_map, ce, value); -} + // Name cache (see interface in protobuf.h). + HashTable name_msg_cache; + HashTable name_enum_cache; +ZEND_END_MODULE_GLOBALS(protobuf) -PHP_PROTO_HASHTABLE_VALUE get_ce_obj(const void* ce) { - return (PHP_PROTO_HASHTABLE_VALUE)get_from_table(ce_to_php_obj_map, ce); -} +ZEND_DECLARE_MODULE_GLOBALS(protobuf) -void add_ce_desc(const zend_class_entry* ce, DescriptorInternal* desc) { -#if PHP_MAJOR_VERSION < 7 - const char* klass = ce->name; -#else - const char* klass = ZSTR_VAL(ce->name); -#endif - upb_strtable_insert(&ce_to_desc_map_persistent, klass, - upb_value_ptr(desc)); +const zval *get_generated_pool() { + return &PROTOBUF_G(generated_pool); } -DescriptorInternal* get_ce_desc(const zend_class_entry* ce) { -#if PHP_MAJOR_VERSION < 7 - const char* klass = ce->name; -#else - const char* klass = ZSTR_VAL(ce->name); -#endif - - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_PTR; -#endif +// This is a PHP extension (not a Zend extension). What follows is a summary of +// a PHP extension's lifetime and when various handlers are called. +// +// * PHP_GINIT_FUNCTION(protobuf) / PHP_GSHUTDOWN_FUNCTION(protobuf) +// are the constructor/destructor for the globals. The sequence over the +// course of a process lifetime is: +// +// # Process startup +// GINIT(
) +// MINIT +// +// foreach request: +// RINIT +// # Request is processed here. +// RSHUTDOWN +// +// foreach thread: +// GINIT() +// # Code for the thread runs here. +// GSHUTDOWN() +// +// # Process Shutdown +// # +// # These should be running per the docs, but I have not been able to +// # actually get the process-wide shutdown functions to run. +// # +// # MSHUTDOWN +// # GSHUTDOWN(
) +// +// * Threads can be created either explicitly by the user, inside a request, +// or implicitly by the runtime, to process multiple requests concurrently. +// If the latter is being used, then the "foreach thread" block above +// actually looks like this: +// +// foreach thread: +// GINIT() +// # A non-main thread will only receive requests when using a threaded +// # MPM with Apache +// foreach request: +// RINIT +// # Request is processed here. +// RSHUTDOWN +// GSHUTDOWN() +// +// That said, it appears that few people use threads with PHP: +// * The pthread package documented at +// https://www.php.net/manual/en/class.thread.php nas not been released +// since 2016, and the current release fails to compile against any PHP +// newer than 7.0.33. +// * The GitHub master branch supports 7.2+, but this has not been released +// to PECL. +// * Its owner has disavowed it as "broken by design" and "in an untenable +// position for the future": https://github.com/krakjoe/pthreads/issues/929 +// * The only way to use PHP with requests in different threads is to use the +// Apache 2 mod_php with the "worker" MPM. But this is explicitly +// discouraged by the documentation: https://serverfault.com/a/231660 - if (!upb_strtable_lookup(&ce_to_desc_map_persistent, klass, &v)) { - return NULL; - } else { - return upb_value_getptr(v); +static PHP_GSHUTDOWN_FUNCTION(protobuf) { + if (protobuf_globals->saved_symtab) { + upb_symtab_free(protobuf_globals->saved_symtab); } } -void add_ce_enumdesc(const zend_class_entry* ce, EnumDescriptorInternal* desc) { -#if PHP_MAJOR_VERSION < 7 - const char* klass = ce->name; -#else - const char* klass = ZSTR_VAL(ce->name); -#endif - upb_strtable_insert(&ce_to_enumdesc_map_persistent, klass, - upb_value_ptr(desc)); -} - -EnumDescriptorInternal* get_ce_enumdesc(const zend_class_entry* ce) { -#if PHP_MAJOR_VERSION < 7 - const char* klass = ce->name; -#else - const char* klass = ZSTR_VAL(ce->name); -#endif - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_PTR; -#endif - if (!upb_strtable_lookup(&ce_to_enumdesc_map_persistent, klass, &v)) { - return NULL; - } else { - return upb_value_getptr(v); - } +static PHP_GINIT_FUNCTION(protobuf) { + ZVAL_NULL(&protobuf_globals->generated_pool); + protobuf_globals->saved_symtab = NULL; } -bool class_added(const void* ce) { - return get_ce_desc(ce) != NULL; -} +/** + * PHP_RINIT_FUNCTION(protobuf) + * + * This function is run at the beginning of processing each request. + */ +static PHP_RINIT_FUNCTION(protobuf) { + // Create the global generated pool. + // Reuse the symtab (if any) left to us by the last request. + upb_symtab *symtab = PROTOBUF_G(saved_symtab); + DescriptorPool_CreateWithSymbolTable(&PROTOBUF_G(generated_pool), symtab); -void add_proto_desc(const char* proto, DescriptorInternal* desc) { - upb_strtable_insert(&proto_to_desc_map_persistent, proto, - upb_value_ptr(desc)); -} + // Set up autoloader for bundled sources. + zend_eval_string("spl_autoload_register('protobuf_internal_loadbundled');", + NULL, "autoload_register.php"); -DescriptorInternal* get_proto_desc(const char* proto) { - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_PTR; -#endif - if (!upb_strtable_lookup(&proto_to_desc_map_persistent, proto, &v)) { - return NULL; - } else { - return upb_value_getptr(v); - } -} + zend_hash_init(&PROTOBUF_G(object_cache), 64, NULL, NULL, 0); + zend_hash_init(&PROTOBUF_G(name_msg_cache), 64, NULL, NULL, 0); + zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0); -void add_class_desc(const char* klass, DescriptorInternal* desc) { - upb_strtable_insert(&class_to_desc_map_persistent, klass, - upb_value_ptr(desc)); + return SUCCESS; } -DescriptorInternal* get_class_desc(const char* klass) { - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_PTR; -#endif - if (!upb_strtable_lookup(&class_to_desc_map_persistent, klass, &v)) { - return NULL; - } else { - return upb_value_getptr(v); +/** + * PHP_RSHUTDOWN_FUNCTION(protobuf) + * + * This function is run at the end of processing each request. + */ +static PHP_RSHUTDOWN_FUNCTION(protobuf) { + // Preserve the symtab if requested. + if (PROTOBUF_G(keep_descriptor_pool_after_request)) { + zval *zv = &PROTOBUF_G(generated_pool); + PROTOBUF_G(saved_symtab) = DescriptorPool_Steal(zv); } -} -void add_class_enumdesc(const char* klass, EnumDescriptorInternal* desc) { - upb_strtable_insert(&class_to_desc_map_persistent, klass, - upb_value_ptr(desc)); -} + zval_dtor(&PROTOBUF_G(generated_pool)); + zend_hash_destroy(&PROTOBUF_G(object_cache)); + zend_hash_destroy(&PROTOBUF_G(name_msg_cache)); + zend_hash_destroy(&PROTOBUF_G(name_enum_cache)); -EnumDescriptorInternal* get_class_enumdesc(const char* klass) { - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_PTR; -#endif - if (!upb_strtable_lookup(&class_to_desc_map_persistent, klass, &v)) { - return NULL; - } else { - return upb_value_getptr(v); - } + return SUCCESS; } // ----------------------------------------------------------------------------- -// Well Known Types. +// Bundled PHP sources // ----------------------------------------------------------------------------- -bool is_inited_file_any; -bool is_inited_file_api; -bool is_inited_file_duration; -bool is_inited_file_field_mask; -bool is_inited_file_empty; -bool is_inited_file_source_context; -bool is_inited_file_struct; -bool is_inited_file_timestamp; -bool is_inited_file_type; -bool is_inited_file_wrappers; +// We bundle PHP sources for well-known types into the C extension. There is no +// need to implement these in C. -// ----------------------------------------------------------------------------- -// Reserved Name. -// ----------------------------------------------------------------------------- +static PHP_FUNCTION(protobuf_internal_loadbundled) { + char *name = NULL; + zend_long size; + BundledPhp_File *file; -// Although we already have kReservedNames, we still add them to hash table to -// speed up look up. -const char *const kReservedNames[] = { - "abstract", "and", "array", "as", "break", - "callable", "case", "catch", "class", "clone", - "const", "continue", "declare", "default", "die", - "do", "echo", "else", "elseif", "empty", - "enddeclare", "endfor", "endforeach", "endif", "endswitch", - "endwhile", "eval", "exit", "extends", "final", - "for", "foreach", "function", "global", "goto", - "if", "implements", "include", "include_once", "instanceof", - "insteadof", "interface", "isset", "list", "namespace", - "new", "or", "print", "private", "protected", - "public", "require", "require_once", "return", "static", - "switch", "throw", "trait", "try", "unset", - "use", "var", "while", "xor", "int", - "float", "bool", "string", "true", "false", - "null", "void", "iterable"}; -const int kReservedNamesSize = 73; - -bool is_reserved_name(const char* name) { - upb_value v; -#ifndef NDEBUG - v.ctype = UPB_CTYPE_UINT64; -#endif - return upb_strtable_lookup2(&reserved_names, name, strlen(name), &v); + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &size) != SUCCESS) { + return; + } + + for (file = bundled_files; file->filename; file++) { + if (strcmp(file->filename, name) == 0) { + zend_eval_string((char*)file->contents, NULL, (char*)file->filename); + return; + } + } } +ZEND_BEGIN_ARG_INFO_EX(arginfo_load_bundled_source, 0, 0, 1) + ZEND_ARG_INFO(0, class_name) +ZEND_END_ARG_INFO() + // ----------------------------------------------------------------------------- -// Utilities. +// Object Cache. // ----------------------------------------------------------------------------- -zend_function_entry protobuf_functions[] = { - ZEND_FE_END -}; - -static const zend_module_dep protobuf_deps[] = { - ZEND_MOD_OPTIONAL("date") - ZEND_MOD_END -}; - -zend_module_entry protobuf_module_entry = { - STANDARD_MODULE_HEADER_EX, - NULL, - protobuf_deps, - PHP_PROTOBUF_EXTNAME, // extension name - protobuf_functions, // function list - PHP_MINIT(protobuf), // process startup - PHP_MSHUTDOWN(protobuf), // process shutdown - PHP_RINIT(protobuf), // request shutdown - PHP_RSHUTDOWN(protobuf), // request shutdown - NULL, // extension info - PHP_PROTOBUF_VERSION, // extension version - PHP_MODULE_GLOBALS(protobuf), // globals descriptor - PHP_GINIT(protobuf), // globals ctor - PHP_GSHUTDOWN(protobuf), // globals dtor - NULL, // post deactivate - STANDARD_MODULE_PROPERTIES_EX -}; - -// install module -ZEND_GET_MODULE(protobuf) - -// global variables -static PHP_GINIT_FUNCTION(protobuf) { +void ObjCache_Add(const void *upb_obj, zend_object *php_obj) { + zend_ulong k = (zend_ulong)upb_obj; + zend_hash_index_add_ptr(&PROTOBUF_G(object_cache), k, php_obj); } -static PHP_GSHUTDOWN_FUNCTION(protobuf) { -} - -#if PHP_MAJOR_VERSION >= 7 -static void php_proto_hashtable_descriptor_release(zval* value) { - void* ptr = Z_PTR_P(value); - zend_object* object = *(zend_object**)ptr; - GC_DELREF(object); - if(GC_REFCOUNT(object) == 0) { - zend_objects_store_del(object); +void ObjCache_Delete(const void *upb_obj) { + if (upb_obj) { + zend_ulong k = (zend_ulong)upb_obj; + int ret = zend_hash_index_del(&PROTOBUF_G(object_cache), k); + PBPHP_ASSERT(ret == SUCCESS); } - efree(ptr); -} -#endif - -static void initialize_persistent_descriptor_pool(TSRMLS_D) { - upb_inttable_init(&upb_def_to_desc_map_persistent, UPB_CTYPE_PTR); - upb_inttable_init(&upb_def_to_enumdesc_map_persistent, UPB_CTYPE_PTR); - upb_strtable_init(&ce_to_desc_map_persistent, UPB_CTYPE_PTR); - upb_strtable_init(&ce_to_enumdesc_map_persistent, UPB_CTYPE_PTR); - upb_strtable_init(&proto_to_desc_map_persistent, UPB_CTYPE_PTR); - upb_strtable_init(&class_to_desc_map_persistent, UPB_CTYPE_PTR); - - internal_descriptor_pool_impl_init(&generated_pool_impl TSRMLS_CC); - - is_inited_file_any = false; - is_inited_file_api = false; - is_inited_file_duration = false; - is_inited_file_field_mask = false; - is_inited_file_empty = false; - is_inited_file_source_context = false; - is_inited_file_struct = false; - is_inited_file_timestamp = false; - is_inited_file_type = false; - is_inited_file_wrappers = false; } -static PHP_RINIT_FUNCTION(protobuf) { - ALLOC_HASHTABLE(upb_def_to_php_obj_map); - zend_hash_init(upb_def_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0); - - ALLOC_HASHTABLE(ce_to_php_obj_map); - zend_hash_init(ce_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0); - - generated_pool = NULL; - generated_pool_php = NULL; - internal_generated_pool_php = NULL; - - if (PROTOBUF_G(keep_descriptor_pool_after_request)) { - // Needs to clean up obsolete class entry - upb_strtable_iter i; - upb_value v; - - DescriptorInternal* desc; - for(upb_strtable_begin(&i, &ce_to_desc_map_persistent); - !upb_strtable_done(&i); - upb_strtable_next(&i)) { - v = upb_strtable_iter_value(&i); - desc = upb_value_getptr(v); - desc->klass = NULL; - } +bool ObjCache_Get(const void *upb_obj, zval *val) { + zend_ulong k = (zend_ulong)upb_obj; + zend_object *obj = zend_hash_index_find_ptr(&PROTOBUF_G(object_cache), k); - EnumDescriptorInternal* enumdesc; - for(upb_strtable_begin(&i, &ce_to_enumdesc_map_persistent); - !upb_strtable_done(&i); - upb_strtable_next(&i)) { - v = upb_strtable_iter_value(&i); - enumdesc = upb_value_getptr(v); - enumdesc->klass = NULL; - } + if (obj) { + GC_ADDREF(obj); + ZVAL_OBJ(val, obj); + return true; } else { - initialize_persistent_descriptor_pool(TSRMLS_C); + ZVAL_NULL(val); + return false; } - - return 0; } -static void cleanup_desc_table(upb_inttable* t) { - upb_inttable_iter i; - upb_value v; - DescriptorInternal* desc; - for(upb_inttable_begin(&i, t); - !upb_inttable_done(&i); - upb_inttable_next(&i)) { - v = upb_inttable_iter_value(&i); - desc = upb_value_getptr(v); - if (desc->layout) { - free_layout(desc->layout); - desc->layout = NULL; - } - free(desc->classname); - SYS_FREE(desc); - } -} +// ----------------------------------------------------------------------------- +// Name Cache. +// ----------------------------------------------------------------------------- -static void cleanup_enumdesc_table(upb_inttable* t) { - upb_inttable_iter i; - upb_value v; - EnumDescriptorInternal* desc; - for(upb_inttable_begin(&i, t); - !upb_inttable_done(&i); - upb_inttable_next(&i)) { - v = upb_inttable_iter_value(&i); - desc = upb_value_getptr(v); - free(desc->classname); - SYS_FREE(desc); - } +void NameMap_AddMessage(const upb_msgdef *m) { + char *k = GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m)); + zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m); + free(k); } -static void cleanup_persistent_descriptor_pool(TSRMLS_D) { - // Clean up - - // Only needs to clean one map out of three (def=>desc, ce=>desc, proto=>desc) - cleanup_desc_table(&upb_def_to_desc_map_persistent); - cleanup_enumdesc_table(&upb_def_to_enumdesc_map_persistent); - - internal_descriptor_pool_impl_destroy(&generated_pool_impl TSRMLS_CC); - - upb_inttable_uninit(&upb_def_to_desc_map_persistent); - upb_inttable_uninit(&upb_def_to_enumdesc_map_persistent); - upb_strtable_uninit(&ce_to_desc_map_persistent); - upb_strtable_uninit(&ce_to_enumdesc_map_persistent); - upb_strtable_uninit(&proto_to_desc_map_persistent); - upb_strtable_uninit(&class_to_desc_map_persistent); +void NameMap_AddEnum(const upb_enumdef *e) { + char *k = GetPhpClassname(upb_enumdef_file(e), upb_enumdef_fullname(e)); + zend_hash_str_add_ptr(&PROTOBUF_G(name_enum_cache), k, strlen(k), (void*)e); + free(k); } -static PHP_RSHUTDOWN_FUNCTION(protobuf) { - zend_hash_destroy(upb_def_to_php_obj_map); - FREE_HASHTABLE(upb_def_to_php_obj_map); - - zend_hash_destroy(ce_to_php_obj_map); - FREE_HASHTABLE(ce_to_php_obj_map); +const upb_msgdef *NameMap_GetMessage(zend_class_entry *ce) { + const upb_msgdef *ret = + zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name); -#if PHP_MAJOR_VERSION < 7 - if (generated_pool_php != NULL) { - zval_dtor(generated_pool_php); - FREE_ZVAL(generated_pool_php); - } - if (internal_generated_pool_php != NULL) { - zval_dtor(internal_generated_pool_php); - FREE_ZVAL(internal_generated_pool_php); - } -#else - if (generated_pool_php != NULL) { + if (!ret && ce->create_object) { zval tmp; - ZVAL_OBJ(&tmp, generated_pool_php); - zval_dtor(&tmp); - } - if (internal_generated_pool_php != NULL) { - zval tmp; - ZVAL_OBJ(&tmp, internal_generated_pool_php); - zval_dtor(&tmp); - } -#endif - - if (!PROTOBUF_G(keep_descriptor_pool_after_request)) { - cleanup_persistent_descriptor_pool(TSRMLS_C); + zval zv; + ZVAL_OBJ(&tmp, ce->create_object(ce)); + zend_call_method_with_0_params(&tmp, ce, NULL, "__construct", &zv); + zval_ptr_dtor(&tmp); + zval_ptr_dtor(&zv); + ret = zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name); } - return 0; + return ret; } -static void reserved_names_init() { - size_t i; - upb_value v = upb_value_bool(false); - for (i = 0; i < kReservedNamesSize; i++) { - upb_strtable_insert2(&reserved_names, kReservedNames[i], - strlen(kReservedNames[i]), v); - } +const upb_enumdef *NameMap_GetEnum(zend_class_entry *ce) { + const upb_enumdef *ret = + zend_hash_find_ptr(&PROTOBUF_G(name_enum_cache), ce->name); + return ret; } +// ----------------------------------------------------------------------------- +// Module init. +// ----------------------------------------------------------------------------- + +zend_function_entry protobuf_functions[] = { + PHP_FE(protobuf_internal_loadbundled, arginfo_load_bundled_source) + ZEND_FE_END +}; + +static const zend_module_dep protobuf_deps[] = { + ZEND_MOD_OPTIONAL("date") + ZEND_MOD_END +}; + PHP_INI_BEGIN() STD_PHP_INI_ENTRY("protobuf.keep_descriptor_pool_after_request", "0", PHP_INI_SYSTEM, OnUpdateBool, @@ -514,86 +314,36 @@ PHP_INI_END() static PHP_MINIT_FUNCTION(protobuf) { REGISTER_INI_ENTRIES(); - - upb_strtable_init(&reserved_names, UPB_CTYPE_UINT64); - reserved_names_init(); - - if (PROTOBUF_G(keep_descriptor_pool_after_request)) { - initialize_persistent_descriptor_pool(TSRMLS_C); - } - - descriptor_pool_init(TSRMLS_C); - descriptor_init(TSRMLS_C); - enum_descriptor_init(TSRMLS_C); - enum_value_descriptor_init(TSRMLS_C); - field_descriptor_init(TSRMLS_C); - gpb_type_init(TSRMLS_C); - internal_descriptor_pool_init(TSRMLS_C); - map_field_init(TSRMLS_C); - map_field_iter_init(TSRMLS_C); - message_init(TSRMLS_C); - oneof_descriptor_init(TSRMLS_C); - repeated_field_init(TSRMLS_C); - repeated_field_iter_init(TSRMLS_C); - util_init(TSRMLS_C); - - gpb_metadata_any_init(TSRMLS_C); - gpb_metadata_api_init(TSRMLS_C); - gpb_metadata_duration_init(TSRMLS_C); - gpb_metadata_field_mask_init(TSRMLS_C); - gpb_metadata_empty_init(TSRMLS_C); - gpb_metadata_source_context_init(TSRMLS_C); - gpb_metadata_struct_init(TSRMLS_C); - gpb_metadata_timestamp_init(TSRMLS_C); - gpb_metadata_type_init(TSRMLS_C); - gpb_metadata_wrappers_init(TSRMLS_C); - - any_init(TSRMLS_C); - api_init(TSRMLS_C); - bool_value_init(TSRMLS_C); - bytes_value_init(TSRMLS_C); - double_value_init(TSRMLS_C); - duration_init(TSRMLS_C); - enum_init(TSRMLS_C); - enum_value_init(TSRMLS_C); - field_cardinality_init(TSRMLS_C); - field_init(TSRMLS_C); - field_kind_init(TSRMLS_C); - field_mask_init(TSRMLS_C); - float_value_init(TSRMLS_C); - empty_init(TSRMLS_C); - int32_value_init(TSRMLS_C); - int64_value_init(TSRMLS_C); - list_value_init(TSRMLS_C); - method_init(TSRMLS_C); - mixin_init(TSRMLS_C); - null_value_init(TSRMLS_C); - option_init(TSRMLS_C); - source_context_init(TSRMLS_C); - string_value_init(TSRMLS_C); - struct_init(TSRMLS_C); - syntax_init(TSRMLS_C); - timestamp_init(TSRMLS_C); - type_init(TSRMLS_C); - u_int32_value_init(TSRMLS_C); - u_int64_value_init(TSRMLS_C); - value_init(TSRMLS_C); - - return 0; + Arena_ModuleInit(); + Array_ModuleInit(); + Convert_ModuleInit(); + Def_ModuleInit(); + Map_ModuleInit(); + Message_ModuleInit(); + return SUCCESS; } static PHP_MSHUTDOWN_FUNCTION(protobuf) { - if (PROTOBUF_G(keep_descriptor_pool_after_request)) { - cleanup_persistent_descriptor_pool(TSRMLS_C); - } - - upb_strtable_uninit(&reserved_names); + return SUCCESS; +} - PEFREE(message_handlers); - PEFREE(repeated_field_handlers); - PEFREE(repeated_field_iter_handlers); - PEFREE(map_field_handlers); - PEFREE(map_field_iter_handlers); +zend_module_entry protobuf_module_entry = { + STANDARD_MODULE_HEADER_EX, + NULL, + protobuf_deps, + "protobuf", // extension name + protobuf_functions, // function list + PHP_MINIT(protobuf), // process startup + PHP_MSHUTDOWN(protobuf), // process shutdown + PHP_RINIT(protobuf), // request shutdown + PHP_RSHUTDOWN(protobuf), // request shutdown + NULL, // extension info + "3.13.0", // extension version + PHP_MODULE_GLOBALS(protobuf), // globals descriptor + PHP_GINIT(protobuf), // globals ctor + PHP_GSHUTDOWN(protobuf), // globals dtor + NULL, // post deactivate + STANDARD_MODULE_PROPERTIES_EX +}; - return 0; -} +ZEND_GET_MODULE(protobuf) diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index 520888733f26..6a7afae0619a 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -28,1556 +28,62 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ -#define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ +#ifndef PHP_PROTOBUF_H_ +#define PHP_PROTOBUF_H_ #include +#include -// ubp.h has to be placed after php.h. Othwise, php.h will introduce NDEBUG. -#include "upb.h" +#include "php-upb.h" -#define PHP_PROTOBUF_EXTNAME "protobuf" -#define PHP_PROTOBUF_VERSION "3.12.3" - -#define MAX_LENGTH_OF_INT64 20 -#define SIZEOF_INT64 8 - -/* From Chromium. */ -#define ARRAY_SIZE(x) \ - ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) - -#define PHP_PROTO_UNUSED(var) (void)var -/* PHP_PROTO_ASSERT(): in release mode, we use the expression without letting - * it be evaluated. This prevents "unused variable" warnings. */ -#ifdef NDEBUG -#define PHP_PROTO_ASSERT(expr) do {} while (false && (expr)) -#else -#define PHP_PROTO_ASSERT(expr) assert(expr) -#endif - -// ----------------------------------------------------------------------------- -// PHP7 Wrappers -// ---------------------------------------------------------------------------- +const zval *get_generated_pool(); #if PHP_VERSION_ID < 70300 #define GC_ADDREF(h) ++GC_REFCOUNT(h) #define GC_DELREF(h) --GC_REFCOUNT(h) #endif -#if PHP_MAJOR_VERSION < 7 - -#define php_proto_zend_literal const zend_literal* -#define PHP_PROTO_CASE_IS_BOOL IS_BOOL -#define PHP_PROTO_SIZE int -#define PHP_PROTO_LONG long -#define PHP_PROTO_TSRMLS_DC TSRMLS_DC -#define PHP_PROTO_TSRMLS_CC TSRMLS_CC - -// PHP String - -#define PHP_PROTO_ZVAL_STRING(zval_ptr, s, copy) \ - ZVAL_STRING(zval_ptr, s, copy) -#define PHP_PROTO_ZVAL_STRINGL(zval_ptr, s, len, copy) \ - ZVAL_STRINGL(zval_ptr, s, len, copy) -#define PHP_PROTO_RETURN_STRING(s, copy) RETURN_STRING(s, copy) -#define PHP_PROTO_RETURN_STRINGL(s, len, copy) RETURN_STRINGL(s, len, copy) -#define PHP_PROTO_RETVAL_STRINGL(s, len, copy) RETVAL_STRINGL(s, len, copy) -#define php_proto_zend_make_printable_zval(from, to) \ - { \ - int use_copy; \ - zend_make_printable_zval(from, to, &use_copy); \ - } - -// PHP Array - -#define PHP_PROTO_HASH_OF(array) Z_ARRVAL_P(array) - -#define php_proto_zend_hash_index_update_zval(ht, h, pData) \ - zend_hash_index_update(ht, h, &(pData), sizeof(void*), NULL) - -#define php_proto_zend_hash_update_zval(ht, key, key_len, value) \ - zend_hash_update(ht, key, key_len, value, sizeof(void*), NULL) - -#define php_proto_zend_hash_update(ht, key, key_len) \ - zend_hash_update(ht, key, key_len, 0, 0, NULL) - -#define php_proto_zend_hash_index_update_mem(ht, h, pData, nDataSize, pDest) \ - zend_hash_index_update(ht, h, pData, nDataSize, pDest) - -#define php_proto_zend_hash_update_mem(ht, key, key_len, pData, nDataSize, \ - pDest) \ - zend_hash_update(ht, key, key_len, pData, nDataSize, pDest) - -#define php_proto_zend_hash_index_find_zval(ht, h, pDest) \ - zend_hash_index_find(ht, h, pDest) - -#define php_proto_zend_hash_find(ht, key, key_len, pDest) \ - zend_hash_find(ht, key, key_len, pDest) - -#define php_proto_zend_hash_index_find_mem(ht, h, pDest) \ - zend_hash_index_find(ht, h, pDest) - -#define php_proto_zend_hash_find_zval(ht, key, key_len, pDest) \ - zend_hash_find(ht, key, key_len, pDest) - -#define php_proto_zend_hash_find_mem(ht, key, key_len, pDest) \ - zend_hash_find(ht, key, key_len, pDest) - -#define php_proto_zend_hash_next_index_insert_zval(ht, pData) \ - zend_hash_next_index_insert(ht, pData, sizeof(void*), NULL) - -#define php_proto_zend_hash_next_index_insert_mem(ht, pData, nDataSize, pDest) \ - zend_hash_next_index_insert(ht, pData, nDataSize, pDest) - -#define php_proto_zend_hash_get_current_data_ex(ht, pDest, pos) \ - zend_hash_get_current_data_ex(ht, pDest, pos) - -// PHP Object - -#define PHP_PROTO_WRAP_OBJECT_START(name) \ - struct name { \ - zend_object std; -#define PHP_PROTO_WRAP_OBJECT_END \ - }; - -#define PHP_PROTO_INIT_SUBMSGCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \ - void LOWWERNAME##_init(TSRMLS_D) { \ - zend_class_entry class_type; \ - INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \ - LOWWERNAME##_methods); \ - LOWWERNAME##_type = zend_register_internal_class_ex( \ - &class_type, message_type, NULL TSRMLS_CC); \ - LOWWERNAME##_type->create_object = message_create; \ - zend_do_inheritance(LOWWERNAME##_type, message_type TSRMLS_CC); -#define PHP_PROTO_INIT_SUBMSGCLASS_END \ - } - -#define PHP_PROTO_INIT_ENUMCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \ - void LOWWERNAME##_init(TSRMLS_D) { \ - zend_class_entry class_type; \ - INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \ - LOWWERNAME##_methods); \ - LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); -#define PHP_PROTO_INIT_ENUMCLASS_END \ - } - -#define PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \ - void LOWWERNAME##_init(TSRMLS_D) { \ - zend_class_entry class_type; \ - INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \ - LOWWERNAME##_methods); \ - LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \ - LOWWERNAME##_type->create_object = LOWWERNAME##_create; \ - LOWWERNAME##_handlers = PEMALLOC(zend_object_handlers, 1); \ - memcpy(LOWWERNAME##_handlers, zend_get_std_object_handlers(), \ - sizeof(zend_object_handlers)); -#define PHP_PROTO_INIT_CLASS_END \ - } - -#define PHP_PROTO_OBJECT_CREATE_START(NAME, LOWWERNAME) \ - static zend_object_value LOWWERNAME##_create( \ - zend_class_entry* ce TSRMLS_DC) { \ - PHP_PROTO_ALLOC_CLASS_OBJECT(NAME, ce); \ - zend_object_std_init(&intern->std, ce TSRMLS_CC); \ - object_properties_init(&intern->std, ce); -#define PHP_PROTO_OBJECT_CREATE_END(NAME, LOWWERNAME) \ - PHP_PROTO_FREE_CLASS_OBJECT(NAME, LOWWERNAME##_free, LOWWERNAME##_handlers); \ - } - -#define PHP_PROTO_OBJECT_EMPTY_FREE_START(classname, lowername) \ - void lowername##_free(void* object TSRMLS_DC) { \ - classname* intern = object; -#define PHP_PROTO_OBJECT_FREE_START(classname, lowername) \ - void lowername##_free(void* object TSRMLS_DC) { \ - classname* intern = object; -#define PHP_PROTO_OBJECT_FREE_END \ - zend_object_std_dtor(&intern->std TSRMLS_CC); \ - efree(intern); \ - } - -#define PHP_PROTO_OBJECT_EMPTY_DTOR_START(classname, lowername) -#define PHP_PROTO_OBJECT_DTOR_START(classname, lowername) -#define PHP_PROTO_OBJECT_DTOR_END - -#define CACHED_VALUE zval* -#define CACHED_TO_ZVAL_PTR(VALUE) (VALUE) -#define CACHED_PTR_TO_ZVAL_PTR(VALUE) (*(CACHED_VALUE*)(VALUE)) -#define ZVAL_PTR_TO_CACHED_PTR(VALUE) (&VALUE) -#define ZVAL_PTR_TO_CACHED_VALUE(VALUE) (VALUE) -#define ZVAL_TO_CACHED_VALUE(VALUE) (&VALUE) - -#define CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(zval_ptr, class_type) \ - ZVAL_OBJ(zval_ptr, class_type->create_object(class_type TSRMLS_CC)); - -#define PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(value) \ - SEPARATE_ZVAL_IF_NOT_REF(value) - -#define PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL EG(uninitialized_zval_ptr) - -#define OBJ_PROP(OBJECT, OFFSET) &((OBJECT)->properties_table[OFFSET]) - -#define php_proto_zval_ptr_dtor(zval_ptr) \ - zval_ptr_dtor(&(zval_ptr)) - -#define PHP_PROTO_ALLOC_CLASS_OBJECT(class_object, class_type) \ - class_object* intern; \ - intern = (class_object*)emalloc(sizeof(class_object)); \ - memset(intern, 0, sizeof(class_object)); - -#define PHP_PROTO_FREE_CLASS_OBJECT(class_object, class_object_free, handler) \ - zend_object_value retval = {0}; \ - retval.handle = zend_objects_store_put( \ - intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ - class_object_free, NULL TSRMLS_CC); \ - retval.handlers = handler; \ - return retval; - -#define PHP_PROTO_ALLOC_ARRAY(zval_ptr) \ - ALLOC_HASHTABLE(Z_ARRVAL_P(zval_ptr)); \ - Z_TYPE_P(zval_ptr) = IS_ARRAY; - -#define ZVAL_OBJ(zval_ptr, call_create) \ - Z_TYPE_P(zval_ptr) = IS_OBJECT; \ - Z_OBJVAL_P(zval_ptr) = call_create; - -#define UNBOX(class_name, val) \ - (class_name*)zend_object_store_get_object(val TSRMLS_CC); - -#define UNBOX_HASHTABLE_VALUE(class_name, val) UNBOX(class_name, val) - -#define HASHTABLE_VALUE_DTOR ZVAL_PTR_DTOR - -#define PHP_PROTO_HASHTABLE_VALUE zval* -#define HASHTABLE_VALUE_CE(val) Z_OBJCE_P(val) - -#define CREATE_HASHTABLE_VALUE(OBJ, WRAPPED_OBJ, OBJ_TYPE, OBJ_CLASS_ENTRY) \ - OBJ_TYPE* OBJ; \ - PHP_PROTO_HASHTABLE_VALUE WRAPPED_OBJ; \ - MAKE_STD_ZVAL(WRAPPED_OBJ); \ - ZVAL_OBJ(WRAPPED_OBJ, \ - OBJ_CLASS_ENTRY->create_object(OBJ_CLASS_ENTRY TSRMLS_CC)); \ - OBJ = UNBOX_HASHTABLE_VALUE(OBJ_TYPE, WRAPPED_OBJ); \ - Z_DELREF_P(desc_php); - -#define PHP_PROTO_CE_DECLARE zend_class_entry** -#define PHP_PROTO_CE_UNREF(ce) (*ce) - -#define php_proto_zend_lookup_class(name, name_length, ce) \ - zend_lookup_class(name, name_length, ce TSRMLS_CC) - -#define PHP_PROTO_RETVAL_ZVAL(value) ZVAL_ZVAL(return_value, value, 1, 0) - -#else // PHP_MAJOR_VERSION >= 7 - -#define php_proto_zend_literal void** -#define PHP_PROTO_CASE_IS_BOOL IS_TRUE: case IS_FALSE -#define PHP_PROTO_SIZE size_t -#define PHP_PROTO_LONG zend_long -#define PHP_PROTO_TSRMLS_DC -#define PHP_PROTO_TSRMLS_CC - -// PHP String - -#define PHP_PROTO_ZVAL_STRING(zval_ptr, s, copy) \ - ZVAL_STRING(zval_ptr, s) -#define PHP_PROTO_ZVAL_STRINGL(zval_ptr, s, len, copy) \ - ZVAL_STRINGL(zval_ptr, s, len) -#define PHP_PROTO_RETURN_STRING(s, copy) RETURN_STRING(s) -#define PHP_PROTO_RETURN_STRINGL(s, len, copy) RETURN_STRINGL(s, len) -#define PHP_PROTO_RETVAL_STRINGL(s, len, copy) RETVAL_STRINGL(s, len) -#define php_proto_zend_make_printable_zval(from, to) \ - zend_make_printable_zval(from, to) - -// PHP Array - -#define PHP_PROTO_HASH_OF(array) Z_ARRVAL_P(&array) - -static inline int php_proto_zend_hash_index_update_zval(HashTable* ht, zend_ulong h, - zval* pData) { - void* result = NULL; - result = zend_hash_index_update(ht, h, pData); - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_update(HashTable* ht, const char* key, - size_t key_len) { - void* result = NULL; - zval temp; - ZVAL_LONG(&temp, 0); - result = zend_hash_str_update(ht, key, key_len, &temp); - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_index_update_mem(HashTable* ht, zend_ulong h, - void* pData, uint nDataSize, - void** pDest) { - void* result = NULL; - result = zend_hash_index_update_mem(ht, h, pData, nDataSize); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_update_zval(HashTable* ht, - const char* key, uint key_len, - zval* pData) { - void* result = NULL; - zend_string* internal_key = zend_string_init(key, key_len, 0); - result = zend_hash_update(ht, internal_key, pData); - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_update_mem(HashTable* ht, const char* key, - uint key_len, void* pData, - uint nDataSize, void** pDest) { - zend_string* internal_key = zend_string_init(key, key_len, 0); - void* result = zend_hash_update_mem(ht, internal_key, pData, nDataSize); - zend_string_release(internal_key); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_index_find_zval(const HashTable* ht, - zend_ulong h, void** pDest) { - zval* result = zend_hash_index_find(ht, h); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_find(const HashTable* ht, const char* key, - size_t key_len, void** pDest) { - void* result = NULL; - result = zend_hash_str_find(ht, key, key_len); - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_index_find_mem(const HashTable* ht, - zend_ulong h, void** pDest) { - void* result = NULL; - result = zend_hash_index_find_ptr(ht, h); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_find_zval(const HashTable* ht, - const char* key, uint key_len, - void** pDest) { - zend_string* internal_key = zend_string_init(key, key_len, 1); - zval* result = zend_hash_find(ht, internal_key); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_find_mem(const HashTable* ht, - const char* key, uint key_len, - void** pDest) { - zend_string* internal_key = zend_string_init(key, key_len, 1); - void* result = zend_hash_find_ptr(ht, internal_key); - zend_string_release(internal_key); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_next_index_insert_zval(HashTable* ht, - void* pData) { - zval tmp; - ZVAL_OBJ(&tmp, *(zend_object**)pData); - zval* result = zend_hash_next_index_insert(ht, &tmp); - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_next_index_insert_mem(HashTable* ht, - void* pData, - uint nDataSize, - void** pDest) { - void* result = NULL; - result = zend_hash_next_index_insert_mem(ht, pData, nDataSize); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -static inline int php_proto_zend_hash_get_current_data_ex(HashTable* ht, - void** pDest, - HashPosition* pos) { - void* result = NULL; - result = zend_hash_get_current_data_ex(ht, pos); - if (pDest != NULL) *pDest = result; - return result != NULL ? SUCCESS : FAILURE; -} - -// PHP Object - -#define PHP_PROTO_WRAP_OBJECT_START(name) struct name { -#define PHP_PROTO_WRAP_OBJECT_END \ - zend_object std; \ - }; - -#define PHP_PROTO_INIT_SUBMSGCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \ - void LOWWERNAME##_init(TSRMLS_D) { \ - zend_class_entry class_type; \ - INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \ - LOWWERNAME##_methods); \ - LOWWERNAME##_type = zend_register_internal_class(&class_type); \ - zend_do_inheritance(LOWWERNAME##_type, message_type); -#define PHP_PROTO_INIT_SUBMSGCLASS_END \ - } - -#define PHP_PROTO_INIT_ENUMCLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \ - void LOWWERNAME##_init(TSRMLS_D) { \ - zend_class_entry class_type; \ - INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \ - LOWWERNAME##_methods); \ - LOWWERNAME##_type = zend_register_internal_class(&class_type); -#define PHP_PROTO_INIT_ENUMCLASS_END \ - } - -#define PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \ - void LOWWERNAME##_init(TSRMLS_D) { \ - zend_class_entry class_type; \ - INIT_CLASS_ENTRY_EX(class_type, CLASSNAME, strlen(CLASSNAME), \ - LOWWERNAME##_methods); \ - LOWWERNAME##_type = zend_register_internal_class(&class_type TSRMLS_CC); \ - LOWWERNAME##_type->create_object = LOWWERNAME##_create; \ - LOWWERNAME##_handlers = PEMALLOC(zend_object_handlers, 1); \ - memcpy(LOWWERNAME##_handlers, zend_get_std_object_handlers(), \ - sizeof(zend_object_handlers)); \ - LOWWERNAME##_handlers->free_obj = LOWWERNAME##_free; \ - LOWWERNAME##_handlers->dtor_obj = LOWWERNAME##_dtor; \ - LOWWERNAME##_handlers->offset = XtOffsetOf(CAMELNAME, std); -#define PHP_PROTO_INIT_CLASS_END \ - } - -#define PHP_PROTO_OBJECT_EMPTY_FREE_START(classname, lowername) \ - void lowername##_free(zend_object* object) { -#define PHP_PROTO_OBJECT_FREE_START(classname, lowername) \ - void lowername##_free(zend_object* object) { \ - classname* intern = \ - (classname*)((char*)object - XtOffsetOf(classname, std)); -#define PHP_PROTO_OBJECT_FREE_END \ - } - -#define PHP_PROTO_OBJECT_EMPTY_DTOR_START(classname, lowername) \ - void lowername##_dtor(zend_object* object) { -#define PHP_PROTO_OBJECT_DTOR_START(classname, lowername) \ - void lowername##_dtor(zend_object* object) { \ - classname* intern = \ - (classname*)((char*)object - XtOffsetOf(classname, std)); -#define PHP_PROTO_OBJECT_DTOR_END \ - zend_object_std_dtor(object TSRMLS_CC); \ - } - -#define PHP_PROTO_OBJECT_CREATE_START(NAME, LOWWERNAME) \ - static zend_object* LOWWERNAME##_create(zend_class_entry* ce TSRMLS_DC) { \ - PHP_PROTO_ALLOC_CLASS_OBJECT(NAME, ce); \ - zend_object_std_init(&intern->std, ce TSRMLS_CC); \ - object_properties_init(&intern->std, ce); -#define PHP_PROTO_OBJECT_CREATE_END(NAME, LOWWERNAME) \ - PHP_PROTO_FREE_CLASS_OBJECT(NAME, LOWWERNAME##_free, LOWWERNAME##_handlers); \ - } - -#define CACHED_VALUE zval -#define CACHED_TO_ZVAL_PTR(VALUE) (&VALUE) -#define CACHED_PTR_TO_ZVAL_PTR(VALUE) ((CACHED_VALUE*)(VALUE)) -#define ZVAL_PTR_TO_CACHED_PTR(VALUE) (VALUE) -#define ZVAL_PTR_TO_CACHED_VALUE(VALUE) (*VALUE) -#define ZVAL_TO_CACHED_VALUE(VALUE) (VALUE) - -#define CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(zval_ptr, class_type) \ - ZVAL_OBJ(zval_ptr, class_type->create_object(class_type)); - -#define PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(value) ; - -#define PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL &EG(uninitialized_zval) - -#define php_proto_zval_ptr_dtor(zval_ptr) \ - zval_ptr_dtor(zval_ptr) - -#define PHP_PROTO_ALLOC_CLASS_OBJECT(class_object, class_type) \ - class_object* intern; \ - int size = sizeof(class_object) + zend_object_properties_size(class_type); \ - intern = ecalloc(1, size); \ - memset(intern, 0, size); - -#define PHP_PROTO_FREE_CLASS_OBJECT(class_object, class_object_free, handler) \ - intern->std.handlers = handler; \ - return &intern->std; - -#define PHP_PROTO_ALLOC_ARRAY(zval_ptr) \ - ZVAL_NEW_ARR(zval_ptr) - -#define UNBOX(class_name, val) \ - (class_name*)((char*)Z_OBJ_P(val) - XtOffsetOf(class_name, std)); - -#define UNBOX_HASHTABLE_VALUE(class_name, val) \ - (class_name*)((char*)val - XtOffsetOf(class_name, std)) - -#define HASHTABLE_VALUE_DTOR php_proto_hashtable_descriptor_release - -#define PHP_PROTO_HASHTABLE_VALUE zend_object* -#define HASHTABLE_VALUE_CE(val) val->ce - -#define CREATE_HASHTABLE_VALUE(OBJ, WRAPPED_OBJ, OBJ_TYPE, OBJ_CLASS_ENTRY) \ - OBJ_TYPE* OBJ; \ - PHP_PROTO_HASHTABLE_VALUE WRAPPED_OBJ; \ - WRAPPED_OBJ = OBJ_CLASS_ENTRY->create_object(OBJ_CLASS_ENTRY); \ - OBJ = UNBOX_HASHTABLE_VALUE(OBJ_TYPE, WRAPPED_OBJ); \ - GC_DELREF(WRAPPED_OBJ); - -#define PHP_PROTO_CE_DECLARE zend_class_entry* -#define PHP_PROTO_CE_UNREF(ce) (ce) - -static inline int php_proto_zend_lookup_class( - const char* name, int name_length, zend_class_entry** ce TSRMLS_DC) { - zend_string *zstr_name = zend_string_init(name, name_length, 0); - *ce = zend_lookup_class(zstr_name); - zend_string_release(zstr_name); - return *ce != NULL ? SUCCESS : FAILURE; -} - -#define PHP_PROTO_RETVAL_ZVAL(value) ZVAL_COPY(return_value, value) - -#endif // PHP_MAJOR_VERSION >= 7 - -#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) -#define PHP_PROTO_FAKE_SCOPE_BEGIN(klass) \ - zend_class_entry* old_scope = EG(scope); \ - EG(scope) = klass; -#define PHP_PROTO_FAKE_SCOPE_RESTART(klass) \ - old_scope = EG(scope); \ - EG(scope) = klass; -#define PHP_PROTO_FAKE_SCOPE_END EG(scope) = old_scope; -#else -#define PHP_PROTO_FAKE_SCOPE_BEGIN(klass) \ - zend_class_entry* old_scope = EG(fake_scope); \ - EG(fake_scope) = klass; -#define PHP_PROTO_FAKE_SCOPE_RESTART(klass) \ - old_scope = EG(fake_scope); \ - EG(fake_scope) = klass; -#define PHP_PROTO_FAKE_SCOPE_END EG(fake_scope) = old_scope; -#endif - -// Define PHP class -#define DEFINE_PROTOBUF_INIT_CLASS(CLASSNAME, CAMELNAME, LOWERNAME) \ - PHP_PROTO_INIT_CLASS_START(CLASSNAME, CAMELNAME, LOWERNAME) \ - PHP_PROTO_INIT_CLASS_END - -#define DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME) \ - PHP_PROTO_OBJECT_CREATE_START(NAME, LOWERNAME) \ - LOWERNAME##_init_c_instance(intern TSRMLS_CC); \ - PHP_PROTO_OBJECT_CREATE_END(NAME, LOWERNAME) - -#define DEFINE_PROTOBUF_FREE(CAMELNAME, LOWERNAME) \ - PHP_PROTO_OBJECT_FREE_START(CAMELNAME, LOWERNAME) \ - LOWERNAME##_free_c(intern TSRMLS_CC); \ - PHP_PROTO_OBJECT_FREE_END - -#define DEFINE_PROTOBUF_DTOR(CAMELNAME, LOWERNAME) \ - PHP_PROTO_OBJECT_EMPTY_DTOR_START(CAMELNAME, LOWERNAME) \ - PHP_PROTO_OBJECT_DTOR_END - -#define DEFINE_CLASS(NAME, LOWERNAME, string_name) \ - zend_class_entry *LOWERNAME##_type; \ - zend_object_handlers *LOWERNAME##_handlers; \ - DEFINE_PROTOBUF_FREE(NAME, LOWERNAME) \ - DEFINE_PROTOBUF_DTOR(NAME, LOWERNAME) \ - DEFINE_PROTOBUF_CREATE(NAME, LOWERNAME) \ - DEFINE_PROTOBUF_INIT_CLASS(string_name, NAME, LOWERNAME) - -// ----------------------------------------------------------------------------- -// Forward Declaration -// ---------------------------------------------------------------------------- - -struct Any; -struct Api; -struct BoolValue; -struct BytesValue; -struct Descriptor; -struct DescriptorInternal; -struct DescriptorPool; -struct DoubleValue; -struct Duration; -struct Enum; -struct EnumDescriptor; -struct EnumDescriptorInternal; -struct EnumValue; -struct EnumValueDescriptor; -struct Field; -struct FieldDescriptor; -struct FieldMask; -struct Field_Cardinality; -struct Field_Kind; -struct FloatValue; -struct GPBEmpty; -struct Int32Value; -struct Int64Value; -struct InternalDescriptorPool; -struct InternalDescriptorPoolImpl; -struct ListValue; -struct Map; -struct MapIter; -struct MessageField; -struct MessageHeader; -struct MessageLayout; -struct Method; -struct Mixin; -struct NullValue; -struct Oneof; -struct Option; -struct RepeatedField; -struct RepeatedFieldIter; -struct SourceContext; -struct StringValue; -struct Struct; -struct Syntax; -struct Timestamp; -struct Type; -struct UInt32Value; -struct UInt64Value; -struct Value; - -typedef struct Any Any; -typedef struct Api Api; -typedef struct BoolValue BoolValue; -typedef struct BytesValue BytesValue; -typedef struct Descriptor Descriptor; -typedef struct DescriptorInternal DescriptorInternal; -typedef struct DescriptorPool DescriptorPool; -typedef struct DoubleValue DoubleValue; -typedef struct Duration Duration; -typedef struct EnumDescriptor EnumDescriptor; -typedef struct EnumDescriptorInternal EnumDescriptorInternal; -typedef struct Enum Enum; -typedef struct EnumValueDescriptor EnumValueDescriptor; -typedef struct EnumValue EnumValue; -typedef struct Field_Cardinality Field_Cardinality; -typedef struct FieldDescriptor FieldDescriptor; -typedef struct Field Field; -typedef struct Field_Kind Field_Kind; -typedef struct FieldMask FieldMask; -typedef struct FloatValue FloatValue; -typedef struct GPBEmpty GPBEmpty; -typedef struct Int32Value Int32Value; -typedef struct Int64Value Int64Value; -typedef struct InternalDescriptorPool InternalDescriptorPool; -typedef struct InternalDescriptorPoolImpl InternalDescriptorPoolImpl; -typedef struct ListValue ListValue; -typedef struct MapIter MapIter; -typedef struct Map Map; -typedef struct MessageField MessageField; -typedef struct MessageHeader MessageHeader; -typedef struct MessageLayout MessageLayout; -typedef struct Method Method; -typedef struct Mixin Mixin; -typedef struct NullValue NullValue; -typedef struct Oneof Oneof; -typedef struct Option Option; -typedef struct RepeatedFieldIter RepeatedFieldIter; -typedef struct RepeatedField RepeatedField; -typedef struct SourceContext SourceContext; -typedef struct StringValue StringValue; -typedef struct Struct Struct; -typedef struct Syntax Syntax; -typedef struct Timestamp Timestamp; -typedef struct Type Type; -typedef struct UInt32Value UInt32Value; -typedef struct UInt64Value UInt64Value; -typedef struct Value Value; - -// ----------------------------------------------------------------------------- -// Globals. -// ----------------------------------------------------------------------------- - -ZEND_BEGIN_MODULE_GLOBALS(protobuf) - zend_bool keep_descriptor_pool_after_request; -ZEND_END_MODULE_GLOBALS(protobuf) - -ZEND_EXTERN_MODULE_GLOBALS(protobuf) - -#ifdef ZTS -#define PROTOBUF_G(v) TSRMG(protobuf_globals_id, zend_protobuf_globals *, v) -#else -#define PROTOBUF_G(v) (protobuf_globals.v) -#endif - -// Init module and PHP classes. -void any_init(TSRMLS_D); -void api_init(TSRMLS_D); -void bool_value_init(TSRMLS_D); -void bytes_value_init(TSRMLS_D); -void descriptor_init(TSRMLS_D); -void descriptor_pool_init(TSRMLS_D); -void double_value_init(TSRMLS_D); -void duration_init(TSRMLS_D); -void empty_init(TSRMLS_D); -void enum_descriptor_init(TSRMLS_D); -void enum_value_descriptor_init(TSRMLS_D); -void enum_init(TSRMLS_D); -void enum_value_init(TSRMLS_D); -void field_cardinality_init(TSRMLS_D); -void field_descriptor_init(TSRMLS_D); -void field_init(TSRMLS_D); -void field_kind_init(TSRMLS_D); -void field_mask_init(TSRMLS_D); -void float_value_init(TSRMLS_D); -void gpb_type_init(TSRMLS_D); -void int32_value_init(TSRMLS_D); -void int64_value_init(TSRMLS_D); -void internal_descriptor_pool_init(TSRMLS_D); -void list_value_init(TSRMLS_D); -void map_field_init(TSRMLS_D); -void map_field_iter_init(TSRMLS_D); -void message_init(TSRMLS_D); -void method_init(TSRMLS_D); -void mixin_init(TSRMLS_D); -void null_value_init(TSRMLS_D); -void oneof_descriptor_init(TSRMLS_D); -void option_init(TSRMLS_D); -void repeated_field_init(TSRMLS_D); -void repeated_field_iter_init(TSRMLS_D); -void source_context_init(TSRMLS_D); -void string_value_init(TSRMLS_D); -void struct_init(TSRMLS_D); -void syntax_init(TSRMLS_D); -void timestamp_init(TSRMLS_D); -void type_init(TSRMLS_D); -void u_int32_value_init(TSRMLS_D); -void u_int64_value_init(TSRMLS_D); -void util_init(TSRMLS_D); -void value_init(TSRMLS_D); - -void gpb_metadata_any_init(TSRMLS_D); -void gpb_metadata_api_init(TSRMLS_D); -void gpb_metadata_duration_init(TSRMLS_D); -void gpb_metadata_field_mask_init(TSRMLS_D); -void gpb_metadata_empty_init(TSRMLS_D); -void gpb_metadata_source_context_init(TSRMLS_D); -void gpb_metadata_struct_init(TSRMLS_D); -void gpb_metadata_timestamp_init(TSRMLS_D); -void gpb_metadata_type_init(TSRMLS_D); -void gpb_metadata_wrappers_init(TSRMLS_D); - -// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor -// instances. -void add_def_obj(const void* def, PHP_PROTO_HASHTABLE_VALUE value); -PHP_PROTO_HASHTABLE_VALUE get_def_obj(const void* def); -void add_msgdef_desc(const upb_msgdef* m, DescriptorInternal* desc); -DescriptorInternal* get_msgdef_desc(const upb_msgdef* m); -void add_enumdef_enumdesc(const upb_enumdef* e, EnumDescriptorInternal* desc); -EnumDescriptorInternal* get_enumdef_enumdesc(const upb_enumdef* e); - -// Global map from PHP class entries to wrapper Descriptor/EnumDescriptor -// instances. -void add_ce_obj(const void* ce, PHP_PROTO_HASHTABLE_VALUE value); -PHP_PROTO_HASHTABLE_VALUE get_ce_obj(const void* ce); -bool class_added(const void* ce); -void add_ce_desc(const zend_class_entry* ce, DescriptorInternal* desc); -DescriptorInternal* get_ce_desc(const zend_class_entry* ce); -void add_ce_enumdesc(const zend_class_entry* ce, EnumDescriptorInternal* desc); -EnumDescriptorInternal* get_ce_enumdesc(const zend_class_entry* ce); - -// Global map from message/enum's proto fully-qualified name to corresponding -// wrapper Descriptor/EnumDescriptor instances. -void add_proto_desc(const char* proto, DescriptorInternal* desc); -DescriptorInternal* get_proto_desc(const char* proto); -void add_class_desc(const char* klass, DescriptorInternal* desc); -DescriptorInternal* get_class_desc(const char* klass); -void add_class_enumdesc(const char* klass, EnumDescriptorInternal* desc); -EnumDescriptorInternal* get_class_enumdesc(const char* klass); - -extern zend_class_entry* map_field_type; -extern zend_class_entry* repeated_field_type; - -// ----------------------------------------------------------------------------- -// Descriptor. -// ----------------------------------------------------------------------------- - -PHP_PROTO_WRAP_OBJECT_START(DescriptorPool) - InternalDescriptorPoolImpl* intern; -PHP_PROTO_WRAP_OBJECT_END - -PHP_METHOD(DescriptorPool, getGeneratedPool); -PHP_METHOD(DescriptorPool, getDescriptorByClassName); -PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName); - -struct InternalDescriptorPoolImpl { - upb_symtab* symtab; - upb_handlercache* fill_handler_cache; - upb_handlercache* pb_serialize_handler_cache; - upb_handlercache* json_serialize_handler_cache; - upb_handlercache* json_serialize_handler_preserve_cache; - upb_pbcodecache* fill_method_cache; - upb_json_codecache* json_fill_method_cache; -}; - -PHP_PROTO_WRAP_OBJECT_START(InternalDescriptorPool) - InternalDescriptorPoolImpl* intern; -PHP_PROTO_WRAP_OBJECT_END - -PHP_METHOD(InternalDescriptorPool, getGeneratedPool); -PHP_METHOD(InternalDescriptorPool, internalAddGeneratedFile); - -void internal_add_generated_file(const char* data, PHP_PROTO_SIZE data_len, - InternalDescriptorPoolImpl* pool, - bool use_nested_submsg TSRMLS_DC); -void init_generated_pool_once(TSRMLS_D); -void add_handlers_for_message(const void* closure, upb_handlers* h); -void register_class(void *desc, bool is_enum TSRMLS_DC); - -// wrapper of generated pool -#if PHP_MAJOR_VERSION < 7 -extern zval* generated_pool_php; -extern zval* internal_generated_pool_php; -void descriptor_pool_free(void* object TSRMLS_DC); -void internal_descriptor_pool_free(void* object TSRMLS_DC); -#else -extern zend_object *generated_pool_php; -extern zend_object *internal_generated_pool_php; -void descriptor_pool_free(zend_object* object); -void internal_descriptor_pool_free(zend_object* object); -#endif -extern InternalDescriptorPoolImpl* generated_pool; -// The actual generated pool -extern InternalDescriptorPoolImpl generated_pool_impl; - -void internal_descriptor_pool_impl_init( - InternalDescriptorPoolImpl *pool TSRMLS_DC); -void internal_descriptor_pool_impl_destroy( - InternalDescriptorPoolImpl *pool TSRMLS_DC); - -struct DescriptorInternal { - InternalDescriptorPoolImpl* pool; - const upb_msgdef* msgdef; - MessageLayout* layout; - zend_class_entry* klass; // begins as NULL - bool use_nested_submsg; - char* classname; -}; - -PHP_PROTO_WRAP_OBJECT_START(Descriptor) - DescriptorInternal* intern; -PHP_PROTO_WRAP_OBJECT_END - -PHP_METHOD(Descriptor, getClass); -PHP_METHOD(Descriptor, getFullName); -PHP_METHOD(Descriptor, getField); -PHP_METHOD(Descriptor, getFieldCount); -PHP_METHOD(Descriptor, getOneofDecl); -PHP_METHOD(Descriptor, getOneofDeclCount); - -extern zend_class_entry* descriptor_type; - -void descriptor_name_set(Descriptor *desc, const char *name); - -PHP_PROTO_WRAP_OBJECT_START(FieldDescriptor) - const upb_fielddef* fielddef; -PHP_PROTO_WRAP_OBJECT_END - -PHP_METHOD(FieldDescriptor, getName); -PHP_METHOD(FieldDescriptor, getNumber); -PHP_METHOD(FieldDescriptor, getLabel); -PHP_METHOD(FieldDescriptor, getType); -PHP_METHOD(FieldDescriptor, isMap); -PHP_METHOD(FieldDescriptor, getEnumType); -PHP_METHOD(FieldDescriptor, getMessageType); - -extern zend_class_entry* field_descriptor_type; - -struct EnumDescriptorInternal { - const upb_enumdef* enumdef; - zend_class_entry* klass; // begins as NULL - bool use_nested_submsg; - char* classname; -}; - -PHP_PROTO_WRAP_OBJECT_START(EnumDescriptor) - EnumDescriptorInternal* intern; -PHP_PROTO_WRAP_OBJECT_END - -PHP_METHOD(EnumDescriptor, getValue); -PHP_METHOD(EnumDescriptor, getValueCount); - -extern zend_class_entry* enum_descriptor_type; - -PHP_PROTO_WRAP_OBJECT_START(EnumValueDescriptor) - const char* name; - int32_t number; -PHP_PROTO_WRAP_OBJECT_END - -PHP_METHOD(EnumValueDescriptor, getName); -PHP_METHOD(EnumValueDescriptor, getNumber); - -extern zend_class_entry* enum_value_descriptor_type; - -// ----------------------------------------------------------------------------- -// Message class creation. -// ----------------------------------------------------------------------------- - -void* message_data(MessageHeader* msg); -void custom_data_init(const zend_class_entry* ce, - MessageHeader* msg PHP_PROTO_TSRMLS_DC); - -extern zend_class_entry* message_type; -extern zend_object_handlers* message_handlers; - -// ----------------------------------------------------------------------------- -// Message layout / storage. -// ----------------------------------------------------------------------------- - -/* - * In c extension, each protobuf message is a zval instance. The zval instance - * is like union, which can be used to store int, string, zend_object_value and - * etc. For protobuf message, the zval instance is used to store the - * zend_object_value. - * - * The zend_object_value is composed of handlers and a handle to look up the - * actual stored data. The handlers are pointers to functions, e.g., read, - * write, and etc, to access properties. - * - * The actual data of protobuf messages is stored as MessageHeader in zend - * engine's central repository. Each MessageHeader instance is composed of a - * zend_object, a Descriptor instance and the real message data. - * - * For the reason that PHP's native types may not be large enough to store - * protobuf message's field (e.g., int64), all message's data is stored in - * custom memory layout and is indexed by the Descriptor instance. - * - * The zend_object contains the zend class entry and the properties table. The - * zend class entry contains all information about protobuf message's - * corresponding PHP class. The most useful information is the offset table of - * properties. Because read access to properties requires returning zval - * instance, we need to convert data from the custom layout to zval instance. - * Instead of creating zval instance for every read access, we use the zval - * instances in the properties table in the zend_object as cache. When - * accessing properties, the offset is needed to find the zval property in - * zend_object's properties table. These properties will be updated using the - * data from custom memory layout only when reading these properties. - * - * zval - * |-zend_object_value obj - * |-zend_object_handlers* handlers -> |-read_property_handler - * | |-write_property_handler - * | ++++++++++++++++++++++ - * |-zend_object_handle handle -> + central repository + - * ++++++++++++++++++++++ - * MessageHeader <-----------------| - * |-zend_object std - * | |-class_entry* ce -> class_entry - * | | |-HashTable properties_table (name->offset) - * | |-zval** properties_table <------------------------------| - * | |------> zval* property(cache) - * |-Descriptor* desc (name->offset) - * |-void** data <-----------| - * |-----------------------> void* property(data) - * - */ - -#define MESSAGE_FIELD_NO_CASE ((size_t)-1) - -struct MessageField { - size_t offset; - int cache_index; // Each field except oneof field has a zval cache to avoid - // multiple creation when being accessed. - size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. -}; - -struct MessageLayout { - const upb_msgdef* msgdef; - void* empty_template; // Can memcpy() onto a layout to clear it. - MessageField* fields; - size_t size; -}; - -PHP_PROTO_WRAP_OBJECT_START(MessageHeader) - void* data; // Point to the real message data. - // Place needs to be consistent with map_parse_frame_data_t. - DescriptorInternal* descriptor; // Kept alive by self.class.descriptor - // reference. -PHP_PROTO_WRAP_OBJECT_END - -MessageLayout* create_layout(const upb_msgdef* msgdef); -void layout_init(MessageLayout* layout, void* storage, - zend_object* object PHP_PROTO_TSRMLS_DC); -zval* layout_get(MessageLayout* layout, MessageHeader* header, - const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC); -void layout_set(MessageLayout* layout, MessageHeader* header, - const upb_fielddef* field, zval* val TSRMLS_DC); -void layout_merge(MessageLayout* layout, MessageHeader* from, - MessageHeader* to TSRMLS_DC); -const char* layout_get_oneof_case(MessageLayout* layout, const void* storage, - const upb_oneofdef* oneof TSRMLS_DC); -void free_layout(MessageLayout* layout); -uint32_t* slot_oneof_case(MessageLayout* layout, const void* storage, - const upb_fielddef* field); -void* slot_memory(MessageLayout* layout, const void* storage, - const upb_fielddef* field); - -PHP_METHOD(Message, clear); -PHP_METHOD(Message, mergeFrom); -PHP_METHOD(Message, readWrapperValue); -PHP_METHOD(Message, writeWrapperValue); -PHP_METHOD(Message, readOneof); -PHP_METHOD(Message, writeOneof); -PHP_METHOD(Message, whichOneof); -PHP_METHOD(Message, __construct); - -// ----------------------------------------------------------------------------- -// Encode / Decode. -// ----------------------------------------------------------------------------- - -// Maximum depth allowed during encoding, to avoid stack overflows due to -// cycles. -#define ENCODE_MAX_NESTING 63 - -// Constructs the upb decoder method for parsing messages of this type. -// This is called from the message class creation code. -const upb_pbdecodermethod *new_fillmsg_decodermethod(Descriptor *desc, - const void *owner); -void serialize_to_string(zval* val, zval* return_value TSRMLS_DC); -void merge_from_string(const char* data, int data_len, DescriptorInternal* desc, - MessageHeader* msg); - -PHP_METHOD(Message, serializeToString); -PHP_METHOD(Message, mergeFromString); -PHP_METHOD(Message, serializeToJsonString); -PHP_METHOD(Message, mergeFromJsonString); -PHP_METHOD(Message, discardUnknownFields); - -// ----------------------------------------------------------------------------- -// Type check / conversion. -// ----------------------------------------------------------------------------- - -bool protobuf_convert_to_int32(zval* from, int32_t* to); -bool protobuf_convert_to_uint32(zval* from, uint32_t* to); -bool protobuf_convert_to_int64(zval* from, int64_t* to); -bool protobuf_convert_to_uint64(zval* from, uint64_t* to); -bool protobuf_convert_to_float(zval* from, float* to); -bool protobuf_convert_to_double(zval* from, double* to); -bool protobuf_convert_to_bool(zval* from, int8_t* to); -bool protobuf_convert_to_string(zval* from); - -void check_repeated_field(const zend_class_entry* klass, PHP_PROTO_LONG type, - zval* val, zval* return_value); -void check_map_field(const zend_class_entry* klass, PHP_PROTO_LONG key_type, - PHP_PROTO_LONG value_type, zval* val, zval* return_value); - -PHP_METHOD(Util, checkInt32); -PHP_METHOD(Util, checkUint32); -PHP_METHOD(Util, checkInt64); -PHP_METHOD(Util, checkUint64); -PHP_METHOD(Util, checkEnum); -PHP_METHOD(Util, checkFloat); -PHP_METHOD(Util, checkDouble); -PHP_METHOD(Util, checkBool); -PHP_METHOD(Util, checkString); -PHP_METHOD(Util, checkBytes); -PHP_METHOD(Util, checkMessage); -PHP_METHOD(Util, checkMapField); -PHP_METHOD(Util, checkRepeatedField); - -// ----------------------------------------------------------------------------- -// Native slot storage abstraction. -// ----------------------------------------------------------------------------- - -#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) - -size_t native_slot_size(upb_fieldtype_t type); -bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, - void* memory, zval* value TSRMLS_DC); -// String/Message is stored differently in array/map from normal message fields. -// So we need to make a special method to handle that. -bool native_slot_set_by_array(upb_fieldtype_t type, - const zend_class_entry* klass, void* memory, - zval* value TSRMLS_DC); -bool native_slot_set_by_map(upb_fieldtype_t type, const zend_class_entry* klass, - void* memory, zval* value TSRMLS_DC); -void native_slot_init(upb_fieldtype_t type, void* memory, CACHED_VALUE* cache); -// For each property, in order to avoid conversion between the zval object and -// the actual data type during parsing/serialization, the containing message -// object use the custom memory layout to store the actual data type for each -// property inside of it. To access a property from php code, the property -// needs to be converted to a zval object. The message object is not responsible -// for providing such a zval object. Instead the caller needs to provide one -// (cache) and update it with the actual data (memory). -void native_slot_get(upb_fieldtype_t type, const void* memory, - CACHED_VALUE* cache TSRMLS_DC); -// String/Message is stored differently in array/map from normal message fields. -// So we need to make a special method to handle that. -void native_slot_get_by_array(upb_fieldtype_t type, const void* memory, - CACHED_VALUE* cache TSRMLS_DC); -void native_slot_get_by_map_key(upb_fieldtype_t type, const void* memory, - int length, CACHED_VALUE* cache TSRMLS_DC); -void native_slot_get_by_map_value(upb_fieldtype_t type, const void* memory, - CACHED_VALUE* cache TSRMLS_DC); -void native_slot_get_default(upb_fieldtype_t type, - CACHED_VALUE* cache TSRMLS_DC); - -// ----------------------------------------------------------------------------- -// Map Field. -// ----------------------------------------------------------------------------- - -extern zend_object_handlers* map_field_handlers; -extern zend_object_handlers* map_field_iter_handlers; - -PHP_PROTO_WRAP_OBJECT_START(Map) - upb_fieldtype_t key_type; - upb_fieldtype_t value_type; - const zend_class_entry* msg_ce; // class entry for value message - upb_strtable table; -PHP_PROTO_WRAP_OBJECT_END - -PHP_PROTO_WRAP_OBJECT_START(MapIter) - Map* self; - upb_strtable_iter it; -PHP_PROTO_WRAP_OBJECT_END - -void map_begin(zval* self, MapIter* iter TSRMLS_DC); -void map_next(MapIter* iter); -bool map_done(MapIter* iter); -const char* map_iter_key(MapIter* iter, int* len); -upb_value map_iter_value(MapIter* iter, int* len); - -// These operate on a map-entry msgdef. -const upb_fielddef* map_entry_key(const upb_msgdef* msgdef); -const upb_fielddef* map_entry_value(const upb_msgdef* msgdef); - -void map_field_ensure_created(const upb_fielddef *field, - CACHED_VALUE *map_field PHP_PROTO_TSRMLS_DC); -void map_field_create_with_field(const zend_class_entry* ce, - const upb_fielddef* field, - CACHED_VALUE* map_field PHP_PROTO_TSRMLS_DC); -void map_field_create_with_type(const zend_class_entry* ce, - upb_fieldtype_t key_type, - upb_fieldtype_t value_type, - const zend_class_entry* msg_ce, - CACHED_VALUE* map_field PHP_PROTO_TSRMLS_DC); -void* upb_value_memory(upb_value* v); - -#define MAP_KEY_FIELD 1 -#define MAP_VALUE_FIELD 2 - -// These operate on a map field (i.e., a repeated field of submessages whose -// submessage type is a map-entry msgdef). -bool is_map_field(const upb_fielddef* field); -const upb_fielddef* map_field_key(const upb_fielddef* field); -const upb_fielddef* map_field_value(const upb_fielddef* field); - -bool map_index_set(Map *intern, const char* keyval, int length, upb_value v); - -PHP_METHOD(MapField, __construct); -PHP_METHOD(MapField, offsetExists); -PHP_METHOD(MapField, offsetGet); -PHP_METHOD(MapField, offsetSet); -PHP_METHOD(MapField, offsetUnset); -PHP_METHOD(MapField, count); -PHP_METHOD(MapField, getIterator); - -PHP_METHOD(MapFieldIter, rewind); -PHP_METHOD(MapFieldIter, current); -PHP_METHOD(MapFieldIter, key); -PHP_METHOD(MapFieldIter, next); -PHP_METHOD(MapFieldIter, valid); - -// ----------------------------------------------------------------------------- -// Repeated Field. -// ----------------------------------------------------------------------------- - -extern zend_object_handlers* repeated_field_handlers; -extern zend_object_handlers* repeated_field_iter_handlers; - -PHP_PROTO_WRAP_OBJECT_START(RepeatedField) -#if PHP_MAJOR_VERSION < 7 - zval* array; -#else - zval array; -#endif - upb_fieldtype_t type; - const zend_class_entry* msg_ce; // class entry for containing message - // (for message field only). -PHP_PROTO_WRAP_OBJECT_END - -PHP_PROTO_WRAP_OBJECT_START(RepeatedFieldIter) - RepeatedField* repeated_field; - long position; -PHP_PROTO_WRAP_OBJECT_END - -void repeated_field_ensure_created( - const upb_fielddef *field, - CACHED_VALUE *repeated_field PHP_PROTO_TSRMLS_DC); -void repeated_field_create_with_field( - zend_class_entry* ce, const upb_fielddef* field, - CACHED_VALUE* repeated_field PHP_PROTO_TSRMLS_DC); -void repeated_field_create_with_type( - zend_class_entry* ce, upb_fieldtype_t type, const zend_class_entry* msg_ce, - CACHED_VALUE* repeated_field PHP_PROTO_TSRMLS_DC); -// Return the element at the index position from the repeated field. There is -// not restriction on the type of stored elements. -void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC); -// Add the element to the end of the repeated field. There is not restriction on -// the type of stored elements. -void repeated_field_push_native(RepeatedField *intern, void *value); - -PHP_METHOD(RepeatedField, __construct); -PHP_METHOD(RepeatedField, append); -PHP_METHOD(RepeatedField, offsetExists); -PHP_METHOD(RepeatedField, offsetGet); -PHP_METHOD(RepeatedField, offsetSet); -PHP_METHOD(RepeatedField, offsetUnset); -PHP_METHOD(RepeatedField, count); -PHP_METHOD(RepeatedField, getIterator); - -PHP_METHOD(RepeatedFieldIter, rewind); -PHP_METHOD(RepeatedFieldIter, current); -PHP_METHOD(RepeatedFieldIter, key); -PHP_METHOD(RepeatedFieldIter, next); -PHP_METHOD(RepeatedFieldIter, valid); - -// ----------------------------------------------------------------------------- -// Oneof Field. -// ----------------------------------------------------------------------------- - -PHP_PROTO_WRAP_OBJECT_START(Oneof) - const upb_oneofdef* oneofdef; - int index; // Index of field in oneof. -1 if not set. - char value[NATIVE_SLOT_MAX_SIZE]; -PHP_PROTO_WRAP_OBJECT_END - -PHP_METHOD(Oneof, getName); -PHP_METHOD(Oneof, getField); -PHP_METHOD(Oneof, getFieldCount); - -extern zend_class_entry* oneof_descriptor_type; - -// Oneof case slot value to indicate that no oneof case is set. The value `0` is -// safe because field numbers are used as case identifiers, and no field can -// have a number of 0. -#define ONEOF_CASE_NONE 0 - -// ----------------------------------------------------------------------------- -// Well Known Type. -// ----------------------------------------------------------------------------- - -extern bool is_inited_file_any; -extern bool is_inited_file_api; -extern bool is_inited_file_duration; -extern bool is_inited_file_field_mask; -extern bool is_inited_file_empty; -extern bool is_inited_file_source_context; -extern bool is_inited_file_struct; -extern bool is_inited_file_timestamp; -extern bool is_inited_file_type; -extern bool is_inited_file_wrappers; - -PHP_METHOD(GPBMetadata_Any, initOnce); -PHP_METHOD(GPBMetadata_Api, initOnce); -PHP_METHOD(GPBMetadata_Duration, initOnce); -PHP_METHOD(GPBMetadata_FieldMask, initOnce); -PHP_METHOD(GPBMetadata_Empty, initOnce); -PHP_METHOD(GPBMetadata_SourceContext, initOnce); -PHP_METHOD(GPBMetadata_Struct, initOnce); -PHP_METHOD(GPBMetadata_Timestamp, initOnce); -PHP_METHOD(GPBMetadata_Type, initOnce); -PHP_METHOD(GPBMetadata_Wrappers, initOnce); - -PHP_METHOD(Any, __construct); -PHP_METHOD(Any, getTypeUrl); -PHP_METHOD(Any, setTypeUrl); -PHP_METHOD(Any, getValue); -PHP_METHOD(Any, setValue); -PHP_METHOD(Any, unpack); -PHP_METHOD(Any, pack); -PHP_METHOD(Any, is); - -PHP_METHOD(Duration, __construct); -PHP_METHOD(Duration, getSeconds); -PHP_METHOD(Duration, setSeconds); -PHP_METHOD(Duration, getNanos); -PHP_METHOD(Duration, setNanos); - -static PHP_METHOD(Timestamp, __construct); -PHP_METHOD(Timestamp, fromDateTime); -PHP_METHOD(Timestamp, toDateTime); -PHP_METHOD(Timestamp, getSeconds); -PHP_METHOD(Timestamp, setSeconds); -PHP_METHOD(Timestamp, getNanos); -PHP_METHOD(Timestamp, setNanos); - -PHP_METHOD(Api, __construct); -PHP_METHOD(Api, getName); -PHP_METHOD(Api, setName); -PHP_METHOD(Api, getMethods); -PHP_METHOD(Api, setMethods); -PHP_METHOD(Api, getOptions); -PHP_METHOD(Api, setOptions); -PHP_METHOD(Api, getVersion); -PHP_METHOD(Api, setVersion); -PHP_METHOD(Api, getSourceContext); -PHP_METHOD(Api, setSourceContext); -PHP_METHOD(Api, getMixins); -PHP_METHOD(Api, setMixins); -PHP_METHOD(Api, getSyntax); -PHP_METHOD(Api, setSyntax); - -PHP_METHOD(BoolValue, __construct); -PHP_METHOD(BoolValue, getValue); -PHP_METHOD(BoolValue, setValue); - -PHP_METHOD(BytesValue, __construct); -PHP_METHOD(BytesValue, getValue); -PHP_METHOD(BytesValue, setValue); - -PHP_METHOD(DoubleValue, __construct); -PHP_METHOD(DoubleValue, getValue); -PHP_METHOD(DoubleValue, setValue); - -PHP_METHOD(Enum, __construct); -PHP_METHOD(Enum, getName); -PHP_METHOD(Enum, setName); -PHP_METHOD(Enum, getEnumvalue); -PHP_METHOD(Enum, setEnumvalue); -PHP_METHOD(Enum, getOptions); -PHP_METHOD(Enum, setOptions); -PHP_METHOD(Enum, getSourceContext); -PHP_METHOD(Enum, setSourceContext); -PHP_METHOD(Enum, getSyntax); -PHP_METHOD(Enum, setSyntax); - -PHP_METHOD(EnumValue, __construct); -PHP_METHOD(EnumValue, getName); -PHP_METHOD(EnumValue, setName); -PHP_METHOD(EnumValue, getNumber); -PHP_METHOD(EnumValue, setNumber); -PHP_METHOD(EnumValue, getOptions); -PHP_METHOD(EnumValue, setOptions); - -PHP_METHOD(FieldMask, __construct); -PHP_METHOD(FieldMask, getPaths); -PHP_METHOD(FieldMask, setPaths); - -PHP_METHOD(Field, __construct); -PHP_METHOD(Field, getKind); -PHP_METHOD(Field, setKind); -PHP_METHOD(Field, getCardinality); -PHP_METHOD(Field, setCardinality); -PHP_METHOD(Field, getNumber); -PHP_METHOD(Field, setNumber); -PHP_METHOD(Field, getName); -PHP_METHOD(Field, setName); -PHP_METHOD(Field, getTypeUrl); -PHP_METHOD(Field, setTypeUrl); -PHP_METHOD(Field, getOneofIndex); -PHP_METHOD(Field, setOneofIndex); -PHP_METHOD(Field, getPacked); -PHP_METHOD(Field, setPacked); -PHP_METHOD(Field, getOptions); -PHP_METHOD(Field, setOptions); -PHP_METHOD(Field, getJsonName); -PHP_METHOD(Field, setJsonName); -PHP_METHOD(Field, getDefaultValue); -PHP_METHOD(Field, setDefaultValue); - -PHP_METHOD(Field_Cardinality, name); -PHP_METHOD(Field_Cardinality, value); - -PHP_METHOD(Field_Kind, name); -PHP_METHOD(Field_Kind, value); - -PHP_METHOD(FloatValue, __construct); -PHP_METHOD(FloatValue, getValue); -PHP_METHOD(FloatValue, setValue); - -PHP_METHOD(GPBEmpty, __construct); - -PHP_METHOD(Int32Value, __construct); -PHP_METHOD(Int32Value, getValue); -PHP_METHOD(Int32Value, setValue); - -PHP_METHOD(Int64Value, __construct); -PHP_METHOD(Int64Value, getValue); -PHP_METHOD(Int64Value, setValue); - -PHP_METHOD(ListValue, __construct); -PHP_METHOD(ListValue, getValues); -PHP_METHOD(ListValue, setValues); - -PHP_METHOD(Method, __construct); -PHP_METHOD(Method, getName); -PHP_METHOD(Method, setName); -PHP_METHOD(Method, getRequestTypeUrl); -PHP_METHOD(Method, setRequestTypeUrl); -PHP_METHOD(Method, getRequestStreaming); -PHP_METHOD(Method, setRequestStreaming); -PHP_METHOD(Method, getResponseTypeUrl); -PHP_METHOD(Method, setResponseTypeUrl); -PHP_METHOD(Method, getResponseStreaming); -PHP_METHOD(Method, setResponseStreaming); -PHP_METHOD(Method, getOptions); -PHP_METHOD(Method, setOptions); -PHP_METHOD(Method, getSyntax); -PHP_METHOD(Method, setSyntax); - -PHP_METHOD(Mixin, __construct); -PHP_METHOD(Mixin, getName); -PHP_METHOD(Mixin, setName); -PHP_METHOD(Mixin, getRoot); -PHP_METHOD(Mixin, setRoot); - -PHP_METHOD(NullValue, name); -PHP_METHOD(NullValue, value); - -PHP_METHOD(Option, __construct); -PHP_METHOD(Option, getName); -PHP_METHOD(Option, setName); -PHP_METHOD(Option, getValue); -PHP_METHOD(Option, setValue); - -PHP_METHOD(SourceContext, __construct); -PHP_METHOD(SourceContext, getFileName); -PHP_METHOD(SourceContext, setFileName); - -PHP_METHOD(StringValue, __construct); -PHP_METHOD(StringValue, getValue); -PHP_METHOD(StringValue, setValue); - -PHP_METHOD(Struct, __construct); -PHP_METHOD(Struct, getFields); -PHP_METHOD(Struct, setFields); - -PHP_METHOD(Syntax, name); -PHP_METHOD(Syntax, value); - -PHP_METHOD(Type, __construct); -PHP_METHOD(Type, getName); -PHP_METHOD(Type, setName); -PHP_METHOD(Type, getFields); -PHP_METHOD(Type, setFields); -PHP_METHOD(Type, getOneofs); -PHP_METHOD(Type, setOneofs); -PHP_METHOD(Type, getOptions); -PHP_METHOD(Type, setOptions); -PHP_METHOD(Type, getSourceContext); -PHP_METHOD(Type, setSourceContext); -PHP_METHOD(Type, getSyntax); -PHP_METHOD(Type, setSyntax); - -PHP_METHOD(UInt32Value, __construct); -PHP_METHOD(UInt32Value, getValue); -PHP_METHOD(UInt32Value, setValue); - -PHP_METHOD(UInt64Value, __construct); -PHP_METHOD(UInt64Value, getValue); -PHP_METHOD(UInt64Value, setValue); - -PHP_METHOD(Value, __construct); -PHP_METHOD(Value, getNullValue); -PHP_METHOD(Value, setNullValue); -PHP_METHOD(Value, getNumberValue); -PHP_METHOD(Value, setNumberValue); -PHP_METHOD(Value, getStringValue); -PHP_METHOD(Value, setStringValue); -PHP_METHOD(Value, getBoolValue); -PHP_METHOD(Value, setBoolValue); -PHP_METHOD(Value, getStructValue); -PHP_METHOD(Value, setStructValue); -PHP_METHOD(Value, getListValue); -PHP_METHOD(Value, setListValue); -PHP_METHOD(Value, getKind); - -extern zend_class_entry* any_type; -extern zend_class_entry* api_type; -extern zend_class_entry* bool_value_type; -extern zend_class_entry* bytes_value_type; -extern zend_class_entry* double_value_type; -extern zend_class_entry* duration_type; -extern zend_class_entry* empty_type; -extern zend_class_entry* enum_type; -extern zend_class_entry* enum_value_type; -extern zend_class_entry* field_cardinality_type; -extern zend_class_entry* field_kind_type; -extern zend_class_entry* field_mask_type; -extern zend_class_entry* field_type; -extern zend_class_entry* float_value_type; -extern zend_class_entry* int32_value_type; -extern zend_class_entry* int64_value_type; -extern zend_class_entry* list_value_type; -extern zend_class_entry* method_type; -extern zend_class_entry* mixin_type; -extern zend_class_entry* null_value_type; -extern zend_class_entry* option_type; -extern zend_class_entry* source_context_type; -extern zend_class_entry* string_value_type; -extern zend_class_entry* struct_type; -extern zend_class_entry* syntax_type; -extern zend_class_entry* timestamp_type; -extern zend_class_entry* type_type; -extern zend_class_entry* uint32_value_type; -extern zend_class_entry* uint64_value_type; -extern zend_class_entry* value_type; - -// ----------------------------------------------------------------------------- -// Upb. -// ----------------------------------------------------------------------------- - -upb_fieldtype_t to_fieldtype(upb_descriptortype_t type); -const zend_class_entry* field_type_class( - const upb_fielddef* field PHP_PROTO_TSRMLS_DC); -void stringsink_uninit_opaque(void *sink); - -typedef struct { - upb_byteshandler handler; - upb_bytessink sink; - char *ptr; - size_t len, size; -} stringsink; - -void stringsink_init(stringsink *sink); -void stringsink_uninit(stringsink *sink); -size_t stringsink_string(void *_sink, const void *hd, const char *ptr, - size_t len, const upb_bufhandle *handle); - -// ----------------------------------------------------------------------------- -// Utilities. -// ----------------------------------------------------------------------------- - -// Memory management -#define SYS_MALLOC(class_name) (class_name*) malloc(sizeof(class_name)) -#define SYS_MALLOC_N(class_name, n) (class_name*) malloc(sizeof(class_name) * n) -#define SYS_FREE(ptr) free(ptr) -#define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) -#define PEMALLOC(class_name, persistent) (class_name*) pemalloc(sizeof(class_name), persistent) -#define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) -#define FREE(object) efree(object) -#define PEFREE(object) pefree(object, 1) - -// Find corresponding zval property for the field. -CACHED_VALUE* find_zval_property(MessageHeader* msg, const upb_fielddef* field); - -// String argument. -#define STR(str) (str), strlen(str) - -// Zend Value -#if PHP_MAJOR_VERSION < 7 -#define Z_OBJ_P(zval_p) \ - ((zend_object*)(EG(objects_store) \ - .object_buckets[Z_OBJ_HANDLE_P(zval_p)] \ - .bucket.obj.object)) -#endif - -// Message handler -static inline zval* php_proto_message_read_property( - zval* msg, zval* member PHP_PROTO_TSRMLS_DC) { -#if PHP_MAJOR_VERSION < 7 - return message_handlers->read_property(msg, member, BP_VAR_R, - NULL PHP_PROTO_TSRMLS_CC); +// ptr -> PHP object cache. This is a weak map that caches lazily-created +// wrapper objects around upb types: +// * upb_msg* -> Message +// * upb_array* -> RepeatedField +// * upb_map*, -> MapField +// * upb_msgdef* -> Descriptor +// * upb_enumdef* -> EnumDescriptor +// * zend_class_entry* -> Descriptor +// +// Each wrapped object should add itself to the map when it is constructed, and +// remove itself from the map when it is destroyed. This is how we ensure that +// the map only contains live objects. The map is weak so it does not actually +// take references to the cached objects. +void ObjCache_Add(const void *key, zend_object *php_obj); +void ObjCache_Delete(const void *key); +bool ObjCache_Get(const void *key, zval *val); + +// PHP class name map. This is necessary because the pb_name->php_class_name +// transformation is non-reversible, so when we need to look up a msgdef or +// enumdef by PHP class, we can't turn the class name into a pb_name. +// * php_class_name -> upb_msgdef* +// * php_class_name -> upb_enumdef* +void NameMap_AddMessage(const upb_msgdef *m); +void NameMap_AddEnum(const upb_enumdef *m); +const upb_msgdef *NameMap_GetMessage(zend_class_entry *ce); +const upb_enumdef *NameMap_GetEnum(zend_class_entry *ce); + +// We need our own assert() because PHP takes control of NDEBUG in its headers. +#ifdef PBPHP_ENABLE_ASSERTS +#define PBPHP_ASSERT(x) \ + do { \ + if (!(x)) { \ + fprintf(stderr, "Assertion failure at %s:%d %s", __FILE__, __LINE__, \ + #x); \ + abort(); \ + } \ + } while (false) #else - return message_handlers->read_property(msg, member, BP_VAR_R, NULL, - NULL PHP_PROTO_TSRMLS_CC); +#define PBPHP_ASSERT(x) \ + do { \ + } while (false && (x)) #endif -} - -// Reserved name -bool is_reserved_name(const char* name); -bool is_valid_constant_name(const char* name); - -// For lazy wrapper -bool is_wrapper_msg(const upb_msgdef* m); -#endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ +#endif // PHP_PROTOBUF_H_ diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c deleted file mode 100644 index fec73358479c..000000000000 --- a/php/ext/google/protobuf/storage.c +++ /dev/null @@ -1,1180 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#include -#include -#include - -#include "utf8.h" - -// ----------------------------------------------------------------------------- -// Native slot storage. -// ----------------------------------------------------------------------------- - -#define DEREF(memory, type) *(type*)(memory) - -size_t native_slot_size(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_FLOAT: return 4; - case UPB_TYPE_DOUBLE: return 8; - case UPB_TYPE_BOOL: return 1; - case UPB_TYPE_STRING: return sizeof(void*); - case UPB_TYPE_BYTES: return sizeof(void*); - case UPB_TYPE_MESSAGE: return sizeof(void*); - case UPB_TYPE_ENUM: return 4; - case UPB_TYPE_INT32: return 4; - case UPB_TYPE_INT64: return 8; - case UPB_TYPE_UINT32: return 4; - case UPB_TYPE_UINT64: return 8; - default: return 0; - } -} - -static bool native_slot_is_default(upb_fieldtype_t type, const void* memory) { - switch (type) { -#define CASE_TYPE(upb_type, c_type) \ - case UPB_TYPE_##upb_type: { \ - return DEREF(memory, c_type) == 0; \ - } - CASE_TYPE(INT32, int32_t ) - CASE_TYPE(UINT32, uint32_t) - CASE_TYPE(ENUM, int32_t ) - CASE_TYPE(INT64, int64_t ) - CASE_TYPE(UINT64, uint64_t) - CASE_TYPE(FLOAT, float ) - CASE_TYPE(DOUBLE, double ) - CASE_TYPE(BOOL, int8_t ) - -#undef CASE_TYPE - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - return Z_STRLEN_P(CACHED_PTR_TO_ZVAL_PTR(memory)) == 0; - case UPB_TYPE_MESSAGE: - return Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(memory)) == IS_NULL; - default: return false; - } -} - -bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass, - void* memory, zval* value PHP_PROTO_TSRMLS_DC) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - if (!protobuf_convert_to_string(value)) { - return false; - } - if (type == UPB_TYPE_STRING && - !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) { - zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); - return false; - } - - zval* cached_zval = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); - if (EXPECTED(cached_zval != NULL)) { -#if PHP_MAJOR_VERSION < 7 - REPLACE_ZVAL_VALUE((zval**)memory, value, 1); -#elif PHP_VERSION_ID < 70400 - zend_assign_to_variable(cached_zval, value, IS_CV); -#else - zend_assign_to_variable(cached_zval, value, IS_CV, 0); -#endif - } - break; - } - case UPB_TYPE_MESSAGE: { - if (Z_TYPE_P(value) != IS_OBJECT && Z_TYPE_P(value) != IS_NULL) { - zend_error(E_USER_ERROR, "Given value is not message."); - return false; - } - if (Z_TYPE_P(value) == IS_OBJECT && klass != Z_OBJCE_P(value)) { - zend_error(E_USER_ERROR, "Given message does not have correct class."); - return false; - } - -#if PHP_MAJOR_VERSION < 7 - REPLACE_ZVAL_VALUE((CACHED_VALUE*)memory, value, 1); -#else - zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); - if (EXPECTED(property_ptr != value)) { - php_proto_zval_ptr_dtor(property_ptr); - } - - ZVAL_ZVAL(property_ptr, value, 1, 0); -#endif - - break; - } - -#define CASE_TYPE(upb_type, type, c_type, php_type) \ - case UPB_TYPE_##upb_type: { \ - c_type type##_value; \ - if (protobuf_convert_to_##type(value, &type##_value)) { \ - DEREF(memory, c_type) = type##_value; \ - } \ - break; \ - } - CASE_TYPE(INT32, int32, int32_t, LONG) - CASE_TYPE(UINT32, uint32, uint32_t, LONG) - CASE_TYPE(ENUM, int32, int32_t, LONG) - CASE_TYPE(INT64, int64, int64_t, LONG) - CASE_TYPE(UINT64, uint64, uint64_t, LONG) - CASE_TYPE(FLOAT, float, float, DOUBLE) - CASE_TYPE(DOUBLE, double, double, DOUBLE) - CASE_TYPE(BOOL, bool, int8_t, BOOL) - -#undef CASE_TYPE - - default: - break; - } - - return true; -} - -bool native_slot_set_by_array(upb_fieldtype_t type, - const zend_class_entry* klass, void* memory, - zval* value TSRMLS_DC) { -#if PHP_MAJOR_VERSION >= 7 - if (Z_ISREF_P(value)) { - ZVAL_DEREF(value); - } -#endif - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - if (!protobuf_convert_to_string(value)) { - return false; - } - if (type == UPB_TYPE_STRING && - !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) { - zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); - return false; - } - - // Handles repeated/map string field. Memory provided by - // RepeatedField/Map is not initialized. -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(DEREF(memory, zval*)); - PHP_PROTO_ZVAL_STRINGL(DEREF(memory, zval*), Z_STRVAL_P(value), - Z_STRLEN_P(value), 1); -#else - *(zend_string**)memory = - zend_string_init(Z_STRVAL_P(value), Z_STRLEN_P(value), 0); -#endif - break; - } - case UPB_TYPE_MESSAGE: { - if (Z_TYPE_P(value) != IS_OBJECT) { - zend_error(E_USER_ERROR, "Given value is not message."); - return false; - } - if (Z_TYPE_P(value) == IS_OBJECT && klass != Z_OBJCE_P(value)) { - zend_error(E_USER_ERROR, "Given message does not have correct class."); - return false; - } -#if PHP_MAJOR_VERSION < 7 - if (EXPECTED(DEREF(memory, zval*) != value)) { - DEREF(memory, zval*) = value; - Z_ADDREF_P(value); - } -#else - DEREF(memory, zval*) = value; - GC_ADDREF(Z_OBJ_P(value)); -#endif - break; - } - default: - return native_slot_set(type, klass, memory, value TSRMLS_CC); - } - return true; -} - -bool native_slot_set_by_map(upb_fieldtype_t type, const zend_class_entry* klass, - void* memory, zval* value TSRMLS_DC) { -#if PHP_MAJOR_VERSION >= 7 - if (Z_ISREF_P(value)) { - ZVAL_DEREF(value); - } -#endif - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - if (!protobuf_convert_to_string(value)) { - return false; - } - if (type == UPB_TYPE_STRING && - !is_structurally_valid_utf8(Z_STRVAL_P(value), Z_STRLEN_P(value))) { - zend_error(E_USER_ERROR, "Given string is not UTF8 encoded."); - return false; - } - - // Handles repeated/map string field. Memory provided by - // RepeatedField/Map is not initialized. -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(DEREF(memory, zval*)); - PHP_PROTO_ZVAL_STRINGL(DEREF(memory, zval*), Z_STRVAL_P(value), - Z_STRLEN_P(value), 1); -#else - *(zend_string**)memory = - zend_string_init(Z_STRVAL_P(value), Z_STRLEN_P(value), 0); -#endif - break; - } - case UPB_TYPE_MESSAGE: { - if (Z_TYPE_P(value) != IS_OBJECT) { - zend_error(E_USER_ERROR, "Given value is not message."); - return false; - } - if (Z_TYPE_P(value) == IS_OBJECT && klass != Z_OBJCE_P(value)) { - zend_error(E_USER_ERROR, "Given message does not have correct class."); - return false; - } -#if PHP_MAJOR_VERSION < 7 - if (EXPECTED(DEREF(memory, zval*) != value)) { - DEREF(memory, zval*) = value; - Z_ADDREF_P(value); - } -#else - DEREF(memory, zend_object*) = Z_OBJ_P(value); - GC_ADDREF(Z_OBJ_P(value)); -#endif - break; - } - default: - return native_slot_set(type, klass, memory, value TSRMLS_CC); - } - return true; -} - -void native_slot_init(upb_fieldtype_t type, void* memory, CACHED_VALUE* cache) { - switch (type) { - case UPB_TYPE_FLOAT: - DEREF(memory, float) = 0.0; - break; - case UPB_TYPE_DOUBLE: - DEREF(memory, double) = 0.0; - break; - case UPB_TYPE_BOOL: - DEREF(memory, int8_t) = 0; - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - DEREF(memory, CACHED_VALUE*) = cache; - break; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - DEREF(memory, int32_t) = 0; - break; - case UPB_TYPE_INT64: - DEREF(memory, int64_t) = 0; - break; - case UPB_TYPE_UINT32: - DEREF(memory, uint32_t) = 0; - break; - case UPB_TYPE_UINT64: - DEREF(memory, uint64_t) = 0; - break; - default: - break; - } -} - -void native_slot_get(upb_fieldtype_t type, const void* memory, - CACHED_VALUE* cache TSRMLS_DC) { - switch (type) { -#define CASE(upb_type, php_type, c_type) \ - case UPB_TYPE_##upb_type: \ - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_##php_type(CACHED_PTR_TO_ZVAL_PTR(cache), DEREF(memory, c_type)); \ - return; - - CASE(FLOAT, DOUBLE, float) - CASE(DOUBLE, DOUBLE, double) - CASE(BOOL, BOOL, int8_t) - CASE(INT32, LONG, int32_t) - CASE(ENUM, LONG, uint32_t) - -#undef CASE - -#if SIZEOF_LONG == 4 -#define CASE(upb_type, c_type) \ - case UPB_TYPE_##upb_type: { \ - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ - char buffer[MAX_LENGTH_OF_INT64]; \ - sprintf(buffer, "%lld", DEREF(memory, c_type)); \ - PHP_PROTO_ZVAL_STRING(CACHED_PTR_TO_ZVAL_PTR(cache), buffer, 1); \ - return; \ - } -#else -#define CASE(upb_type, c_type) \ - case UPB_TYPE_##upb_type: { \ - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), DEREF(memory, c_type)); \ - return; \ - } -#endif -CASE(UINT64, uint64_t) -CASE(INT64, int64_t) -#undef CASE - - case UPB_TYPE_UINT32: { - // Prepend bit-1 for negative numbers, so that uint32 value will be - // consistent on both 32-bit and 64-bit architectures. - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); - int value = DEREF(memory, int32_t); - if (sizeof(int) == 8) { - value |= (-((value >> 31) & 0x1) & 0xFFFFFFFF00000000); - } - ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), value); - return; - } - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - // For optional string/bytes/message fields, the cache is owned by the - // containing message and should have been updated during - // setting/decoding. However, oneof accessor call this function by - // providing the return value directly, which is not the same as the cache - // value. - zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); - if (CACHED_PTR_TO_ZVAL_PTR(cache) != value) { - PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), Z_STRVAL_P(value), - Z_STRLEN_P(value), 1); - } - break; - } - case UPB_TYPE_MESSAGE: { - // Same as above for string/bytes fields. - zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); - if (CACHED_PTR_TO_ZVAL_PTR(cache) != value) { - ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0); - } - return; - } - default: - return; - } -} - -void native_slot_get_by_array(upb_fieldtype_t type, const void* memory, - CACHED_VALUE* cache TSRMLS_DC) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { -#if PHP_MAJOR_VERSION < 7 - zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); - if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) { - PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), - Z_STRVAL_P(value), Z_STRLEN_P(value), 1); - } -#else - ZVAL_NEW_STR(cache, zend_string_dup(*(zend_string**)memory, 0)); -#endif - return; - } - case UPB_TYPE_MESSAGE: { -#if PHP_MAJOR_VERSION < 7 - zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); - if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) { - ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0); - } -#else - ZVAL_COPY(CACHED_PTR_TO_ZVAL_PTR(cache), memory); -#endif - return; - } - default: - native_slot_get(type, memory, cache TSRMLS_CC); - } -} - -void native_slot_get_by_map_key(upb_fieldtype_t type, const void* memory, - int length, CACHED_VALUE* cache TSRMLS_DC) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), memory, length, 1); - return; - } - default: - native_slot_get(type, memory, cache TSRMLS_CC); - } -} - -void native_slot_get_by_map_value(upb_fieldtype_t type, const void* memory, - CACHED_VALUE* cache TSRMLS_DC) { - switch (type) { - case UPB_TYPE_MESSAGE: { -#if PHP_MAJOR_VERSION < 7 - zval* value = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory); - if (EXPECTED(CACHED_PTR_TO_ZVAL_PTR(cache) != value)) { - ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), value, 1, 0); - } -#else - GC_ADDREF(*(zend_object**)memory); - ZVAL_OBJ(cache, *(zend_object**)memory); -#endif - return; - } - default: - native_slot_get_by_array(type, memory, cache TSRMLS_CC); - } -} - -void native_slot_get_default(upb_fieldtype_t type, - CACHED_VALUE* cache TSRMLS_DC) { - switch (type) { -#define CASE(upb_type, php_type) \ - case UPB_TYPE_##upb_type: \ - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_##php_type(CACHED_PTR_TO_ZVAL_PTR(cache), 0); \ - return; - - CASE(FLOAT, DOUBLE) - CASE(DOUBLE, DOUBLE) - CASE(BOOL, BOOL) - CASE(INT32, LONG) - CASE(UINT32, LONG) - CASE(ENUM, LONG) - -#undef CASE - -#if SIZEOF_LONG == 4 -#define CASE(upb_type) \ - case UPB_TYPE_##upb_type: { \ - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ - PHP_PROTO_ZVAL_STRING(CACHED_PTR_TO_ZVAL_PTR(cache), "0", 1); \ - return; \ - } -#else -#define CASE(upb_type) \ - case UPB_TYPE_##upb_type: { \ - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); \ - ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), 0); \ - return; \ - } -#endif -CASE(UINT64) -CASE(INT64) -#undef CASE - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); - PHP_PROTO_ZVAL_STRINGL(CACHED_PTR_TO_ZVAL_PTR(cache), "", 0, 1); - break; - } - case UPB_TYPE_MESSAGE: { - PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache); - ZVAL_NULL(CACHED_PTR_TO_ZVAL_PTR(cache)); - return; - } - default: - return; - } -} - -// ----------------------------------------------------------------------------- -// Map field utilities. -// ---------------------------------------------------------------------------- - -const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) { - const upb_msgdef* subdef; - if (upb_fielddef_label(field) != UPB_LABEL_REPEATED || - upb_fielddef_type(field) != UPB_TYPE_MESSAGE) { - return NULL; - } - subdef = upb_fielddef_msgsubdef(field); - return upb_msgdef_mapentry(subdef) ? subdef : NULL; -} - -const upb_msgdef* map_entry_msgdef(const upb_fielddef* field) { - const upb_msgdef* subdef = tryget_map_entry_msgdef(field); - assert(subdef); - return subdef; -} - -bool is_map_field(const upb_fielddef* field) { - return tryget_map_entry_msgdef(field) != NULL; -} - -const upb_fielddef* map_field_key(const upb_fielddef* field) { - const upb_msgdef* subdef = map_entry_msgdef(field); - return map_entry_key(subdef); -} - -const upb_fielddef* map_field_value(const upb_fielddef* field) { - const upb_msgdef* subdef = map_entry_msgdef(field); - return map_entry_value(subdef); -} - -const upb_fielddef* map_entry_key(const upb_msgdef* msgdef) { - const upb_fielddef* key_field = upb_msgdef_itof(msgdef, MAP_KEY_FIELD); - assert(key_field != NULL); - return key_field; -} - -const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) { - const upb_fielddef* value_field = upb_msgdef_itof(msgdef, MAP_VALUE_FIELD); - assert(value_field != NULL); - return value_field; -} - -const zend_class_entry* field_type_class( - const upb_fielddef* field PHP_PROTO_TSRMLS_DC) { - if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { - DescriptorInternal* desc = get_msgdef_desc(upb_fielddef_msgsubdef(field)); - register_class(desc, false TSRMLS_CC); - return desc->klass; - } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { - EnumDescriptorInternal* desc = - get_enumdef_enumdesc(upb_fielddef_enumsubdef(field)); - register_class(desc, false TSRMLS_CC); - return desc->klass; - } - return NULL; -} - -// ----------------------------------------------------------------------------- -// Memory layout management. -// ----------------------------------------------------------------------------- - -static size_t align_up_to(size_t offset, size_t granularity) { - // Granularity must be a power of two. - return (offset + granularity - 1) & ~(granularity - 1); -} - -uint32_t* slot_oneof_case(MessageLayout* layout, const void* storage, - const upb_fielddef* field) { - return (uint32_t*)(((uint8_t*)storage) + - layout->fields[upb_fielddef_index(field)].case_offset); -} - -void* slot_memory(MessageLayout* layout, const void* storage, - const upb_fielddef* field) { - return ((uint8_t*)storage) + layout->fields[upb_fielddef_index(field)].offset; -} - -MessageLayout* create_layout(const upb_msgdef* msgdef) { - MessageLayout* layout = SYS_MALLOC(MessageLayout); - int nfields = upb_msgdef_numfields(msgdef); - upb_msg_field_iter it; - upb_msg_oneof_iter oit; - size_t off = 0; - int i = 0; - - // Reserve space for unknown fields. - off += sizeof(void*); - - layout->empty_template = NULL; - - TSRMLS_FETCH(); - DescriptorInternal* desc = get_msgdef_desc(msgdef); - register_class(desc, false TSRMLS_CC); - layout->fields = SYS_MALLOC_N(MessageField, nfields); - - for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - size_t field_size; - - if (upb_fielddef_containingoneof(field)) { - // Oneofs are handled separately below. - continue; - } - - // Allocate |field_size| bytes for this field in the layout. - field_size = 0; - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - field_size = sizeof(zval*); - } else { - field_size = native_slot_size(upb_fielddef_type(field)); - } - - // Align current offset up to | size | granularity. - off = align_up_to(off, field_size); - layout->fields[upb_fielddef_index(field)].offset = off; - layout->fields[upb_fielddef_index(field)].case_offset = - MESSAGE_FIELD_NO_CASE; - - const char* fieldname = upb_fielddef_name(field); - -#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - zend_class_entry* old_scope = EG(scope); - EG(scope) = desc->klass; -#else - zend_class_entry* old_scope = EG(fake_scope); - EG(fake_scope) = desc->klass; -#endif - -#if PHP_MAJOR_VERSION < 7 - zval member; - ZVAL_STRINGL(&member, fieldname, strlen(fieldname), 0); - zend_property_info* property_info = - zend_get_property_info(desc->klass, &member, true TSRMLS_CC); -#else - zend_string* member = zend_string_init(fieldname, strlen(fieldname), 1); - zend_property_info* property_info = - zend_get_property_info(desc->klass, member, true); - zend_string_release(member); -#endif - -#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - EG(scope) = old_scope; -#else - EG(fake_scope) = old_scope; -#endif - - layout->fields[upb_fielddef_index(field)].cache_index = - property_info->offset; - off += field_size; - } - - // Handle oneofs now -- we iterate over oneofs specifically and allocate only - // one slot per oneof. - // - // We assign all value slots first, then pack the 'case' fields at the end, - // since in the common case (modern 64-bit platform) these are 8 bytes and 4 - // bytes respectively and we want to avoid alignment overhead. - // - // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value - // space for oneof cases is conceptually as wide as field tag numbers. In - // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K - // members (8 or 16 bits respectively), so conceivably we could assign - // consecutive case numbers and then pick a smaller oneof case slot size, but - // the complexity to implement this indirection is probably not worthwhile. - for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between - // all fields. - size_t field_size = NATIVE_SLOT_MAX_SIZE; - // Align the offset . - off = align_up_to( off, field_size); - // Assign all fields in the oneof this same offset. - const char* oneofname = upb_oneofdef_name(oneof); - for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* field = upb_oneof_iter_field(&fit); - layout->fields[upb_fielddef_index(field)].offset = off; - -#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - zend_class_entry* old_scope = EG(scope); - EG(scope) = desc->klass; -#else - zend_class_entry* old_scope = EG(fake_scope); - EG(fake_scope) = desc->klass; -#endif - -#if PHP_MAJOR_VERSION < 7 - zval member; - ZVAL_STRINGL(&member, oneofname, strlen(oneofname), 0); - zend_property_info* property_info = - zend_get_property_info(desc->klass, &member, true TSRMLS_CC); -#else - zend_string* member = zend_string_init(oneofname, strlen(oneofname), 1); - zend_property_info* property_info = - zend_get_property_info(desc->klass, member, true); - zend_string_release(member); -#endif - -#if PHP_MAJOR_VERSION < 7 || (PHP_MAJOR_VERSION == 7 && PHP_MINOR_VERSION == 0) - EG(scope) = old_scope; -#else - EG(fake_scope) = old_scope; -#endif - - layout->fields[upb_fielddef_index(field)].cache_index = - property_info->offset; - } - i++; - off += field_size; - } - - // Now the case offset. - for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - size_t field_size = sizeof(uint32_t); - // Align the offset . - off = (off + field_size - 1) & ~(field_size - 1); - // Assign all fields in the oneof this same offset. - for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* field = upb_oneof_iter_field(&fit); - layout->fields[upb_fielddef_index(field)].case_offset = off; - } - off += field_size; - } - - layout->size = off; - layout->msgdef = msgdef; - - // Create the empty message template. - layout->empty_template = SYS_MALLOC_N(char, layout->size); - memset(layout->empty_template, 0, layout->size); - - return layout; -} - -void free_layout(MessageLayout* layout) { - SYS_FREE(layout->empty_template); - SYS_FREE(layout->fields); - SYS_FREE(layout); -} - -void layout_init(MessageLayout* layout, void* storage, - zend_object* object PHP_PROTO_TSRMLS_DC) { - memcpy(storage, layout->empty_template, layout->size); -} - -// Switch memory for processing for singular fields based on field type. -// * primitive fields: memory -// * others (string, bytes and message): cache (the correspond zval -// property) -static void* value_memory( - upb_fieldtype_t type, void* memory, CACHED_VALUE* cache) { - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: - return cache; - default: - // No operation - break; - } - return memory; -} - -CACHED_VALUE* find_zval_property( - MessageHeader* header, const upb_fielddef* field) { - int property_cache_index = - header->descriptor->layout->fields[upb_fielddef_index(field)] - .cache_index; - return OBJ_PROP(&header->std, property_cache_index); -} - -zval* layout_get(MessageLayout* layout, MessageHeader* header, - const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC) { - const void* storage = message_data(header); - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - if (*oneof_case != upb_fielddef_number(field)) { - native_slot_get_default(upb_fielddef_type(field), cache TSRMLS_CC); - return CACHED_PTR_TO_ZVAL_PTR(cache); - } - // Intentional fall through to be handled as a signuarl field. - } else if (is_map_field(field)) { - map_field_ensure_created(field, cache PHP_PROTO_TSRMLS_CC); - return CACHED_PTR_TO_ZVAL_PTR(cache); - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - repeated_field_ensure_created(field, cache PHP_PROTO_TSRMLS_CC); - return CACHED_PTR_TO_ZVAL_PTR(cache); - } - - CACHED_VALUE* stored_cache = find_zval_property(header, field); - - if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE && - is_wrapper_msg(upb_fielddef_msgsubdef(field))) { - zval * cached_zval = CACHED_PTR_TO_ZVAL_PTR(stored_cache); -#if PHP_MAJOR_VERSION >= 7 - zend_object* obj; -#endif - if (Z_TYPE_P(cached_zval) != IS_OBJECT && - Z_TYPE_P(cached_zval) != IS_NULL) { - // Needs to expand value to wrapper. - const upb_msgdef* submsgdef = upb_fielddef_msgsubdef(field); - const upb_fielddef* value_field = upb_msgdef_itof(submsgdef, 1); - MessageHeader* submsg; - DescriptorInternal* subdesc = get_msgdef_desc(submsgdef); - register_class(subdesc, false TSRMLS_CC); - zend_class_entry* subklass = subdesc->klass; -#if PHP_MAJOR_VERSION < 7 - zval* val = NULL; - MAKE_STD_ZVAL(val); - ZVAL_OBJ(val, subklass->create_object(subklass TSRMLS_CC)); - submsg = UNBOX(MessageHeader, val); -#else - obj = subklass->create_object(subklass TSRMLS_CC); - submsg = (MessageHeader*)((char*)obj - XtOffsetOf(MessageHeader, std)); -#endif - custom_data_init(subklass, submsg PHP_PROTO_TSRMLS_CC); - - layout_set(subdesc->layout, submsg, value_field, cached_zval TSRMLS_CC); -#if PHP_MAJOR_VERSION < 7 - ZVAL_ZVAL(cached_zval, val, 1, 1); -#else - ZVAL_OBJ(cached_zval, obj); -#endif - } - if (stored_cache != cache) { - ZVAL_ZVAL(CACHED_PTR_TO_ZVAL_PTR(cache), cached_zval, 1, 0); - } - } else { - upb_fieldtype_t type = upb_fielddef_type(field); - native_slot_get(type, value_memory(type, memory, stored_cache), - cache TSRMLS_CC); - } - return CACHED_PTR_TO_ZVAL_PTR(cache); -} - -void layout_set(MessageLayout* layout, MessageHeader* header, - const upb_fielddef* field, zval* val TSRMLS_DC) { - void* storage = message_data(header); - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - *oneof_case = upb_fielddef_number(field); - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - // Works for both repeated and map fields - CACHED_VALUE* cached = find_zval_property(header, field); - zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR(cached); - - if (EXPECTED(property_ptr != val)) { - zend_class_entry *subce = NULL; - zval converted_value; - - if (upb_fielddef_ismap(field)) { - const upb_msgdef* mapmsg = upb_fielddef_msgsubdef(field); - const upb_fielddef* keyfield = upb_msgdef_ntof(mapmsg, "key", 3); - const upb_fielddef* valuefield = upb_msgdef_ntof(mapmsg, "value", 5); - if (upb_fielddef_descriptortype(valuefield) == - UPB_DESCRIPTOR_TYPE_MESSAGE) { - const upb_msgdef* submsg = upb_fielddef_msgsubdef(valuefield); - DescriptorInternal* subdesc = get_msgdef_desc(submsg); - register_class(subdesc, false TSRMLS_CC); - subce = subdesc->klass; - } - check_map_field(subce, upb_fielddef_descriptortype(keyfield), - upb_fielddef_descriptortype(valuefield), val, - &converted_value); - } else { - if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { - const upb_msgdef* submsg = upb_fielddef_msgsubdef(field); - DescriptorInternal* subdesc = get_msgdef_desc(submsg); - register_class(subdesc, false TSRMLS_CC); - subce = subdesc->klass; - } - - check_repeated_field(subce, upb_fielddef_descriptortype(field), val, - &converted_value); - } -#if PHP_MAJOR_VERSION < 7 - REPLACE_ZVAL_VALUE((zval**)cached, &converted_value, 1); -#else - php_proto_zval_ptr_dtor(property_ptr); - ZVAL_ZVAL(property_ptr, &converted_value, 1, 0); -#endif - zval_dtor(&converted_value); - } - return; - } - - upb_fieldtype_t type = upb_fielddef_type(field); - zend_class_entry *ce = NULL; - if (type == UPB_TYPE_MESSAGE) { - const upb_msgdef* msg = upb_fielddef_msgsubdef(field); - DescriptorInternal* desc = get_msgdef_desc(msg); - register_class(desc, false TSRMLS_CC); - ce = desc->klass; - } - CACHED_VALUE* cache = find_zval_property(header, field); - native_slot_set( - type, ce, value_memory(upb_fielddef_type(field), memory, cache), - val TSRMLS_CC); -} - -static void native_slot_merge( - const upb_fielddef* field, const void* from_memory, - void* to_memory PHP_PROTO_TSRMLS_DC) { - upb_fieldtype_t type = upb_fielddef_type(field); - zend_class_entry* ce = NULL; - if (!native_slot_is_default(type, from_memory)) { - switch (type) { -#define CASE_TYPE(upb_type, c_type) \ - case UPB_TYPE_##upb_type: { \ - DEREF(to_memory, c_type) = DEREF(from_memory, c_type); \ - break; \ - } - CASE_TYPE(INT32, int32_t) - CASE_TYPE(UINT32, uint32_t) - CASE_TYPE(ENUM, int32_t) - CASE_TYPE(INT64, int64_t) - CASE_TYPE(UINT64, uint64_t) - CASE_TYPE(FLOAT, float) - CASE_TYPE(DOUBLE, double) - CASE_TYPE(BOOL, int8_t) - -#undef CASE_TYPE - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - native_slot_set(type, NULL, to_memory, - CACHED_PTR_TO_ZVAL_PTR(from_memory) PHP_PROTO_TSRMLS_CC); - break; - case UPB_TYPE_MESSAGE: { - const upb_msgdef* msg = upb_fielddef_msgsubdef(field); - DescriptorInternal* desc = get_msgdef_desc(msg); - register_class(desc, false TSRMLS_CC); - ce = desc->klass; - if (native_slot_is_default(type, to_memory)) { -#if PHP_MAJOR_VERSION < 7 - SEPARATE_ZVAL_IF_NOT_REF((zval**)to_memory); -#endif - CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR( - CACHED_PTR_TO_ZVAL_PTR(to_memory), ce); - MessageHeader* submsg = - UNBOX(MessageHeader, CACHED_PTR_TO_ZVAL_PTR(to_memory)); - custom_data_init(ce, submsg PHP_PROTO_TSRMLS_CC); - } - - MessageHeader* sub_from = - UNBOX(MessageHeader, - CACHED_PTR_TO_ZVAL_PTR(from_memory)); - MessageHeader* sub_to = - UNBOX(MessageHeader, - CACHED_PTR_TO_ZVAL_PTR(to_memory)); - - layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC); - break; - } - } - } -} - -static void native_slot_merge_by_array(const upb_fielddef* field, const void* from_memory, - void* to_memory PHP_PROTO_TSRMLS_DC) { - upb_fieldtype_t type = upb_fielddef_type(field); - switch (type) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(DEREF(to_memory, zval*)); - PHP_PROTO_ZVAL_STRINGL(DEREF(to_memory, zval*), - Z_STRVAL_P(*(zval**)from_memory), - Z_STRLEN_P(*(zval**)from_memory), 1); -#else - DEREF(to_memory, zend_string*) = - zend_string_dup(*(zend_string**)from_memory, 0); -#endif - break; - } - case UPB_TYPE_MESSAGE: { - DescriptorInternal* desc = get_msgdef_desc(upb_fielddef_msgsubdef(field)); - register_class(desc, false TSRMLS_CC); - zend_class_entry* ce = desc->klass; -#if PHP_MAJOR_VERSION < 7 - MAKE_STD_ZVAL(DEREF(to_memory, zval*)); - CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(DEREF(to_memory, zval*), ce); -#else - DEREF(to_memory, zend_object*) = ce->create_object(ce TSRMLS_CC); -#endif - MessageHeader* sub_from = UNBOX_HASHTABLE_VALUE( - MessageHeader, DEREF(from_memory, PHP_PROTO_HASHTABLE_VALUE)); - MessageHeader* sub_to = UNBOX_HASHTABLE_VALUE( - MessageHeader, DEREF(to_memory, PHP_PROTO_HASHTABLE_VALUE)); - custom_data_init(ce, sub_to PHP_PROTO_TSRMLS_CC); - - layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC); - break; - } - default: - native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC); - break; - } -} - -void layout_merge(MessageLayout* layout, MessageHeader* from, - MessageHeader* to PHP_PROTO_TSRMLS_DC) { - int i, j; - upb_msg_field_iter it; - - for (upb_msg_field_begin(&it, layout->msgdef), i = 0; !upb_msg_field_done(&it); - upb_msg_field_next(&it), i++) { - const upb_fielddef* field = upb_msg_iter_field(&it); - - void* to_memory = slot_memory(layout, message_data(to), field); - void* from_memory = slot_memory(layout, message_data(from), field); - - if (upb_fielddef_containingoneof(field)) { - uint32_t oneof_case_offset = - layout->fields[upb_fielddef_index(field)].case_offset; - // For a oneof, check that this field is actually present -- skip all the - // below if not. - if (DEREF((message_data(from) + oneof_case_offset), uint32_t) != - upb_fielddef_number(field)) { - continue; - } - uint32_t* from_oneof_case = slot_oneof_case(layout, message_data(from), field); - uint32_t* to_oneof_case = slot_oneof_case(layout, message_data(to), field); - - // For non-singular fields, the related memory needs to point to the - // actual zval in properties table first. - switch (upb_fielddef_type(field)) { - case UPB_TYPE_MESSAGE: - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - int property_cache_index = - layout->fields[upb_fielddef_index(field)].cache_index; - DEREF(to_memory, CACHED_VALUE*) = - OBJ_PROP(&to->std, property_cache_index); - break; - } - default: - break; - } - - *to_oneof_case = *from_oneof_case; - - // Otherwise, fall through to the appropriate singular-field handler - // below. - } - - if (is_map_field(field)) { - int size, key_length, value_length; - MapIter map_it; - - CACHED_VALUE* from_cache = find_zval_property(from, field); - CACHED_VALUE* to_cache = find_zval_property(to, field); - - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(from_cache)) == IS_NULL) { - continue; - } - map_field_ensure_created(field, to_cache PHP_PROTO_TSRMLS_CC); - - zval* to_map_php = CACHED_PTR_TO_ZVAL_PTR(to_cache); - zval* from_map_php = CACHED_PTR_TO_ZVAL_PTR(from_cache); - - Map* to_map = UNBOX(Map, to_map_php); - Map* from_map = UNBOX(Map, from_map_php); - - size = upb_strtable_count(&from_map->table); - if (size == 0) continue; - - const upb_msgdef *mapentry_def = upb_fielddef_msgsubdef(field); - const upb_fielddef *value_field = upb_msgdef_itof(mapentry_def, 2); - - for (map_begin(from_map_php, &map_it TSRMLS_CC); !map_done(&map_it); - map_next(&map_it)) { - const char* key = map_iter_key(&map_it, &key_length); - upb_value from_value = map_iter_value(&map_it, &value_length); - upb_value to_value; - void* from_mem = upb_value_memory(&from_value); - void* to_mem = upb_value_memory(&to_value); - memset(to_mem, 0, native_slot_size(to_map->value_type)); - - native_slot_merge_by_array(value_field, from_mem, - to_mem PHP_PROTO_TSRMLS_CC); - - map_index_set(to_map, key, key_length, to_value); - } - - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - CACHED_VALUE* from_cache = find_zval_property(from, field); - CACHED_VALUE* to_cache = find_zval_property(to, field); - - if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(from_cache)) == IS_NULL) { - continue; - } - repeated_field_ensure_created(field, to_cache PHP_PROTO_TSRMLS_CC); - - zval* to_array_php = CACHED_PTR_TO_ZVAL_PTR(to_cache); - zval* from_array_php = CACHED_PTR_TO_ZVAL_PTR(from_cache); - RepeatedField* to_array = UNBOX(RepeatedField, to_array_php); - RepeatedField* from_array = UNBOX(RepeatedField, from_array_php); - - int size = zend_hash_num_elements(PHP_PROTO_HASH_OF(from_array->array)); - if (size > 0) { - for (j = 0; j < size; j++) { - void* from_memory = NULL; - void* to_memory = - ALLOC_N(char, native_slot_size(upb_fielddef_type(field))); - memset(to_memory, 0, native_slot_size(upb_fielddef_type(field))); - - if (to_array->type == UPB_TYPE_MESSAGE) { - php_proto_zend_hash_index_find_zval( - PHP_PROTO_HASH_OF(from_array->array), j, (void**)&from_memory); -#if PHP_MAJOR_VERSION >= 7 - from_memory = &Z_OBJ_P((zval*)from_memory); -#endif - } else { - php_proto_zend_hash_index_find_mem( - PHP_PROTO_HASH_OF(from_array->array), j, (void**)&from_memory); - } - - native_slot_merge_by_array(field, from_memory, - to_memory PHP_PROTO_TSRMLS_CC); - repeated_field_push_native(to_array, to_memory); - FREE(to_memory); - } - } - } else { - switch (upb_fielddef_type(field)) { - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: { - CACHED_VALUE* from_cache = find_zval_property(from, field); - CACHED_VALUE* to_cache = find_zval_property(to, field); - native_slot_merge(field, from_cache, to_cache PHP_PROTO_TSRMLS_CC); - break; - } - default: - native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC); - break; - } - } - } -} - -const char* layout_get_oneof_case(MessageLayout* layout, const void* storage, - const upb_oneofdef* oneof TSRMLS_DC) { - upb_oneof_iter i; - const upb_fielddef* first_field = NULL; - - // Oneof is guaranteed to have at least one field. Get the first field. - for(upb_oneof_begin(&i, oneof); !upb_oneof_done(&i); upb_oneof_next(&i)) { - first_field = upb_oneof_iter_field(&i); - break; - } - - uint32_t* oneof_case = slot_oneof_case(layout, storage, first_field); - if (*oneof_case == 0) { - return ""; - } - const upb_fielddef* field = upb_oneofdef_itof(oneof, *oneof_case); - return upb_fielddef_name(field); -} diff --git a/php/ext/google/protobuf/type_check.c b/php/ext/google/protobuf/type_check.c deleted file mode 100644 index 84d06be7efb8..000000000000 --- a/php/ext/google/protobuf/type_check.c +++ /dev/null @@ -1,680 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -// The Zend Engine License, version 2.00 -// Copyright (c) 1999-2002 Zend Technologies Ltd. All rights reserved. -// -------------------------------------------------------------------- -// -// Redistribution and use in source and binary forms, with or without -// modification, is permitted provided that the following conditions -// are met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. 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. -// -// 3. The names "Zend" and "Zend Engine" must not be used to endorse -// or promote products derived from this software without prior -// permission from Zend Technologies Ltd. For written permission, -// please contact license@zend.com. -// -// 4. Zend Technologies Ltd. may publish revised and/or new versions -// of the license from time to time. Each version will be given a -// distinguishing version number. -// Once covered code has been published under a particular version -// of the license, you may always continue to use it under the -// terms of that version. You may also choose to use such covered -// code under the terms of any subsequent version of the license -// published by Zend Technologies Ltd. No one other than Zend -// Technologies Ltd. has the right to modify the terms applicable -// to covered code created under this License. -// -// 5. Redistributions of any form whatsoever must retain the following -// acknowledgment: -// "This product includes the Zend Engine, freely available at -// http://www.zend.com" -// -// 6. All advertising materials mentioning features or use of this -// software must display the following acknowledgment: -// "The Zend Engine is freely available at http://www.zend.com" -// -// THIS SOFTWARE IS PROVIDED BY ZEND TECHNOLOGIES LTD. ``AS IS'' AND -// ANY EXPRESSED 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 ZEND -// TECHNOLOGIES LTD. 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. - -#include -#include - -#include "protobuf.h" -#include "utf8.h" - -static zend_class_entry* util_type; -static const char int64_min_digits[] = "9223372036854775808"; - -ZEND_BEGIN_ARG_INFO_EX(arg_check_optional, 0, 0, 1) - ZEND_ARG_INFO(1, val) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arg_check_message, 0, 0, 2) - ZEND_ARG_INFO(1, val) - ZEND_ARG_INFO(0, klass) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arg_check_repeated, 0, 0, 2) - ZEND_ARG_INFO(1, val) - ZEND_ARG_INFO(0, type) - ZEND_ARG_INFO(0, klass) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arg_check_map, 0, 0, 3) - ZEND_ARG_INFO(1, val) - ZEND_ARG_INFO(0, key_type) - ZEND_ARG_INFO(0, value_type) - ZEND_ARG_INFO(0, klass) -ZEND_END_ARG_INFO() - -static zend_function_entry util_methods[] = { - PHP_ME(Util, checkInt32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkUint32, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkInt64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkUint64, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkEnum, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkFloat, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkDouble, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkBool, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkString, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkBytes, arg_check_optional, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkMessage, arg_check_message, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkMapField, arg_check_map, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(Util, checkRepeatedField, arg_check_repeated, - ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - ZEND_FE_END -}; - -void util_init(TSRMLS_D) { - zend_class_entry class_type; - INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBUtil", - util_methods); - util_type = zend_register_internal_class(&class_type TSRMLS_CC); -} - -// ----------------------------------------------------------------------------- -// Type checking/conversion. -// ----------------------------------------------------------------------------- - -// This is modified from is_numeric_string in zend_operators.h. The behavior of -// this function is the same as is_numeric_string, except that this takes -// int64_t as input instead of long. -static zend_uchar convert_numeric_string( - const char *str, int length, int64_t *lval, double *dval) { - const char *ptr; - int base = 10, digits = 0, dp_or_e = 0; - double local_dval = 0.0; - zend_uchar type; - - if (length == 0) { - return IS_NULL; - } - - while (*str == ' ' || *str == '\t' || *str == '\n' || - *str == '\r' || *str == '\v' || *str == '\f') { - str++; - length--; - } - ptr = str; - - if (*ptr == '-' || *ptr == '+') { - ptr++; - } - - if (ZEND_IS_DIGIT(*ptr)) { - // Handle hex numbers - // str is used instead of ptr to disallow signs and keep old behavior. - if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) { - base = 16; - ptr += 2; - } - - // Skip any leading 0s. - while (*ptr == '0') { - ptr++; - } - - // Count the number of digits. If a decimal point/exponent is found, - // it's a double. Otherwise, if there's a dval or no need to check for - // a full match, stop when there are too many digits for a int64 */ - for (type = IS_LONG; - !(digits >= MAX_LENGTH_OF_INT64 && dval); - digits++, ptr++) { -check_digits: - if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) { - continue; - } else if (base == 10) { - if (*ptr == '.' && dp_or_e < 1) { - goto process_double; - } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) { - const char *e = ptr + 1; - - if (*e == '-' || *e == '+') { - ptr = e++; - } - if (ZEND_IS_DIGIT(*e)) { - goto process_double; - } - } - } - break; - } - - if (base == 10) { - if (digits >= MAX_LENGTH_OF_INT64) { - dp_or_e = -1; - goto process_double; - } - } else if (!(digits < SIZEOF_INT64 * 2 || - (digits == SIZEOF_INT64 * 2 && ptr[-digits] <= '7'))) { - if (dval) { - local_dval = zend_hex_strtod(str, &ptr); - } - type = IS_DOUBLE; - } - } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) { -process_double: - type = IS_DOUBLE; - - // If there's a dval, do the conversion; else continue checking - // the digits if we need to check for a full match. - if (dval) { - local_dval = zend_strtod(str, &ptr); - } else if (dp_or_e != -1) { - dp_or_e = (*ptr++ == '.') ? 1 : 2; - goto check_digits; - } - } else { - return IS_NULL; - } - if (ptr != str + length) { - zend_error(E_NOTICE, "A non well formed numeric value encountered"); - return 0; - } - - if (type == IS_LONG) { - if (digits == MAX_LENGTH_OF_INT64 - 1) { - int cmp = strcmp(&ptr[-digits], int64_min_digits); - - if (!(cmp < 0 || (cmp == 0 && *str == '-'))) { - if (dval) { - *dval = zend_strtod(str, NULL); - } - - return IS_DOUBLE; - } - } - if (lval) { - *lval = strtoll(str, NULL, base); - } - return IS_LONG; - } else { - if (dval) { - *dval = local_dval; - } - return IS_DOUBLE; - } -} - -#define CONVERT_TO_INTEGER(type) \ - static bool convert_int64_to_##type(int64_t val, type##_t* type##_value) { \ - *type##_value = (type##_t)val; \ - return true; \ - } \ - \ - static bool convert_double_to_##type(double val, type##_t* type##_value) { \ - *type##_value = (type##_t)zend_dval_to_lval(val); \ - return true; \ - } \ - \ - static bool convert_string_to_##type(const char* val, int len, \ - type##_t* type##_value) { \ - int64_t lval; \ - double dval; \ - TSRMLS_FETCH(); \ - switch (convert_numeric_string(val, len, &lval, &dval)) { \ - case IS_DOUBLE: { \ - return convert_double_to_##type(dval, type##_value); \ - } \ - case IS_LONG: { \ - return convert_int64_to_##type(lval, type##_value); \ - } \ - default: \ - zend_throw_exception(NULL, \ - "Given string value cannot be converted to integer.", \ - 0 TSRMLS_CC); \ - return false; \ - } \ - } \ - \ - bool protobuf_convert_to_##type(zval* from, type##_t* to) { \ - TSRMLS_FETCH(); \ - switch (Z_TYPE_P(from)) { \ - case IS_LONG: { \ - return convert_int64_to_##type(Z_LVAL_P(from), to); \ - } \ - case IS_DOUBLE: { \ - return convert_double_to_##type(Z_DVAL_P(from), to); \ - } \ - case IS_STRING: { \ - return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \ - to); \ - } \ - default: { \ - zend_throw_exception(NULL, \ - "Given value cannot be converted to integer.", \ - 0 TSRMLS_CC); \ - return false; \ - } \ - } \ - return false; \ - } - -CONVERT_TO_INTEGER(int32); -CONVERT_TO_INTEGER(uint32); -CONVERT_TO_INTEGER(int64); -CONVERT_TO_INTEGER(uint64); - -#undef CONVERT_TO_INTEGER - -#define CONVERT_TO_FLOAT(type) \ - static bool convert_int64_to_##type(int64_t val, type* type##_value) { \ - *type##_value = (type)val; \ - return true; \ - } \ - \ - static bool convert_double_to_##type(double val, type* type##_value) { \ - *type##_value = (type)val; \ - return true; \ - } \ - \ - static bool convert_string_to_##type(const char* val, int len, \ - type* type##_value) { \ - int64_t lval; \ - double dval; \ - \ - TSRMLS_FETCH(); \ - switch (convert_numeric_string(val, len, &lval, &dval)) { \ - case IS_DOUBLE: { \ - *type##_value = (type)dval; \ - return true; \ - } \ - case IS_LONG: { \ - *type##_value = (type)lval; \ - return true; \ - } \ - default: \ - zend_throw_exception(NULL, \ - "Given string value cannot be converted to integer.", \ - 0 TSRMLS_CC); \ - return false; \ - } \ - } \ - \ - bool protobuf_convert_to_##type(zval* from, type* to) { \ - TSRMLS_FETCH(); \ - switch (Z_TYPE_P(from)) { \ - case IS_LONG: { \ - return convert_int64_to_##type(Z_LVAL_P(from), to); \ - } \ - case IS_DOUBLE: { \ - return convert_double_to_##type(Z_DVAL_P(from), to); \ - } \ - case IS_STRING: { \ - return convert_string_to_##type(Z_STRVAL_P(from), Z_STRLEN_P(from), \ - to); \ - } \ - default: { \ - zend_throw_exception(NULL, \ - "Given value cannot be converted to integer.", \ - 0 TSRMLS_CC); \ - return false; \ - } \ - } \ - return false; \ - } - -CONVERT_TO_FLOAT(float); -CONVERT_TO_FLOAT(double); - -#undef CONVERT_TO_FLOAT - -bool protobuf_convert_to_bool(zval* from, int8_t* to) { - TSRMLS_FETCH(); - switch (Z_TYPE_P(from)) { -#if PHP_MAJOR_VERSION < 7 - case IS_BOOL: - *to = (int8_t)Z_BVAL_P(from); - break; -#else - case IS_TRUE: - *to = 1; - break; - case IS_FALSE: - *to = 0; - break; -#endif - case IS_LONG: - *to = (int8_t)(Z_LVAL_P(from) != 0); - break; - case IS_DOUBLE: - *to = (int8_t)(Z_LVAL_P(from) != 0); - break; - case IS_STRING: { - if (Z_STRLEN_P(from) == 0 || - (Z_STRLEN_P(from) == 1 && Z_STRVAL_P(from)[0] == '0')) { - *to = 0; - } else { - *to = 1; - } - } break; - default: { - zend_throw_exception( - NULL, "Given value cannot be converted to bool.", - 0 TSRMLS_CC); - return false; - } - } - return true; -} - -bool protobuf_convert_to_string(zval* from) { -#if PHP_MAJOR_VERSION >= 7 - if (Z_ISREF_P(from)) { - ZVAL_DEREF(from); - } -#endif - TSRMLS_FETCH(); - switch (Z_TYPE_P(from)) { - case IS_STRING: { - return true; - } -#if PHP_MAJOR_VERSION < 7 - case IS_BOOL: -#else - case IS_TRUE: - case IS_FALSE: -#endif - case IS_LONG: - case IS_DOUBLE: { - zval tmp; - php_proto_zend_make_printable_zval(from, &tmp); - ZVAL_COPY_VALUE(from, &tmp); - return true; - } - default: - zend_throw_exception( - NULL, "Given value cannot be converted to string.", - 0 TSRMLS_CC); - return false; - } -} - -// ----------------------------------------------------------------------------- -// PHP Functions. -// ----------------------------------------------------------------------------- - -// The implementation of type checking for primitive fields is empty. This is -// because type checking is done when direct assigning message fields (e.g., -// foo->a = 1). Functions defined here are place holders in generated code for -// pure PHP implementation (c extension and pure PHP share the same generated -// code). -#define PHP_TYPE_CHECK(type) \ - PHP_METHOD(Util, check##type) {} - -PHP_TYPE_CHECK(Int32) -PHP_TYPE_CHECK(Uint32) -PHP_TYPE_CHECK(Int64) -PHP_TYPE_CHECK(Uint64) -PHP_TYPE_CHECK(Enum) -PHP_TYPE_CHECK(Float) -PHP_TYPE_CHECK(Double) -PHP_TYPE_CHECK(Bool) -PHP_TYPE_CHECK(String) -PHP_TYPE_CHECK(Bytes) - -#undef PHP_TYPE_CHECK - -PHP_METHOD(Util, checkMessage) { - zval* val; - zend_class_entry* klass = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o!C", &val, &klass) == - FAILURE) { - return; - } - if (val == NULL) { - RETURN_NULL(); - } - if (!instanceof_function(Z_OBJCE_P(val), klass TSRMLS_CC)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Given value is not an instance of %s.", -#if PHP_MAJOR_VERSION < 7 - klass->name); -#else - ZSTR_VAL(klass->name)); -#endif - return; - } - RETURN_ZVAL(val, 1, 0); -} - -void check_repeated_field(const zend_class_entry* klass, PHP_PROTO_LONG type, - zval* val, zval* return_value) { -#if PHP_MAJOR_VERSION >= 7 - if (Z_ISREF_P(val)) { - ZVAL_DEREF(val); - } -#endif - - TSRMLS_FETCH(); - if (Z_TYPE_P(val) == IS_ARRAY) { - HashTable* table = HASH_OF(val); - HashPosition pointer; - void* memory; - -#if PHP_MAJOR_VERSION < 7 - zval* repeated_field; - MAKE_STD_ZVAL(repeated_field); -#else - zval repeated_field; -#endif - - repeated_field_create_with_type(repeated_field_type, to_fieldtype(type), - klass, &repeated_field TSRMLS_CC); - - for (zend_hash_internal_pointer_reset_ex(table, &pointer); - php_proto_zend_hash_get_current_data_ex(table, (void**)&memory, - &pointer) == SUCCESS; - zend_hash_move_forward_ex(table, &pointer)) { - repeated_field_handlers->write_dimension( - CACHED_TO_ZVAL_PTR(repeated_field), NULL, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC); - } - - RETURN_ZVAL(CACHED_TO_ZVAL_PTR(repeated_field), 1, 1); - - } else if (Z_TYPE_P(val) == IS_OBJECT) { - if (!instanceof_function(Z_OBJCE_P(val), repeated_field_type TSRMLS_CC)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Given value is not an instance of %s.", -#if PHP_MAJOR_VERSION < 7 - repeated_field_type->name); -#else - ZSTR_VAL(repeated_field_type->name)); -#endif - return; - } - RepeatedField* intern = UNBOX(RepeatedField, val); - if (to_fieldtype(type) != intern->type) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Incorrect repeated field type."); - return; - } - if (klass != NULL && intern->msg_ce != klass) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Expect a repeated field of %s, but %s is given.", -#if PHP_MAJOR_VERSION < 7 - klass->name, intern->msg_ce->name); -#else - ZSTR_VAL(klass->name), - ZSTR_VAL(intern->msg_ce->name)); -#endif - return; - } - RETURN_ZVAL(val, 1, 0); - } else { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Incorrect repeated field type."); - return; - } -} - -PHP_METHOD(Util, checkRepeatedField) { - zval* val; - PHP_PROTO_LONG type; - const zend_class_entry* klass = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl|C", &val, &type, - &klass) == FAILURE) { - return; - } - RETURN_ZVAL(val, 1, 0); -} - -void check_map_field(const zend_class_entry* klass, PHP_PROTO_LONG key_type, - PHP_PROTO_LONG value_type, zval* val, zval* return_value) { -#if PHP_MAJOR_VERSION >= 7 - if (Z_ISREF_P(val)) { - ZVAL_DEREF(val); - } -#endif - - TSRMLS_FETCH(); - if (Z_TYPE_P(val) == IS_ARRAY) { - HashTable* table = Z_ARRVAL_P(val); - HashPosition pointer; - zval key; - void* value; - -#if PHP_MAJOR_VERSION < 7 - zval* map_field; - MAKE_STD_ZVAL(map_field); -#else - zval map_field; -#endif - - map_field_create_with_type(map_field_type, to_fieldtype(key_type), - to_fieldtype(value_type), klass, - &map_field TSRMLS_CC); - - for (zend_hash_internal_pointer_reset_ex(table, &pointer); - php_proto_zend_hash_get_current_data_ex(table, (void**)&value, - &pointer) == SUCCESS; - zend_hash_move_forward_ex(table, &pointer)) { - zend_hash_get_current_key_zval_ex(table, &key, &pointer); - map_field_handlers->write_dimension( - CACHED_TO_ZVAL_PTR(map_field), &key, - CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value) TSRMLS_CC); - zval_dtor(&key); - } - - RETURN_ZVAL(CACHED_TO_ZVAL_PTR(map_field), 1, 1); - } else if (Z_TYPE_P(val) == IS_OBJECT) { - if (!instanceof_function(Z_OBJCE_P(val), map_field_type TSRMLS_CC)) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Given value is not an instance of %s.", -#if PHP_MAJOR_VERSION < 7 - map_field_type->name); -#else - ZSTR_VAL(map_field_type->name)); -#endif - return; - } - Map* intern = UNBOX(Map, val); - if (to_fieldtype(key_type) != intern->key_type) { - zend_throw_exception( - NULL, "Incorrect map field key type.", - 0 TSRMLS_CC); - return; - } - if (to_fieldtype(value_type) != intern->value_type) { - zend_throw_exception( - NULL, "Incorrect map field value type.", - 0 TSRMLS_CC); - return; - } - if (klass != NULL && intern->msg_ce != klass) { - zend_throw_exception_ex(NULL, 0 TSRMLS_CC, - "Expect a map field of %s, but %s is given.", -#if PHP_MAJOR_VERSION < 7 - klass->name, intern->msg_ce->name); -#else - ZSTR_VAL(klass->name), - ZSTR_VAL(intern->msg_ce->name)); -#endif - return; - } - RETURN_ZVAL(val, 1, 0); - } else { - zend_throw_exception( - NULL, "Incorrect map field type.", - 0 TSRMLS_CC); - return; - } -} - -PHP_METHOD(Util, checkMapField) { - zval* val; - PHP_PROTO_LONG key_type, value_type; - const zend_class_entry* klass = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zll|C", &val, &key_type, - &value_type, &klass) == FAILURE) { - return; - } - RETURN_ZVAL(val, 1, 0); -} diff --git a/php/ext/google/protobuf/upb.c b/php/ext/google/protobuf/upb.c deleted file mode 100644 index cf27432f03da..000000000000 --- a/php/ext/google/protobuf/upb.c +++ /dev/null @@ -1,13840 +0,0 @@ -/* Amalgamated source file */ -#include "upb.h" -/* -* This is where we define macros used across upb. -* -* All of these macros are undef'd in port_undef.inc to avoid leaking them to -* users. -* -* The correct usage is: -* -* #include "upb/foobar.h" -* #include "upb/baz.h" -* -* // MUST be last included header. -* #include "upb/port_def.inc" -* -* // Code for this file. -* // <...> -* -* // Can be omitted for .c files, required for .h. -* #include "upb/port_undef.inc" -* -* This file is private and must not be included by users! -*/ -#include -#include - -#if UINTPTR_MAX == 0xffffffff -#define UPB_SIZE(size32, size64) size32 -#else -#define UPB_SIZE(size32, size64) size64 -#endif - -/* If we always read/write as a consistent type to each address, this shouldn't - * violate aliasing. - */ -#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) - -#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \ - *UPB_PTR_AT(msg, case_offset, int) == case_val \ - ? *UPB_PTR_AT(msg, offset, fieldtype) \ - : default - -#define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \ - *UPB_PTR_AT(msg, case_offset, int) = case_val; \ - *UPB_PTR_AT(msg, offset, fieldtype) = value; - -#define UPB_MAPTYPE_STRING 0 - -/* UPB_INLINE: inline if possible, emit standalone code if required. */ -#ifdef __cplusplus -#define UPB_INLINE inline -#elif defined (__GNUC__) || defined(__clang__) -#define UPB_INLINE static __inline__ -#else -#define UPB_INLINE static -#endif - -#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) -#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) -#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) - -/* Hints to the compiler about likely/unlikely branches. */ -#if defined (__GNUC__) || defined(__clang__) -#define UPB_LIKELY(x) __builtin_expect((x),1) -#define UPB_UNLIKELY(x) __builtin_expect((x),0) -#else -#define UPB_LIKELY(x) (x) -#define UPB_UNLIKELY(x) (x) -#endif - -/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler - * doesn't provide these preprocessor symbols. */ -#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define UPB_BIG_ENDIAN -#endif - -/* Macros for function attributes on compilers that support them. */ -#ifdef __GNUC__ -#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) -#define UPB_NOINLINE __attribute__((noinline)) -#define UPB_NORETURN __attribute__((__noreturn__)) -#else /* !defined(__GNUC__) */ -#define UPB_FORCEINLINE -#define UPB_NOINLINE -#define UPB_NORETURN -#endif - -#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L -/* C99/C++11 versions. */ -#include -#define _upb_snprintf snprintf -#define _upb_vsnprintf vsnprintf -#define _upb_va_copy(a, b) va_copy(a, b) -#elif defined(_MSC_VER) -/* Microsoft C/C++ versions. */ -#include -#include -#if _MSC_VER < 1900 -int msvc_snprintf(char* s, size_t n, const char* format, ...); -int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg); -#define UPB_MSVC_VSNPRINTF -#define _upb_snprintf msvc_snprintf -#define _upb_vsnprintf msvc_vsnprintf -#else -#define _upb_snprintf snprintf -#define _upb_vsnprintf vsnprintf -#endif -#define _upb_va_copy(a, b) va_copy(a, b) -#elif defined __GNUC__ -/* A few hacky workarounds for functions not in C89. - * For internal use only! - * TODO(haberman): fix these by including our own implementations, or finding - * another workaround. - */ -#define _upb_snprintf __builtin_snprintf -#define _upb_vsnprintf __builtin_vsnprintf -#define _upb_va_copy(a, b) __va_copy(a, b) -#else -#error Need implementations of [v]snprintf and va_copy -#endif - -#ifdef __cplusplus -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || \ - (defined(_MSC_VER) && _MSC_VER >= 1900) -/* C++11 is present */ -#else -#error upb requires C++11 for C++ support -#endif -#endif - -#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) -#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) - -#define UPB_UNUSED(var) (void)var - -/* UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. - */ -#ifdef NDEBUG -#ifdef __GNUC__ -#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() -#else -#define UPB_ASSUME(expr) do {} if (false && (expr)) -#endif -#else -#define UPB_ASSUME(expr) assert(expr) -#endif - -/* UPB_ASSERT(): in release mode, we use the expression without letting it be - * evaluated. This prevents "unused variable" warnings. */ -#ifdef NDEBUG -#define UPB_ASSERT(expr) do {} while (false && (expr)) -#else -#define UPB_ASSERT(expr) assert(expr) -#endif - -/* UPB_ASSERT_DEBUGVAR(): assert that uses functions or variables that only - * exist in debug mode. This turns into regular assert. */ -#define UPB_ASSERT_DEBUGVAR(expr) assert(expr) - -#if defined(__GNUC__) || defined(__clang__) -#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) -#else -#define UPB_UNREACHABLE() do { assert(0); } while(0) -#endif - -/* UPB_INFINITY representing floating-point positive infinity. */ -#include -#ifdef INFINITY -#define UPB_INFINITY INFINITY -#else -#define UPB_INFINITY (1.0 / 0.0) -#endif - -#include -#include - - - -/* Maps descriptor type -> upb field type. */ -static const uint8_t desctype_to_fieldtype[] = { - -1, /* invalid descriptor type */ - UPB_TYPE_DOUBLE, /* DOUBLE */ - UPB_TYPE_FLOAT, /* FLOAT */ - UPB_TYPE_INT64, /* INT64 */ - UPB_TYPE_UINT64, /* UINT64 */ - UPB_TYPE_INT32, /* INT32 */ - UPB_TYPE_UINT64, /* FIXED64 */ - UPB_TYPE_UINT32, /* FIXED32 */ - UPB_TYPE_BOOL, /* BOOL */ - UPB_TYPE_STRING, /* STRING */ - UPB_TYPE_MESSAGE, /* GROUP */ - UPB_TYPE_MESSAGE, /* MESSAGE */ - UPB_TYPE_BYTES, /* BYTES */ - UPB_TYPE_UINT32, /* UINT32 */ - UPB_TYPE_ENUM, /* ENUM */ - UPB_TYPE_INT32, /* SFIXED32 */ - UPB_TYPE_INT64, /* SFIXED64 */ - UPB_TYPE_INT32, /* SINT32 */ - UPB_TYPE_INT64, /* SINT64 */ -}; - -/* Maps descriptor type -> upb map size. */ -static const uint8_t desctype_to_mapsize[] = { - -1, /* invalid descriptor type */ - 8, /* DOUBLE */ - 4, /* FLOAT */ - 8, /* INT64 */ - 8, /* UINT64 */ - 4, /* INT32 */ - 8, /* FIXED64 */ - 4, /* FIXED32 */ - 1, /* BOOL */ - UPB_MAPTYPE_STRING, /* STRING */ - sizeof(void *), /* GROUP */ - sizeof(void *), /* MESSAGE */ - UPB_MAPTYPE_STRING, /* BYTES */ - 4, /* UINT32 */ - 4, /* ENUM */ - 4, /* SFIXED32 */ - 8, /* SFIXED64 */ - 4, /* SINT32 */ - 8, /* SINT64 */ -}; - -static const unsigned fixed32_ok = (1 << UPB_DTYPE_FLOAT) | - (1 << UPB_DTYPE_FIXED32) | - (1 << UPB_DTYPE_SFIXED32); - -static const unsigned fixed64_ok = (1 << UPB_DTYPE_DOUBLE) | - (1 << UPB_DTYPE_FIXED64) | - (1 << UPB_DTYPE_SFIXED64); - -/* Op: an action to be performed for a wire-type/field-type combination. */ -#define OP_SCALAR_LG2(n) (n) -#define OP_FIXPCK_LG2(n) (n + 4) -#define OP_VARPCK_LG2(n) (n + 8) -#define OP_STRING 4 -#define OP_SUBMSG 5 - -static const int8_t varint_ops[19] = { - -1, /* field not found */ - -1, /* DOUBLE */ - -1, /* FLOAT */ - OP_SCALAR_LG2(3), /* INT64 */ - OP_SCALAR_LG2(3), /* UINT64 */ - OP_SCALAR_LG2(2), /* INT32 */ - -1, /* FIXED64 */ - -1, /* FIXED32 */ - OP_SCALAR_LG2(0), /* BOOL */ - -1, /* STRING */ - -1, /* GROUP */ - -1, /* MESSAGE */ - -1, /* BYTES */ - OP_SCALAR_LG2(2), /* UINT32 */ - OP_SCALAR_LG2(2), /* ENUM */ - -1, /* SFIXED32 */ - -1, /* SFIXED64 */ - OP_SCALAR_LG2(2), /* SINT32 */ - OP_SCALAR_LG2(3), /* SINT64 */ -}; - -static const int8_t delim_ops[37] = { - /* For non-repeated field type. */ - -1, /* field not found */ - -1, /* DOUBLE */ - -1, /* FLOAT */ - -1, /* INT64 */ - -1, /* UINT64 */ - -1, /* INT32 */ - -1, /* FIXED64 */ - -1, /* FIXED32 */ - -1, /* BOOL */ - OP_STRING, /* STRING */ - -1, /* GROUP */ - OP_SUBMSG, /* MESSAGE */ - OP_STRING, /* BYTES */ - -1, /* UINT32 */ - -1, /* ENUM */ - -1, /* SFIXED32 */ - -1, /* SFIXED64 */ - -1, /* SINT32 */ - -1, /* SINT64 */ - /* For repeated field type. */ - OP_FIXPCK_LG2(3), /* REPEATED DOUBLE */ - OP_FIXPCK_LG2(2), /* REPEATED FLOAT */ - OP_VARPCK_LG2(3), /* REPEATED INT64 */ - OP_VARPCK_LG2(3), /* REPEATED UINT64 */ - OP_VARPCK_LG2(2), /* REPEATED INT32 */ - OP_FIXPCK_LG2(3), /* REPEATED FIXED64 */ - OP_FIXPCK_LG2(2), /* REPEATED FIXED32 */ - OP_VARPCK_LG2(0), /* REPEATED BOOL */ - OP_STRING, /* REPEATED STRING */ - OP_SUBMSG, /* REPEATED GROUP */ - OP_SUBMSG, /* REPEATED MESSAGE */ - OP_STRING, /* REPEATED BYTES */ - OP_VARPCK_LG2(2), /* REPEATED UINT32 */ - OP_VARPCK_LG2(2), /* REPEATED ENUM */ - OP_FIXPCK_LG2(2), /* REPEATED SFIXED32 */ - OP_FIXPCK_LG2(3), /* REPEATED SFIXED64 */ - OP_VARPCK_LG2(2), /* REPEATED SINT32 */ - OP_VARPCK_LG2(3), /* REPEATED SINT64 */ -}; - -/* Data pertaining to the parse. */ -typedef struct { - const char *limit; /* End of delimited region or end of buffer. */ - upb_arena *arena; - int depth; - uint32_t end_group; /* Set to field number of END_GROUP tag, if any. */ - jmp_buf err; -} upb_decstate; - -typedef union { - bool bool_val; - int32_t int32_val; - int64_t int64_val; - uint32_t uint32_val; - uint64_t uint64_val; - upb_strview str_val; -} wireval; - -static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, - const upb_msglayout *layout); - -UPB_NORETURN static void decode_err(upb_decstate *d) { longjmp(d->err, 1); } - -static bool decode_reserve(upb_decstate *d, upb_array *arr, int elem) { - bool need_realloc = arr->size - arr->len < elem; - if (need_realloc && !_upb_array_realloc(arr, arr->len + elem, d->arena)) { - decode_err(d); - } - return need_realloc; -} - -UPB_NOINLINE -static const char *decode_longvarint64(upb_decstate *d, const char *ptr, - const char *limit, uint64_t *val) { - uint8_t byte; - int bitpos = 0; - uint64_t out = 0; - - do { - if (bitpos >= 70 || ptr == limit) decode_err(d); - byte = *ptr; - out |= (uint64_t)(byte & 0x7F) << bitpos; - ptr++; - bitpos += 7; - } while (byte & 0x80); - - *val = out; - return ptr; -} - -UPB_FORCEINLINE -static const char *decode_varint64(upb_decstate *d, const char *ptr, - const char *limit, uint64_t *val) { - if (UPB_LIKELY(ptr < limit && (*ptr & 0x80) == 0)) { - *val = (uint8_t)*ptr; - return ptr + 1; - } else { - return decode_longvarint64(d, ptr, limit, val); - } -} - -static const char *decode_varint32(upb_decstate *d, const char *ptr, - const char *limit, uint32_t *val) { - uint64_t u64; - ptr = decode_varint64(d, ptr, limit, &u64); - if (u64 > UINT32_MAX) decode_err(d); - *val = (uint32_t)u64; - return ptr; -} - -static void decode_munge(int type, wireval *val) { - switch (type) { - case UPB_DESCRIPTOR_TYPE_BOOL: - val->bool_val = val->uint64_val != 0; - break; - case UPB_DESCRIPTOR_TYPE_SINT32: { - uint32_t n = val->uint32_val; - val->int32_val = (n >> 1) ^ -(int32_t)(n & 1); - break; - } - case UPB_DESCRIPTOR_TYPE_SINT64: { - uint64_t n = val->uint64_val; - val->int64_val = (n >> 1) ^ -(int64_t)(n & 1); - break; - } - } -} - -static const upb_msglayout_field *upb_find_field(const upb_msglayout *l, - uint32_t field_number) { - static upb_msglayout_field none = {0}; - - /* Lots of optimization opportunities here. */ - int i; - if (l == NULL) return &none; - for (i = 0; i < l->field_count; i++) { - if (l->fields[i].number == field_number) { - return &l->fields[i]; - } - } - - return &none; /* Unknown field. */ -} - -static upb_msg *decode_newsubmsg(upb_decstate *d, const upb_msglayout *layout, - const upb_msglayout_field *field) { - const upb_msglayout *subl = layout->submsgs[field->submsg_index]; - return _upb_msg_new(subl, d->arena); -} - -static void decode_tosubmsg(upb_decstate *d, upb_msg *submsg, - const upb_msglayout *layout, - const upb_msglayout_field *field, upb_strview val) { - const upb_msglayout *subl = layout->submsgs[field->submsg_index]; - const char *saved_limit = d->limit; - if (--d->depth < 0) decode_err(d); - d->limit = val.data + val.size; - decode_msg(d, val.data, submsg, subl); - d->limit = saved_limit; - if (d->end_group != 0) decode_err(d); - d->depth++; -} - -static const char *decode_group(upb_decstate *d, const char *ptr, - upb_msg *submsg, const upb_msglayout *subl, - uint32_t number) { - if (--d->depth < 0) decode_err(d); - ptr = decode_msg(d, ptr, submsg, subl); - if (d->end_group != number) decode_err(d); - d->end_group = 0; - d->depth++; - return ptr; -} - -static const char *decode_togroup(upb_decstate *d, const char *ptr, - upb_msg *submsg, const upb_msglayout *layout, - const upb_msglayout_field *field) { - const upb_msglayout *subl = layout->submsgs[field->submsg_index]; - return decode_group(d, ptr, submsg, subl, field->number); -} - -static const char *decode_toarray(upb_decstate *d, const char *ptr, - upb_msg *msg, const upb_msglayout *layout, - const upb_msglayout_field *field, wireval val, - int op) { - upb_array **arrp = UPB_PTR_AT(msg, field->offset, void); - upb_array *arr = *arrp; - void *mem; - - if (!arr) { - upb_fieldtype_t type = desctype_to_fieldtype[field->descriptortype]; - arr = _upb_array_new(d->arena, type); - if (!arr) decode_err(d); - *arrp = arr; - } - - decode_reserve(d, arr, 1); - - switch (op) { - case OP_SCALAR_LG2(0): - case OP_SCALAR_LG2(2): - case OP_SCALAR_LG2(3): - /* Append scalar value. */ - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << op, void); - arr->len++; - memcpy(mem, &val, 1 << op); - return ptr; - case OP_STRING: - /* Append string. */ - mem = - UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(upb_strview), void); - arr->len++; - memcpy(mem, &val, sizeof(upb_strview)); - return ptr; - case OP_SUBMSG: { - /* Append submessage / group. */ - upb_msg *submsg = decode_newsubmsg(d, layout, field); - *UPB_PTR_AT(_upb_array_ptr(arr), arr->len * sizeof(void *), upb_msg *) = - submsg; - arr->len++; - if (UPB_UNLIKELY(field->descriptortype == UPB_DTYPE_GROUP)) { - ptr = decode_togroup(d, ptr, submsg, layout, field); - } else { - decode_tosubmsg(d, submsg, layout, field, val.str_val); - } - return ptr; - } - case OP_FIXPCK_LG2(2): - case OP_FIXPCK_LG2(3): { - /* Fixed packed. */ - int lg2 = op - OP_FIXPCK_LG2(0); - int mask = (1 << lg2) - 1; - int count = val.str_val.size >> lg2; - if ((val.str_val.size & mask) != 0) { - decode_err(d); /* Length isn't a round multiple of elem size. */ - } - decode_reserve(d, arr, count); - mem = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - arr->len += count; - memcpy(mem, val.str_val.data, val.str_val.size); - return ptr; - } - case OP_VARPCK_LG2(0): - case OP_VARPCK_LG2(2): - case OP_VARPCK_LG2(3): { - /* Varint packed. */ - int lg2 = op - OP_VARPCK_LG2(0); - int scale = 1 << lg2; - const char *ptr = val.str_val.data; - const char *end = ptr + val.str_val.size; - char *out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - while (ptr < end) { - wireval elem; - ptr = decode_varint64(d, ptr, end, &elem.uint64_val); - decode_munge(field->descriptortype, &elem); - if (decode_reserve(d, arr, 1)) { - out = UPB_PTR_AT(_upb_array_ptr(arr), arr->len << lg2, void); - } - arr->len++; - memcpy(out, &elem, scale); - out += scale; - } - if (ptr != end) decode_err(d); - return ptr; - } - default: - UPB_UNREACHABLE(); - } -} - -static void decode_tomap(upb_decstate *d, upb_msg *msg, - const upb_msglayout *layout, - const upb_msglayout_field *field, wireval val) { - upb_map **map_p = UPB_PTR_AT(msg, field->offset, upb_map *); - upb_map *map = *map_p; - upb_map_entry ent; - const upb_msglayout *entry = layout->submsgs[field->submsg_index]; - - if (!map) { - /* Lazily create map. */ - const upb_msglayout *entry = layout->submsgs[field->submsg_index]; - const upb_msglayout_field *key_field = &entry->fields[0]; - const upb_msglayout_field *val_field = &entry->fields[1]; - char key_size = desctype_to_mapsize[key_field->descriptortype]; - char val_size = desctype_to_mapsize[val_field->descriptortype]; - UPB_ASSERT(key_field->offset == 0); - UPB_ASSERT(val_field->offset == sizeof(upb_strview)); - map = _upb_map_new(d->arena, key_size, val_size); - *map_p = map; - } - - /* Parse map entry. */ - memset(&ent, 0, sizeof(ent)); - - if (entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || - entry->fields[1].descriptortype == UPB_DESCRIPTOR_TYPE_GROUP) { - /* Create proactively to handle the case where it doesn't appear. */ - ent.v.val.val = (uint64_t)_upb_msg_new(entry->submsgs[0], d->arena); - } - - decode_tosubmsg(d, &ent.k, layout, field, val.str_val); - - /* Insert into map. */ - _upb_map_set(map, &ent.k, map->key_size, &ent.v, map->val_size, d->arena); -} - -static const char *decode_tomsg(upb_decstate *d, const char *ptr, upb_msg *msg, - const upb_msglayout *layout, - const upb_msglayout_field *field, wireval val, - int op) { - void *mem = UPB_PTR_AT(msg, field->offset, void); - int type = field->descriptortype; - - /* Set presence if necessary. */ - if (field->presence < 0) { - /* Oneof case */ - *UPB_PTR_AT(msg, -field->presence, int32_t) = field->number; - } else if (field->presence > 0) { - /* Hasbit */ - uint32_t hasbit = field->presence; - *UPB_PTR_AT(msg, hasbit / 8, uint8_t) |= (1 << (hasbit % 8)); - } - - /* Store into message. */ - switch (op) { - case OP_SUBMSG: { - upb_msg **submsgp = mem; - upb_msg *submsg = *submsgp; - if (!submsg) { - submsg = decode_newsubmsg(d, layout, field); - *submsgp = submsg; - } - if (UPB_UNLIKELY(type == UPB_DTYPE_GROUP)) { - ptr = decode_togroup(d, ptr, submsg, layout, field); - } else { - decode_tosubmsg(d, submsg, layout, field, val.str_val); - } - break; - } - case OP_STRING: - memcpy(mem, &val, sizeof(upb_strview)); - break; - case OP_SCALAR_LG2(3): - memcpy(mem, &val, 8); - break; - case OP_SCALAR_LG2(2): - memcpy(mem, &val, 4); - break; - case OP_SCALAR_LG2(0): - memcpy(mem, &val, 1); - break; - default: - UPB_UNREACHABLE(); - } - - return ptr; -} - -static const char *decode_msg(upb_decstate *d, const char *ptr, upb_msg *msg, - const upb_msglayout *layout) { - while (ptr < d->limit) { - uint32_t tag; - const upb_msglayout_field *field; - int field_number; - int wire_type; - const char *field_start = ptr; - wireval val; - int op; - - ptr = decode_varint32(d, ptr, d->limit, &tag); - field_number = tag >> 3; - wire_type = tag & 7; - - field = upb_find_field(layout, field_number); - - switch (wire_type) { - case UPB_WIRE_TYPE_VARINT: - ptr = decode_varint64(d, ptr, d->limit, &val.uint64_val); - op = varint_ops[field->descriptortype]; - decode_munge(field->descriptortype, &val); - break; - case UPB_WIRE_TYPE_32BIT: - if (d->limit - ptr < 4) decode_err(d); - memcpy(&val, ptr, 4); - ptr += 4; - op = OP_SCALAR_LG2(2); - if (((1 << field->descriptortype) & fixed32_ok) == 0) goto unknown; - break; - case UPB_WIRE_TYPE_64BIT: - if (d->limit - ptr < 8) decode_err(d); - memcpy(&val, ptr, 8); - ptr += 8; - op = OP_SCALAR_LG2(3); - if (((1 << field->descriptortype) & fixed64_ok) == 0) goto unknown; - break; - case UPB_WIRE_TYPE_DELIMITED: { - uint32_t size; - int ndx = field->descriptortype; - if (_upb_isrepeated(field)) ndx += 18; - ptr = decode_varint32(d, ptr, d->limit, &size); - if (size >= INT32_MAX || (size_t)(d->limit - ptr) < size) { - decode_err(d); /* Length overflow. */ - } - val.str_val.data = ptr; - val.str_val.size = size; - ptr += size; - op = delim_ops[ndx]; - break; - } - case UPB_WIRE_TYPE_START_GROUP: - val.int32_val = field_number; - op = OP_SUBMSG; - if (field->descriptortype != UPB_DTYPE_GROUP) goto unknown; - break; - case UPB_WIRE_TYPE_END_GROUP: - d->end_group = field_number; - return ptr; - default: - decode_err(d); - } - - if (op >= 0) { - /* Parse, using op for dispatch. */ - switch (field->label) { - case UPB_LABEL_REPEATED: - case _UPB_LABEL_PACKED: - ptr = decode_toarray(d, ptr, msg, layout, field, val, op); - break; - case _UPB_LABEL_MAP: - decode_tomap(d, msg, layout, field, val); - break; - default: - ptr = decode_tomsg(d, ptr, msg, layout, field, val, op); - break; - } - } else { - unknown: - /* Skip unknown field. */ - if (field_number == 0) decode_err(d); - if (wire_type == UPB_WIRE_TYPE_START_GROUP) { - ptr = decode_group(d, ptr, NULL, NULL, field_number); - } - if (msg) { - if (!_upb_msg_addunknown(msg, field_start, ptr - field_start, - d->arena)) { - decode_err(d); - } - } - } - } - - if (ptr != d->limit) decode_err(d); - return ptr; -} - -bool upb_decode(const char *buf, size_t size, void *msg, const upb_msglayout *l, - upb_arena *arena) { - upb_decstate state; - state.limit = buf + size; - state.arena = arena; - state.depth = 64; - state.end_group = 0; - - if (setjmp(state.err)) return false; - - if (size == 0) return true; - decode_msg(&state, buf, msg, l); - - return state.end_group == 0; -} - -#undef OP_SCALAR_LG2 -#undef OP_FIXPCK_LG2 -#undef OP_VARPCK_LG2 -#undef OP_STRING -#undef OP_SUBMSG -/* We encode backwards, to avoid pre-computing lengths (one-pass encode). */ - - -#include - - - -#define UPB_PB_VARINT_MAX_LEN 10 -#define CHK(x) do { if (!(x)) { return false; } } while(0) - -static size_t upb_encode_varint(uint64_t val, char *buf) { - size_t i; - if (val < 128) { buf[0] = val; return 1; } - i = 0; - while (val) { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - buf[i++] = byte; - } - return i; -} - -static uint32_t upb_zzencode_32(int32_t n) { return ((uint32_t)n << 1) ^ (n >> 31); } -static uint64_t upb_zzencode_64(int64_t n) { return ((uint64_t)n << 1) ^ (n >> 63); } - -typedef struct { - upb_alloc *alloc; - char *buf, *ptr, *limit; -} upb_encstate; - -static size_t upb_roundup_pow2(size_t bytes) { - size_t ret = 128; - while (ret < bytes) { - ret *= 2; - } - return ret; -} - -static bool upb_encode_growbuffer(upb_encstate *e, size_t bytes) { - size_t old_size = e->limit - e->buf; - size_t new_size = upb_roundup_pow2(bytes + (e->limit - e->ptr)); - char *new_buf = upb_realloc(e->alloc, e->buf, old_size, new_size); - CHK(new_buf); - - /* We want previous data at the end, realloc() put it at the beginning. */ - if (old_size > 0) { - memmove(new_buf + new_size - old_size, e->buf, old_size); - } - - e->ptr = new_buf + new_size - (e->limit - e->ptr); - e->limit = new_buf + new_size; - e->buf = new_buf; - return true; -} - -/* Call to ensure that at least "bytes" bytes are available for writing at - * e->ptr. Returns false if the bytes could not be allocated. */ -static bool upb_encode_reserve(upb_encstate *e, size_t bytes) { - CHK(UPB_LIKELY((size_t)(e->ptr - e->buf) >= bytes) || - upb_encode_growbuffer(e, bytes)); - - e->ptr -= bytes; - return true; -} - -/* Writes the given bytes to the buffer, handling reserve/advance. */ -static bool upb_put_bytes(upb_encstate *e, const void *data, size_t len) { - if (len == 0) return true; - CHK(upb_encode_reserve(e, len)); - memcpy(e->ptr, data, len); - return true; -} - -static bool upb_put_fixed64(upb_encstate *e, uint64_t val) { - /* TODO(haberman): byte-swap for big endian. */ - return upb_put_bytes(e, &val, sizeof(uint64_t)); -} - -static bool upb_put_fixed32(upb_encstate *e, uint32_t val) { - /* TODO(haberman): byte-swap for big endian. */ - return upb_put_bytes(e, &val, sizeof(uint32_t)); -} - -static bool upb_put_varint(upb_encstate *e, uint64_t val) { - size_t len; - char *start; - CHK(upb_encode_reserve(e, UPB_PB_VARINT_MAX_LEN)); - len = upb_encode_varint(val, e->ptr); - start = e->ptr + UPB_PB_VARINT_MAX_LEN - len; - memmove(start, e->ptr, len); - e->ptr = start; - return true; -} - -static bool upb_put_double(upb_encstate *e, double d) { - uint64_t u64; - UPB_ASSERT(sizeof(double) == sizeof(uint64_t)); - memcpy(&u64, &d, sizeof(uint64_t)); - return upb_put_fixed64(e, u64); -} - -static bool upb_put_float(upb_encstate *e, float d) { - uint32_t u32; - UPB_ASSERT(sizeof(float) == sizeof(uint32_t)); - memcpy(&u32, &d, sizeof(uint32_t)); - return upb_put_fixed32(e, u32); -} - -static uint32_t upb_readcase(const char *msg, const upb_msglayout_field *f) { - uint32_t ret; - memcpy(&ret, msg - f->presence, sizeof(ret)); - return ret; -} - -static bool upb_readhasbit(const char *msg, const upb_msglayout_field *f) { - uint32_t hasbit = f->presence; - UPB_ASSERT(f->presence > 0); - return (*UPB_PTR_AT(msg, hasbit / 8, uint8_t)) & (1 << (hasbit % 8)); -} - -static bool upb_put_tag(upb_encstate *e, int field_number, int wire_type) { - return upb_put_varint(e, (field_number << 3) | wire_type); -} - -static bool upb_put_fixedarray(upb_encstate *e, const upb_array *arr, - size_t elem_size, uint32_t tag) { - size_t bytes = arr->len * elem_size; - const char* data = _upb_array_constptr(arr); - const char* ptr = data + bytes - elem_size; - if (tag) { - while (true) { - CHK(upb_put_bytes(e, ptr, elem_size) && upb_put_varint(e, tag)); - if (ptr == data) break; - ptr -= elem_size; - } - return true; - } else { - return upb_put_bytes(e, data, bytes) && upb_put_varint(e, bytes); - } -} - -bool upb_encode_message(upb_encstate *e, const char *msg, - const upb_msglayout *m, size_t *size); - -static bool upb_encode_scalarfield(upb_encstate *e, const void *_field_mem, - const upb_msglayout *m, - const upb_msglayout_field *f, - bool skip_zero_value) { - const char *field_mem = _field_mem; -#define CASE(ctype, type, wire_type, encodeval) do { \ - ctype val = *(ctype*)field_mem; \ - if (skip_zero_value && val == 0) { \ - return true; \ - } \ - return upb_put_ ## type(e, encodeval) && \ - upb_put_tag(e, f->number, wire_type); \ -} while(0) - - switch (f->descriptortype) { - case UPB_DESCRIPTOR_TYPE_DOUBLE: - CASE(double, double, UPB_WIRE_TYPE_64BIT, val); - case UPB_DESCRIPTOR_TYPE_FLOAT: - CASE(float, float, UPB_WIRE_TYPE_32BIT, val); - case UPB_DESCRIPTOR_TYPE_INT64: - case UPB_DESCRIPTOR_TYPE_UINT64: - CASE(uint64_t, varint, UPB_WIRE_TYPE_VARINT, val); - case UPB_DESCRIPTOR_TYPE_UINT32: - CASE(uint32_t, varint, UPB_WIRE_TYPE_VARINT, val); - case UPB_DESCRIPTOR_TYPE_INT32: - case UPB_DESCRIPTOR_TYPE_ENUM: - CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, (int64_t)val); - case UPB_DESCRIPTOR_TYPE_SFIXED64: - case UPB_DESCRIPTOR_TYPE_FIXED64: - CASE(uint64_t, fixed64, UPB_WIRE_TYPE_64BIT, val); - case UPB_DESCRIPTOR_TYPE_FIXED32: - case UPB_DESCRIPTOR_TYPE_SFIXED32: - CASE(uint32_t, fixed32, UPB_WIRE_TYPE_32BIT, val); - case UPB_DESCRIPTOR_TYPE_BOOL: - CASE(bool, varint, UPB_WIRE_TYPE_VARINT, val); - case UPB_DESCRIPTOR_TYPE_SINT32: - CASE(int32_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_32(val)); - case UPB_DESCRIPTOR_TYPE_SINT64: - CASE(int64_t, varint, UPB_WIRE_TYPE_VARINT, upb_zzencode_64(val)); - case UPB_DESCRIPTOR_TYPE_STRING: - case UPB_DESCRIPTOR_TYPE_BYTES: { - upb_strview view = *(upb_strview*)field_mem; - if (skip_zero_value && view.size == 0) { - return true; - } - return upb_put_bytes(e, view.data, view.size) && - upb_put_varint(e, view.size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); - } - case UPB_DESCRIPTOR_TYPE_GROUP: { - size_t size; - void *submsg = *(void **)field_mem; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; - if (submsg == NULL) { - return true; - } - return upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && - upb_encode_message(e, submsg, subm, &size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP); - } - case UPB_DESCRIPTOR_TYPE_MESSAGE: { - size_t size; - void *submsg = *(void **)field_mem; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; - if (submsg == NULL) { - return true; - } - return upb_encode_message(e, submsg, subm, &size) && - upb_put_varint(e, size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED); - } - } -#undef CASE - UPB_UNREACHABLE(); -} - -static bool upb_encode_array(upb_encstate *e, const char *field_mem, - const upb_msglayout *m, - const upb_msglayout_field *f) { - const upb_array *arr = *(const upb_array**)field_mem; - bool packed = f->label == _UPB_LABEL_PACKED; - - if (arr == NULL || arr->len == 0) { - return true; - } - -#define VARINT_CASE(ctype, encode) \ - { \ - const ctype *start = _upb_array_constptr(arr); \ - const ctype *ptr = start + arr->len; \ - size_t pre_len = e->limit - e->ptr; \ - uint32_t tag = packed ? 0 : (f->number << 3) | UPB_WIRE_TYPE_VARINT; \ - do { \ - ptr--; \ - CHK(upb_put_varint(e, encode)); \ - if (tag) CHK(upb_put_varint(e, tag)); \ - } while (ptr != start); \ - if (!tag) CHK(upb_put_varint(e, e->limit - e->ptr - pre_len)); \ - } \ - break; \ - do { \ - ; \ - } while (0) - -#define TAG(wire_type) (packed ? 0 : (f->number << 3 | wire_type)) - - switch (f->descriptortype) { - case UPB_DESCRIPTOR_TYPE_DOUBLE: - CHK(upb_put_fixedarray(e, arr, sizeof(double), TAG(UPB_WIRE_TYPE_64BIT))); - break; - case UPB_DESCRIPTOR_TYPE_FLOAT: - CHK(upb_put_fixedarray(e, arr, sizeof(float), TAG(UPB_WIRE_TYPE_32BIT))); - break; - case UPB_DESCRIPTOR_TYPE_SFIXED64: - case UPB_DESCRIPTOR_TYPE_FIXED64: - CHK(upb_put_fixedarray(e, arr, sizeof(uint64_t), TAG(UPB_WIRE_TYPE_64BIT))); - break; - case UPB_DESCRIPTOR_TYPE_FIXED32: - case UPB_DESCRIPTOR_TYPE_SFIXED32: - CHK(upb_put_fixedarray(e, arr, sizeof(uint32_t), TAG(UPB_WIRE_TYPE_32BIT))); - break; - case UPB_DESCRIPTOR_TYPE_INT64: - case UPB_DESCRIPTOR_TYPE_UINT64: - VARINT_CASE(uint64_t, *ptr); - case UPB_DESCRIPTOR_TYPE_UINT32: - VARINT_CASE(uint32_t, *ptr); - case UPB_DESCRIPTOR_TYPE_INT32: - case UPB_DESCRIPTOR_TYPE_ENUM: - VARINT_CASE(int32_t, (int64_t)*ptr); - case UPB_DESCRIPTOR_TYPE_BOOL: - VARINT_CASE(bool, *ptr); - case UPB_DESCRIPTOR_TYPE_SINT32: - VARINT_CASE(int32_t, upb_zzencode_32(*ptr)); - case UPB_DESCRIPTOR_TYPE_SINT64: - VARINT_CASE(int64_t, upb_zzencode_64(*ptr)); - case UPB_DESCRIPTOR_TYPE_STRING: - case UPB_DESCRIPTOR_TYPE_BYTES: { - const upb_strview *start = _upb_array_constptr(arr); - const upb_strview *ptr = start + arr->len; - do { - ptr--; - CHK(upb_put_bytes(e, ptr->data, ptr->size) && - upb_put_varint(e, ptr->size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); - } while (ptr != start); - return true; - } - case UPB_DESCRIPTOR_TYPE_GROUP: { - const void *const*start = _upb_array_constptr(arr); - const void *const*ptr = start + arr->len; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; - do { - size_t size; - ptr--; - CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_END_GROUP) && - upb_encode_message(e, *ptr, subm, &size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_START_GROUP)); - } while (ptr != start); - return true; - } - case UPB_DESCRIPTOR_TYPE_MESSAGE: { - const void *const*start = _upb_array_constptr(arr); - const void *const*ptr = start + arr->len; - const upb_msglayout *subm = m->submsgs[f->submsg_index]; - do { - size_t size; - ptr--; - CHK(upb_encode_message(e, *ptr, subm, &size) && - upb_put_varint(e, size) && - upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); - } while (ptr != start); - return true; - } - } -#undef VARINT_CASE - - if (packed) { - CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); - } - return true; -} - -static bool upb_encode_map(upb_encstate *e, const char *field_mem, - const upb_msglayout *m, - const upb_msglayout_field *f) { - const upb_map *map = *(const upb_map**)field_mem; - const upb_msglayout *entry = m->submsgs[f->submsg_index]; - const upb_msglayout_field *key_field = &entry->fields[0]; - const upb_msglayout_field *val_field = &entry->fields[1]; - upb_strtable_iter i; - if (map == NULL) { - return true; - } - - upb_strtable_begin(&i, &map->table); - for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { - size_t pre_len = e->limit - e->ptr; - size_t size; - upb_strview key = upb_strtable_iter_key(&i); - const upb_value val = upb_strtable_iter_value(&i); - const void *keyp = - map->key_size == UPB_MAPTYPE_STRING ? (void *)&key : key.data; - const void *valp = - map->val_size == UPB_MAPTYPE_STRING ? upb_value_getptr(val) : &val; - - CHK(upb_encode_scalarfield(e, valp, entry, val_field, false)); - CHK(upb_encode_scalarfield(e, keyp, entry, key_field, false)); - size = (e->limit - e->ptr) - pre_len; - CHK(upb_put_varint(e, size)); - CHK(upb_put_tag(e, f->number, UPB_WIRE_TYPE_DELIMITED)); - } - - return true; -} - - -bool upb_encode_message(upb_encstate *e, const char *msg, - const upb_msglayout *m, size_t *size) { - int i; - size_t pre_len = e->limit - e->ptr; - const char *unknown; - size_t unknown_size; - - unknown = upb_msg_getunknown(msg, &unknown_size); - - if (unknown) { - upb_put_bytes(e, unknown, unknown_size); - } - - for (i = m->field_count - 1; i >= 0; i--) { - const upb_msglayout_field *f = &m->fields[i]; - - if (_upb_isrepeated(f)) { - CHK(upb_encode_array(e, msg + f->offset, m, f)); - } else if (f->label == _UPB_LABEL_MAP) { - CHK(upb_encode_map(e, msg + f->offset, m, f)); - } else { - bool skip_empty = false; - if (f->presence == 0) { - /* Proto3 presence. */ - skip_empty = true; - } else if (f->presence > 0) { - /* Proto2 presence: hasbit. */ - if (!upb_readhasbit(msg, f)) { - continue; - } - } else { - /* Field is in a oneof. */ - if (upb_readcase(msg, f) != f->number) { - continue; - } - } - CHK(upb_encode_scalarfield(e, msg + f->offset, m, f, skip_empty)); - } - } - - *size = (e->limit - e->ptr) - pre_len; - return true; -} - -char *upb_encode(const void *msg, const upb_msglayout *m, upb_arena *arena, - size_t *size) { - upb_encstate e; - e.alloc = upb_arena_alloc(arena); - e.buf = NULL; - e.limit = NULL; - e.ptr = NULL; - - if (!upb_encode_message(&e, msg, m, size)) { - *size = 0; - return NULL; - } - - *size = e.limit - e.ptr; - - if (*size == 0) { - static char ch; - return &ch; - } else { - UPB_ASSERT(e.ptr); - return e.ptr; - } -} - -#undef CHK - - - - -/** upb_msg *******************************************************************/ - -static const char _upb_fieldtype_to_sizelg2[12] = { - 0, - 0, /* UPB_TYPE_BOOL */ - 2, /* UPB_TYPE_FLOAT */ - 2, /* UPB_TYPE_INT32 */ - 2, /* UPB_TYPE_UINT32 */ - 2, /* UPB_TYPE_ENUM */ - UPB_SIZE(2, 3), /* UPB_TYPE_MESSAGE */ - 3, /* UPB_TYPE_DOUBLE */ - 3, /* UPB_TYPE_INT64 */ - 3, /* UPB_TYPE_UINT64 */ - UPB_SIZE(3, 4), /* UPB_TYPE_STRING */ - UPB_SIZE(3, 4), /* UPB_TYPE_BYTES */ -}; - -static uintptr_t tag_arrptr(void* ptr, int elem_size_lg2) { - UPB_ASSERT(elem_size_lg2 <= 4); - return (uintptr_t)ptr | elem_size_lg2; -} - -static int upb_msg_internalsize(const upb_msglayout *l) { - return sizeof(upb_msg_internal) - l->extendable * sizeof(void *); -} - -static size_t upb_msg_sizeof(const upb_msglayout *l) { - return l->size + upb_msg_internalsize(l); -} - -static upb_msg_internal *upb_msg_getinternal(upb_msg *msg) { - return UPB_PTR_AT(msg, -sizeof(upb_msg_internal), upb_msg_internal); -} - -static const upb_msg_internal *upb_msg_getinternal_const(const upb_msg *msg) { - return UPB_PTR_AT(msg, -sizeof(upb_msg_internal), upb_msg_internal); -} - -static upb_msg_internal_withext *upb_msg_getinternalwithext( - upb_msg *msg, const upb_msglayout *l) { - UPB_ASSERT(l->extendable); - return UPB_PTR_AT(msg, -sizeof(upb_msg_internal_withext), - upb_msg_internal_withext); -} - -upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a) { - void *mem = upb_arena_malloc(a, upb_msg_sizeof(l)); - upb_msg_internal *in; - upb_msg *msg; - - if (!mem) { - return NULL; - } - - msg = UPB_PTR_AT(mem, upb_msg_internalsize(l), upb_msg); - - /* Initialize normal members. */ - memset(msg, 0, l->size); - - /* Initialize internal members. */ - in = upb_msg_getinternal(msg); - in->unknown = NULL; - in->unknown_len = 0; - in->unknown_size = 0; - - if (l->extendable) { - upb_msg_getinternalwithext(msg, l)->extdict = NULL; - } - - return msg; -} - -bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, - upb_arena *arena) { - upb_msg_internal *in = upb_msg_getinternal(msg); - if (len > in->unknown_size - in->unknown_len) { - upb_alloc *alloc = upb_arena_alloc(arena); - size_t need = in->unknown_size + len; - size_t newsize = UPB_MAX(in->unknown_size * 2, need); - void *mem = upb_realloc(alloc, in->unknown, in->unknown_size, newsize); - if (!mem) return false; - in->unknown = mem; - in->unknown_size = newsize; - } - memcpy(in->unknown + in->unknown_len, data, len); - in->unknown_len += len; - return true; -} - -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len) { - const upb_msg_internal *in = upb_msg_getinternal_const(msg); - *len = in->unknown_len; - return in->unknown; -} - -/** upb_array *****************************************************************/ - -upb_array *_upb_array_new(upb_arena *a, upb_fieldtype_t type) { - upb_array *arr = upb_arena_malloc(a, sizeof(upb_array)); - - if (!arr) { - return NULL; - } - - arr->data = tag_arrptr(NULL, _upb_fieldtype_to_sizelg2[type]); - arr->len = 0; - arr->size = 0; - - return arr; -} - -bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena) { - size_t new_size = UPB_MAX(arr->size, 4); - int elem_size_lg2 = arr->data & 7; - size_t old_bytes = arr->size << elem_size_lg2; - size_t new_bytes; - void* ptr = _upb_array_ptr(arr); - - /* Log2 ceiling of size. */ - while (new_size < min_size) new_size *= 2; - - new_bytes = new_size << elem_size_lg2; - ptr = upb_arena_realloc(arena, ptr, old_bytes, new_bytes); - - if (!ptr) { - return false; - } - - arr->data = tag_arrptr(ptr, elem_size_lg2); - arr->size = new_size; - return true; -} - -static upb_array *getorcreate_array(upb_array **arr_ptr, upb_fieldtype_t type, - upb_arena *arena) { - upb_array *arr = *arr_ptr; - if (!arr) { - arr = _upb_array_new(arena, type); - if (!arr) return NULL; - *arr_ptr = arr; - } - return arr; -} - -static bool resize_array(upb_array *arr, size_t size, upb_arena *arena) { - if (size > arr->size && !_upb_array_realloc(arr, size, arena)) { - return false; - } - - arr->len = size; - return true; -} - -void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, - upb_fieldtype_t type, upb_arena *arena) { - upb_array *arr = getorcreate_array(arr_ptr, type, arena); - return arr && resize_array(arr, size, arena) ? _upb_array_ptr(arr) : NULL; -} - -bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, - upb_fieldtype_t type, upb_arena *arena) { - upb_array *arr = getorcreate_array(arr_ptr, type, arena); - size_t elem = arr->len; - int lg2 = _upb_fieldtype_to_sizelg2[type]; - char *data; - - if (!arr || !resize_array(arr, elem + 1, arena)) return false; - - data = _upb_array_ptr(arr); - memcpy(data + (elem << lg2), value, 1 << lg2); - return true; -} - -/** upb_map *******************************************************************/ - -upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size) { - upb_map *map = upb_arena_malloc(a, sizeof(upb_map)); - - if (!map) { - return NULL; - } - - upb_strtable_init2(&map->table, UPB_CTYPE_INT32, upb_arena_alloc(a)); - map->key_size = key_size; - map->val_size = value_size; - - return map; -} -/* -** upb_table Implementation -** -** Implementation is heavily inspired by Lua's ltable.c. -*/ - - -#include - - -#define UPB_MAXARRSIZE 16 /* 64k. */ - -/* From Chromium. */ -#define ARRAY_SIZE(x) \ - ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) - -static const double MAX_LOAD = 0.85; - -/* The minimum utilization of the array part of a mixed hash/array table. This - * is a speed/memory-usage tradeoff (though it's not straightforward because of - * cache effects). The lower this is, the more memory we'll use. */ -static const double MIN_DENSITY = 0.1; - -bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } - -int log2ceil(uint64_t v) { - int ret = 0; - bool pow2 = is_pow2(v); - while (v >>= 1) ret++; - ret = pow2 ? ret : ret + 1; /* Ceiling. */ - return UPB_MIN(UPB_MAXARRSIZE, ret); -} - -char *upb_strdup(const char *s, upb_alloc *a) { - return upb_strdup2(s, strlen(s), a); -} - -char *upb_strdup2(const char *s, size_t len, upb_alloc *a) { - size_t n; - char *p; - - /* Prevent overflow errors. */ - if (len == SIZE_MAX) return NULL; - /* Always null-terminate, even if binary data; but don't rely on the input to - * have a null-terminating byte since it may be a raw binary buffer. */ - n = len + 1; - p = upb_malloc(a, n); - if (p) { - memcpy(p, s, len); - p[len] = 0; - } - return p; -} - -/* A type to represent the lookup key of either a strtable or an inttable. */ -typedef union { - uintptr_t num; - struct { - const char *str; - size_t len; - } str; -} lookupkey_t; - -static lookupkey_t strkey2(const char *str, size_t len) { - lookupkey_t k; - k.str.str = str; - k.str.len = len; - return k; -} - -static lookupkey_t intkey(uintptr_t key) { - lookupkey_t k; - k.num = key; - return k; -} - -typedef uint32_t hashfunc_t(upb_tabkey key); -typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); - -/* Base table (shared code) ***************************************************/ - -/* For when we need to cast away const. */ -static upb_tabent *mutable_entries(upb_table *t) { - return (upb_tabent*)t->entries; -} - -static bool isfull(upb_table *t) { - if (upb_table_size(t) == 0) { - return true; - } else { - return ((double)(t->count + 1) / upb_table_size(t)) > MAX_LOAD; - } -} - -static bool init(upb_table *t, uint8_t size_lg2, upb_alloc *a) { - size_t bytes; - - t->count = 0; - t->size_lg2 = size_lg2; - t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; - bytes = upb_table_size(t) * sizeof(upb_tabent); - if (bytes > 0) { - t->entries = upb_malloc(a, bytes); - if (!t->entries) return false; - memset(mutable_entries(t), 0, bytes); - } else { - t->entries = NULL; - } - return true; -} - -static void uninit(upb_table *t, upb_alloc *a) { - upb_free(a, mutable_entries(t)); -} - -static upb_tabent *emptyent(upb_table *t) { - upb_tabent *e = mutable_entries(t) + upb_table_size(t); - while (1) { if (upb_tabent_isempty(--e)) return e; UPB_ASSERT(e > t->entries); } -} - -static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) { - return (upb_tabent*)upb_getentry(t, hash); -} - -static const upb_tabent *findentry(const upb_table *t, lookupkey_t key, - uint32_t hash, eqlfunc_t *eql) { - const upb_tabent *e; - - if (t->size_lg2 == 0) return NULL; - e = upb_getentry(t, hash); - if (upb_tabent_isempty(e)) return NULL; - while (1) { - if (eql(e->key, key)) return e; - if ((e = e->next) == NULL) return NULL; - } -} - -static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key, - uint32_t hash, eqlfunc_t *eql) { - return (upb_tabent*)findentry(t, key, hash, eql); -} - -static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v, - uint32_t hash, eqlfunc_t *eql) { - const upb_tabent *e = findentry(t, key, hash, eql); - if (e) { - if (v) { - _upb_value_setval(v, e->val.val); - } - return true; - } else { - return false; - } -} - -/* The given key must not already exist in the table. */ -static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey, - upb_value val, uint32_t hash, - hashfunc_t *hashfunc, eqlfunc_t *eql) { - upb_tabent *mainpos_e; - upb_tabent *our_e; - - UPB_ASSERT(findentry(t, key, hash, eql) == NULL); - - t->count++; - mainpos_e = getentry_mutable(t, hash); - our_e = mainpos_e; - - if (upb_tabent_isempty(mainpos_e)) { - /* Our main position is empty; use it. */ - our_e->next = NULL; - } else { - /* Collision. */ - upb_tabent *new_e = emptyent(t); - /* Head of collider's chain. */ - upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key)); - if (chain == mainpos_e) { - /* Existing ent is in its main posisiton (it has the same hash as us, and - * is the head of our chain). Insert to new ent and append to this chain. */ - new_e->next = mainpos_e->next; - mainpos_e->next = new_e; - our_e = new_e; - } else { - /* Existing ent is not in its main position (it is a node in some other - * chain). This implies that no existing ent in the table has our hash. - * Evict it (updating its chain) and use its ent for head of our chain. */ - *new_e = *mainpos_e; /* copies next. */ - while (chain->next != mainpos_e) { - chain = (upb_tabent*)chain->next; - UPB_ASSERT(chain); - } - chain->next = new_e; - our_e = mainpos_e; - our_e->next = NULL; - } - } - our_e->key = tabkey; - our_e->val.val = val.val; - UPB_ASSERT(findentry(t, key, hash, eql) == our_e); -} - -static bool rm(upb_table *t, lookupkey_t key, upb_value *val, - upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) { - upb_tabent *chain = getentry_mutable(t, hash); - if (upb_tabent_isempty(chain)) return false; - if (eql(chain->key, key)) { - /* Element to remove is at the head of its chain. */ - t->count--; - if (val) _upb_value_setval(val, chain->val.val); - if (removed) *removed = chain->key; - if (chain->next) { - upb_tabent *move = (upb_tabent*)chain->next; - *chain = *move; - move->key = 0; /* Make the slot empty. */ - } else { - chain->key = 0; /* Make the slot empty. */ - } - return true; - } else { - /* Element to remove is either in a non-head position or not in the - * table. */ - while (chain->next && !eql(chain->next->key, key)) { - chain = (upb_tabent*)chain->next; - } - if (chain->next) { - /* Found element to remove. */ - upb_tabent *rm = (upb_tabent*)chain->next; - t->count--; - if (val) _upb_value_setval(val, chain->next->val.val); - if (removed) *removed = rm->key; - rm->key = 0; /* Make the slot empty. */ - chain->next = rm->next; - return true; - } else { - /* Element to remove is not in the table. */ - return false; - } - } -} - -static size_t next(const upb_table *t, size_t i) { - do { - if (++i >= upb_table_size(t)) - return SIZE_MAX; - } while(upb_tabent_isempty(&t->entries[i])); - - return i; -} - -static size_t begin(const upb_table *t) { - return next(t, -1); -} - - -/* upb_strtable ***************************************************************/ - -/* A simple "subclass" of upb_table that only adds a hash function for strings. */ - -static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) { - uint32_t len = (uint32_t) k2.str.len; - char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1); - if (str == NULL) return 0; - memcpy(str, &len, sizeof(uint32_t)); - memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len); - str[sizeof(uint32_t) + k2.str.len] = '\0'; - return (uintptr_t)str; -} - -static uint32_t strhash(upb_tabkey key) { - uint32_t len; - char *str = upb_tabstr(key, &len); - return upb_murmur_hash2(str, len, 0); -} - -static bool streql(upb_tabkey k1, lookupkey_t k2) { - uint32_t len; - char *str = upb_tabstr(k1, &len); - return len == k2.str.len && memcmp(str, k2.str.str, len) == 0; -} - -bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) { - return init(&t->t, 2, a); -} - -void upb_strtable_clear(upb_strtable *t) { - size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); - t->t.count = 0; - memset((char*)t->t.entries, 0, bytes); -} - -void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) { - size_t i; - for (i = 0; i < upb_table_size(&t->t); i++) - upb_free(a, (void*)t->t.entries[i].key); - uninit(&t->t, a); -} - -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { - upb_strtable new_table; - upb_strtable_iter i; - - if (!init(&new_table.t, size_lg2, a)) - return false; - upb_strtable_begin(&i, t); - for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_strview key = upb_strtable_iter_key(&i); - upb_strtable_insert3( - &new_table, key.data, key.size, - upb_strtable_iter_value(&i), a); - } - upb_strtable_uninit2(t, a); - *t = new_table; - return true; -} - -bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len, - upb_value v, upb_alloc *a) { - lookupkey_t key; - upb_tabkey tabkey; - uint32_t hash; - - if (isfull(&t->t)) { - /* Need to resize. New table of double the size, add old elements to it. */ - if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { - return false; - } - } - - key = strkey2(k, len); - tabkey = strcopy(key, a); - if (tabkey == 0) return false; - - hash = upb_murmur_hash2(key.str.str, key.str.len, 0); - insert(&t->t, key, tabkey, v, hash, &strhash, &streql); - return true; -} - -bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, - upb_value *v) { - uint32_t hash = upb_murmur_hash2(key, len, 0); - return lookup(&t->t, strkey2(key, len), v, hash, &streql); -} - -bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, - upb_value *val, upb_alloc *alloc) { - uint32_t hash = upb_murmur_hash2(key, len, 0); - upb_tabkey tabkey; - if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { - if (alloc) { - /* Arena-based allocs don't need to free and won't pass this. */ - upb_free(alloc, (void*)tabkey); - } - return true; - } else { - return false; - } -} - -/* Iteration */ - -void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) { - i->t = t; - i->index = begin(&t->t); -} - -void upb_strtable_next(upb_strtable_iter *i) { - i->index = next(&i->t->t, i->index); -} - -bool upb_strtable_done(const upb_strtable_iter *i) { - if (!i->t) return true; - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(str_tabent(i)); -} - -upb_strview upb_strtable_iter_key(const upb_strtable_iter *i) { - upb_strview key; - uint32_t len; - UPB_ASSERT(!upb_strtable_done(i)); - key.data = upb_tabstr(str_tabent(i)->key, &len); - key.size = len; - return key; -} - -upb_value upb_strtable_iter_value(const upb_strtable_iter *i) { - UPB_ASSERT(!upb_strtable_done(i)); - return _upb_value_val(str_tabent(i)->val.val); -} - -void upb_strtable_iter_setdone(upb_strtable_iter *i) { - i->t = NULL; - i->index = SIZE_MAX; -} - -bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, - const upb_strtable_iter *i2) { - if (upb_strtable_done(i1) && upb_strtable_done(i2)) - return true; - return i1->t == i2->t && i1->index == i2->index; -} - - -/* upb_inttable ***************************************************************/ - -/* For inttables we use a hybrid structure where small keys are kept in an - * array and large keys are put in the hash table. */ - -static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } - -static bool inteql(upb_tabkey k1, lookupkey_t k2) { - return k1 == k2.num; -} - -static upb_tabval *mutable_array(upb_inttable *t) { - return (upb_tabval*)t->array; -} - -static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) { - if (key < t->array_size) { - return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; - } else { - upb_tabent *e = - findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); - return e ? &e->val : NULL; - } -} - -static const upb_tabval *inttable_val_const(const upb_inttable *t, - uintptr_t key) { - return inttable_val((upb_inttable*)t, key); -} - -size_t upb_inttable_count(const upb_inttable *t) { - return t->t.count + t->array_count; -} - -static void check(upb_inttable *t) { - UPB_UNUSED(t); -#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) - { - /* This check is very expensive (makes inserts/deletes O(N)). */ - size_t count = 0; - upb_inttable_iter i; - upb_inttable_begin(&i, t); - for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { - UPB_ASSERT(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); - } - UPB_ASSERT(count == upb_inttable_count(t)); - } -#endif -} - -bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, - upb_alloc *a) { - size_t array_bytes; - - if (!init(&t->t, hsize_lg2, a)) return false; - /* Always make the array part at least 1 long, so that we know key 0 - * won't be in the hash part, which simplifies things. */ - t->array_size = UPB_MAX(1, asize); - t->array_count = 0; - array_bytes = t->array_size * sizeof(upb_value); - t->array = upb_malloc(a, array_bytes); - if (!t->array) { - uninit(&t->t, a); - return false; - } - memset(mutable_array(t), 0xff, array_bytes); - check(t); - return true; -} - -bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) { - return upb_inttable_sizedinit(t, 0, 4, a); -} - -void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) { - uninit(&t->t, a); - upb_free(a, mutable_array(t)); -} - -bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, - upb_alloc *a) { - upb_tabval tabval; - tabval.val = val.val; - UPB_ASSERT(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ - - if (key < t->array_size) { - UPB_ASSERT(!upb_arrhas(t->array[key])); - t->array_count++; - mutable_array(t)[key].val = val.val; - } else { - if (isfull(&t->t)) { - /* Need to resize the hash part, but we re-use the array part. */ - size_t i; - upb_table new_table; - - if (!init(&new_table, t->t.size_lg2 + 1, a)) { - return false; - } - - for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { - const upb_tabent *e = &t->t.entries[i]; - uint32_t hash; - upb_value v; - - _upb_value_setval(&v, e->val.val); - hash = upb_inthash(e->key); - insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); - } - - UPB_ASSERT(t->t.count == new_table.count); - - uninit(&t->t, a); - t->t = new_table; - } - insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); - } - check(t); - return true; -} - -bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) { - const upb_tabval *table_v = inttable_val_const(t, key); - if (!table_v) return false; - if (v) _upb_value_setval(v, table_v->val); - return true; -} - -bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) { - upb_tabval *table_v = inttable_val(t, key); - if (!table_v) return false; - table_v->val = val.val; - return true; -} - -bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { - bool success; - if (key < t->array_size) { - if (upb_arrhas(t->array[key])) { - upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; - t->array_count--; - if (val) { - _upb_value_setval(val, t->array[key].val); - } - mutable_array(t)[key] = empty; - success = true; - } else { - success = false; - } - } else { - success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql); - } - check(t); - return success; -} - -bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a) { - return upb_inttable_insert2(t, upb_inttable_count(t), val, a); -} - -upb_value upb_inttable_pop(upb_inttable *t) { - upb_value val; - bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val); - UPB_ASSERT(ok); - return val; -} - -bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, - upb_alloc *a) { - return upb_inttable_insert2(t, (uintptr_t)key, val, a); -} - -bool upb_inttable_lookupptr(const upb_inttable *t, const void *key, - upb_value *v) { - return upb_inttable_lookup(t, (uintptr_t)key, v); -} - -bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { - return upb_inttable_remove(t, (uintptr_t)key, val); -} - -void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { - /* A power-of-two histogram of the table keys. */ - size_t counts[UPB_MAXARRSIZE + 1] = {0}; - - /* The max key in each bucket. */ - uintptr_t max[UPB_MAXARRSIZE + 1] = {0}; - - upb_inttable_iter i; - size_t arr_count; - int size_lg2; - upb_inttable new_t; - - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t key = upb_inttable_iter_key(&i); - int bucket = log2ceil(key); - max[bucket] = UPB_MAX(max[bucket], key); - counts[bucket]++; - } - - /* Find the largest power of two that satisfies the MIN_DENSITY - * definition (while actually having some keys). */ - arr_count = upb_inttable_count(t); - - for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) { - if (counts[size_lg2] == 0) { - /* We can halve again without losing any entries. */ - continue; - } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) { - break; - } - - arr_count -= counts[size_lg2]; - } - - UPB_ASSERT(arr_count <= upb_inttable_count(t)); - - { - /* Insert all elements into new, perfectly-sized table. */ - size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */ - size_t hash_count = upb_inttable_count(t) - arr_count; - size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; - int hashsize_lg2 = log2ceil(hash_size); - - upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a); - upb_inttable_begin(&i, t); - for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { - uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a); - } - UPB_ASSERT(new_t.array_size == arr_size); - UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2); - } - upb_inttable_uninit2(t, a); - *t = new_t; -} - -/* Iteration. */ - -static const upb_tabent *int_tabent(const upb_inttable_iter *i) { - UPB_ASSERT(!i->array_part); - return &i->t->t.entries[i->index]; -} - -static upb_tabval int_arrent(const upb_inttable_iter *i) { - UPB_ASSERT(i->array_part); - return i->t->array[i->index]; -} - -void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) { - i->t = t; - i->index = -1; - i->array_part = true; - upb_inttable_next(i); -} - -void upb_inttable_next(upb_inttable_iter *iter) { - const upb_inttable *t = iter->t; - if (iter->array_part) { - while (++iter->index < t->array_size) { - if (upb_arrhas(int_arrent(iter))) { - return; - } - } - iter->array_part = false; - iter->index = begin(&t->t); - } else { - iter->index = next(&t->t, iter->index); - } -} - -bool upb_inttable_done(const upb_inttable_iter *i) { - if (!i->t) return true; - if (i->array_part) { - return i->index >= i->t->array_size || - !upb_arrhas(int_arrent(i)); - } else { - return i->index >= upb_table_size(&i->t->t) || - upb_tabent_isempty(int_tabent(i)); - } -} - -uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) { - UPB_ASSERT(!upb_inttable_done(i)); - return i->array_part ? i->index : int_tabent(i)->key; -} - -upb_value upb_inttable_iter_value(const upb_inttable_iter *i) { - UPB_ASSERT(!upb_inttable_done(i)); - return _upb_value_val( - i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val); -} - -void upb_inttable_iter_setdone(upb_inttable_iter *i) { - i->t = NULL; - i->index = SIZE_MAX; - i->array_part = false; -} - -bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, - const upb_inttable_iter *i2) { - if (upb_inttable_done(i1) && upb_inttable_done(i2)) - return true; - return i1->t == i2->t && i1->index == i2->index && - i1->array_part == i2->array_part; -} - -#if defined(UPB_UNALIGNED_READS_OK) || defined(__s390x__) -/* ----------------------------------------------------------------------------- - * MurmurHash2, by Austin Appleby (released as public domain). - * Reformatted and C99-ified by Joshua Haberman. - * Note - This code makes a few assumptions about how your machine behaves - - * 1. We can read a 4-byte value from any address without crashing - * 2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t - * And it has a few limitations - - * 1. It will not work incrementally. - * 2. It will not produce the same results on little-endian and big-endian - * machines. */ -uint32_t upb_murmur_hash2(const void *key, size_t len, uint32_t seed) { - /* 'm' and 'r' are mixing constants generated offline. - * They're not really 'magic', they just happen to work well. */ - const uint32_t m = 0x5bd1e995; - const int32_t r = 24; - - /* Initialize the hash to a 'random' value */ - uint32_t h = seed ^ len; - - /* Mix 4 bytes at a time into the hash */ - const uint8_t * data = (const uint8_t *)key; - while(len >= 4) { - uint32_t k; - memcpy(&k, data, sizeof(k)); - - k *= m; - k ^= k >> r; - k *= m; - - h *= m; - h ^= k; - - data += 4; - len -= 4; - } - - /* Handle the last few bytes of the input array */ - switch(len) { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; h *= m; - }; - - /* Do a few final mixes of the hash to ensure the last few - * bytes are well-incorporated. */ - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - -#else /* !UPB_UNALIGNED_READS_OK */ - -/* ----------------------------------------------------------------------------- - * MurmurHashAligned2, by Austin Appleby - * Same algorithm as MurmurHash2, but only does aligned reads - should be safer - * on certain platforms. - * Performance will be lower than MurmurHash2 */ - -#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } - -uint32_t upb_murmur_hash2(const void * key, size_t len, uint32_t seed) { - const uint32_t m = 0x5bd1e995; - const int32_t r = 24; - const uint8_t * data = (const uint8_t *)key; - uint32_t h = (uint32_t)(seed ^ len); - uint8_t align = (uintptr_t)data & 3; - - if(align && (len >= 4)) { - /* Pre-load the temp registers */ - uint32_t t = 0, d = 0; - int32_t sl; - int32_t sr; - - switch(align) { - case 1: t |= data[2] << 16; - case 2: t |= data[1] << 8; - case 3: t |= data[0]; - } - - t <<= (8 * align); - - data += 4-align; - len -= 4-align; - - sl = 8 * (4-align); - sr = 8 * align; - - /* Mix */ - - while(len >= 4) { - uint32_t k; - - d = *(uint32_t *)data; - t = (t >> sr) | (d << sl); - - k = t; - - MIX(h,k,m); - - t = d; - - data += 4; - len -= 4; - } - - /* Handle leftover data in temp registers */ - - d = 0; - - if(len >= align) { - uint32_t k; - - switch(align) { - case 3: d |= data[2] << 16; - case 2: d |= data[1] << 8; - case 1: d |= data[0]; - } - - k = (t >> sr) | (d << sl); - MIX(h,k,m); - - data += align; - len -= align; - - /* ---------- - * Handle tail bytes */ - - switch(len) { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; h *= m; - }; - } else { - switch(len) { - case 3: d |= data[2] << 16; - case 2: d |= data[1] << 8; - case 1: d |= data[0]; - case 0: h ^= (t >> sr) | (d << sl); h *= m; - } - } - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; - } else { - while(len >= 4) { - uint32_t k = *(uint32_t *)data; - - MIX(h,k,m); - - data += 4; - len -= 4; - } - - /* ---------- - * Handle tail bytes */ - - switch(len) { - case 3: h ^= data[2] << 16; - case 2: h ^= data[1] << 8; - case 1: h ^= data[0]; h *= m; - }; - - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; - } -} -#undef MIX - -#endif /* UPB_UNALIGNED_READS_OK */ - - -#include -#include -#include -#include -#include -#include -#include - - -/* upb_status *****************************************************************/ - -void upb_status_clear(upb_status *status) { - if (!status) return; - status->ok = true; - status->msg[0] = '\0'; -} - -bool upb_ok(const upb_status *status) { return status->ok; } - -const char *upb_status_errmsg(const upb_status *status) { return status->msg; } - -void upb_status_seterrmsg(upb_status *status, const char *msg) { - if (!status) return; - status->ok = false; - strncpy(status->msg, msg, UPB_STATUS_MAX_MESSAGE - 1); - status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0'; -} - -void upb_status_seterrf(upb_status *status, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - upb_status_vseterrf(status, fmt, args); - va_end(args); -} - -void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) { - if (!status) return; - status->ok = false; - _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args); - status->msg[UPB_STATUS_MAX_MESSAGE - 1] = '\0'; -} - -/* upb_alloc ******************************************************************/ - -static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, - size_t size) { - UPB_UNUSED(alloc); - UPB_UNUSED(oldsize); - if (size == 0) { - free(ptr); - return NULL; - } else { - return realloc(ptr, size); - } -} - -upb_alloc upb_alloc_global = {&upb_global_allocfunc}; - -/* upb_arena ******************************************************************/ - -/* Be conservative and choose 16 in case anyone is using SSE. */ - -typedef struct mem_block { - struct mem_block *next; - uint32_t size; - uint32_t cleanups; - /* Data follows. */ -} mem_block; - -typedef struct cleanup_ent { - upb_cleanup_func *cleanup; - void *ud; -} cleanup_ent; - -struct upb_arena { - _upb_arena_head head; - uint32_t *cleanups; - - /* Allocator to allocate arena blocks. We are responsible for freeing these - * when we are destroyed. */ - upb_alloc *block_alloc; - uint32_t last_size; - - /* When multiple arenas are fused together, each arena points to a parent - * arena (root points to itself). The root tracks how many live arenas - * reference it. */ - uint32_t refcount; /* Only used when a->parent == a */ - struct upb_arena *parent; - - /* Linked list of blocks to free/cleanup. */ - mem_block *freelist, *freelist_tail; -}; - -static const size_t memblock_reserve = UPB_ALIGN_UP(sizeof(mem_block), 16); - -static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size) { - mem_block *block = ptr; - - block->next = a->freelist; - block->size = size; - block->cleanups = 0; - a->freelist = block; - a->last_size = size; - if (!a->freelist_tail) a->freelist_tail = block; - - a->head.ptr = UPB_PTR_AT(block, memblock_reserve, char); - a->head.end = UPB_PTR_AT(block, size, char); - a->cleanups = &block->cleanups; - - /* TODO(haberman): ASAN poison. */ -} - -static bool upb_arena_allocblock(upb_arena *a, size_t size) { - size_t block_size = UPB_MAX(size, a->last_size * 2) + memblock_reserve; - mem_block *block = upb_malloc(a->block_alloc, block_size); - - if (!block) return false; - upb_arena_addblock(a, block, block_size); - return true; -} - -static bool arena_has(upb_arena *a, size_t size) { - _upb_arena_head *h = (_upb_arena_head*)a; - return (size_t)(h->end - h->ptr) >= size; -} - -void *_upb_arena_slowmalloc(upb_arena *a, size_t size) { - if (!upb_arena_allocblock(a, size)) return NULL; /* Out of memory. */ - UPB_ASSERT(arena_has(a, size)); - return upb_arena_malloc(a, size); -} - -static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize, - size_t size) { - upb_arena *a = (upb_arena*)alloc; /* upb_alloc is initial member. */ - return upb_arena_realloc(a, ptr, oldsize, size); -} - -static upb_arena *arena_findroot(upb_arena *a) { - /* Path splitting keeps time complexity down, see: - * https://en.wikipedia.org/wiki/Disjoint-set_data_structure */ - while (a->parent != a) { - upb_arena *next = a->parent; - a->parent = next->parent; - a = next; - } - return a; -} - -/* Public Arena API ***********************************************************/ - -upb_arena *arena_initslow(void *mem, size_t n, upb_alloc *alloc) { - const size_t first_block_overhead = sizeof(upb_arena) + memblock_reserve; - upb_arena *a; - - /* We need to malloc the initial block. */ - n = first_block_overhead + 256; - if (!alloc || !(mem = upb_malloc(alloc, n))) { - return NULL; - } - - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_arena); - n -= sizeof(*a); - - a->head.alloc.func = &upb_arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->freelist = NULL; - a->freelist_tail = NULL; - - upb_arena_addblock(a, mem, n); - - return a; -} - -upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc) { - upb_arena *a; - - /* Round block size down to alignof(*a) since we will allocate the arena - * itself at the end. */ - n = UPB_ALIGN_DOWN(n, UPB_ALIGN_OF(upb_arena)); - - if (UPB_UNLIKELY(n < sizeof(upb_arena))) { - return arena_initslow(mem, n, alloc); - } - - a = UPB_PTR_AT(mem, n - sizeof(*a), upb_arena); - n -= sizeof(*a); - - a->head.alloc.func = &upb_arena_doalloc; - a->block_alloc = alloc; - a->parent = a; - a->refcount = 1; - a->last_size = 128; - a->head.ptr = mem; - a->head.end = UPB_PTR_AT(mem, n, char); - a->freelist = NULL; - a->cleanups = NULL; - - return a; -} - -static void arena_dofree(upb_arena *a) { - mem_block *block = a->freelist; - UPB_ASSERT(a->parent == a); - UPB_ASSERT(a->refcount == 0); - - while (block) { - /* Load first since we are deleting block. */ - mem_block *next = block->next; - - if (block->cleanups > 0) { - cleanup_ent *end = UPB_PTR_AT(block, block->size, void); - cleanup_ent *ptr = end - block->cleanups; - - for (; ptr < end; ptr++) { - ptr->cleanup(ptr->ud); - } - } - - upb_free(a->block_alloc, block); - block = next; - } -} - -void upb_arena_free(upb_arena *a) { - a = arena_findroot(a); - if (--a->refcount == 0) arena_dofree(a); -} - -bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func) { - cleanup_ent *ent; - - if (!a->cleanups || !arena_has(a, sizeof(cleanup_ent))) { - if (!upb_arena_allocblock(a, 128)) return false; /* Out of memory. */ - UPB_ASSERT(arena_has(a, sizeof(cleanup_ent))); - } - - a->head.end -= sizeof(cleanup_ent); - ent = (cleanup_ent*)a->head.end; - (*a->cleanups)++; - - ent->cleanup = func; - ent->ud = ud; - - return true; -} - -void upb_arena_fuse(upb_arena *a1, upb_arena *a2) { - upb_arena *r1 = arena_findroot(a1); - upb_arena *r2 = arena_findroot(a2); - - if (r1 == r2) return; /* Already fused. */ - - /* We want to join the smaller tree to the larger tree. - * So swap first if they are backwards. */ - if (r1->refcount < r2->refcount) { - upb_arena *tmp = r1; - r1 = r2; - r2 = tmp; - } - - /* r1 takes over r2's freelist and refcount. */ - r1->refcount += r2->refcount; - if (r2->freelist_tail) { - UPB_ASSERT(r2->freelist_tail->next == NULL); - r2->freelist_tail->next = r1->freelist; - r1->freelist = r2->freelist; - } - r2->parent = r1; -} -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#include - - -static const upb_msglayout *const google_protobuf_FileDescriptorSet_submsgs[1] = { - &google_protobuf_FileDescriptorProto_msginit, -}; - -static const upb_msglayout_field google_protobuf_FileDescriptorSet__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_FileDescriptorSet_msginit = { - &google_protobuf_FileDescriptorSet_submsgs[0], - &google_protobuf_FileDescriptorSet__fields[0], - UPB_SIZE(4, 8), 1, false, -}; - -static const upb_msglayout *const google_protobuf_FileDescriptorProto_submsgs[6] = { - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_FileOptions_msginit, - &google_protobuf_ServiceDescriptorProto_msginit, - &google_protobuf_SourceCodeInfo_msginit, -}; - -static const upb_msglayout_field google_protobuf_FileDescriptorProto__fields[12] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {2, UPB_SIZE(12, 24), 2, 0, 9, 1}, - {3, UPB_SIZE(36, 72), 0, 0, 9, 3}, - {4, UPB_SIZE(40, 80), 0, 0, 11, 3}, - {5, UPB_SIZE(44, 88), 0, 1, 11, 3}, - {6, UPB_SIZE(48, 96), 0, 4, 11, 3}, - {7, UPB_SIZE(52, 104), 0, 2, 11, 3}, - {8, UPB_SIZE(28, 56), 4, 3, 11, 1}, - {9, UPB_SIZE(32, 64), 5, 5, 11, 1}, - {10, UPB_SIZE(56, 112), 0, 0, 5, 3}, - {11, UPB_SIZE(60, 120), 0, 0, 5, 3}, - {12, UPB_SIZE(20, 40), 3, 0, 9, 1}, -}; - -const upb_msglayout google_protobuf_FileDescriptorProto_msginit = { - &google_protobuf_FileDescriptorProto_submsgs[0], - &google_protobuf_FileDescriptorProto__fields[0], - UPB_SIZE(64, 128), 12, false, -}; - -static const upb_msglayout *const google_protobuf_DescriptorProto_submsgs[8] = { - &google_protobuf_DescriptorProto_msginit, - &google_protobuf_DescriptorProto_ExtensionRange_msginit, - &google_protobuf_DescriptorProto_ReservedRange_msginit, - &google_protobuf_EnumDescriptorProto_msginit, - &google_protobuf_FieldDescriptorProto_msginit, - &google_protobuf_MessageOptions_msginit, - &google_protobuf_OneofDescriptorProto_msginit, -}; - -static const upb_msglayout_field google_protobuf_DescriptorProto__fields[10] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {2, UPB_SIZE(16, 32), 0, 4, 11, 3}, - {3, UPB_SIZE(20, 40), 0, 0, 11, 3}, - {4, UPB_SIZE(24, 48), 0, 3, 11, 3}, - {5, UPB_SIZE(28, 56), 0, 1, 11, 3}, - {6, UPB_SIZE(32, 64), 0, 4, 11, 3}, - {7, UPB_SIZE(12, 24), 2, 5, 11, 1}, - {8, UPB_SIZE(36, 72), 0, 6, 11, 3}, - {9, UPB_SIZE(40, 80), 0, 2, 11, 3}, - {10, UPB_SIZE(44, 88), 0, 0, 9, 3}, -}; - -const upb_msglayout google_protobuf_DescriptorProto_msginit = { - &google_protobuf_DescriptorProto_submsgs[0], - &google_protobuf_DescriptorProto__fields[0], - UPB_SIZE(48, 96), 10, false, -}; - -static const upb_msglayout *const google_protobuf_DescriptorProto_ExtensionRange_submsgs[1] = { - &google_protobuf_ExtensionRangeOptions_msginit, -}; - -static const upb_msglayout_field google_protobuf_DescriptorProto_ExtensionRange__fields[3] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, - {3, UPB_SIZE(12, 16), 3, 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit = { - &google_protobuf_DescriptorProto_ExtensionRange_submsgs[0], - &google_protobuf_DescriptorProto_ExtensionRange__fields[0], - UPB_SIZE(16, 24), 3, false, -}; - -static const upb_msglayout_field google_protobuf_DescriptorProto_ReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit = { - NULL, - &google_protobuf_DescriptorProto_ReservedRange__fields[0], - UPB_SIZE(12, 12), 2, false, -}; - -static const upb_msglayout *const google_protobuf_ExtensionRangeOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_ExtensionRangeOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit = { - &google_protobuf_ExtensionRangeOptions_submsgs[0], - &google_protobuf_ExtensionRangeOptions__fields[0], - UPB_SIZE(4, 8), 1, false, -}; - -static const upb_msglayout *const google_protobuf_FieldDescriptorProto_submsgs[1] = { - &google_protobuf_FieldOptions_msginit, -}; - -static const upb_msglayout_field google_protobuf_FieldDescriptorProto__fields[11] = { - {1, UPB_SIZE(36, 40), 6, 0, 9, 1}, - {2, UPB_SIZE(44, 56), 7, 0, 9, 1}, - {3, UPB_SIZE(24, 24), 3, 0, 5, 1}, - {4, UPB_SIZE(8, 8), 1, 0, 14, 1}, - {5, UPB_SIZE(16, 16), 2, 0, 14, 1}, - {6, UPB_SIZE(52, 72), 8, 0, 9, 1}, - {7, UPB_SIZE(60, 88), 9, 0, 9, 1}, - {8, UPB_SIZE(76, 120), 11, 0, 11, 1}, - {9, UPB_SIZE(28, 28), 4, 0, 5, 1}, - {10, UPB_SIZE(68, 104), 10, 0, 9, 1}, - {17, UPB_SIZE(32, 32), 5, 0, 8, 1}, -}; - -const upb_msglayout google_protobuf_FieldDescriptorProto_msginit = { - &google_protobuf_FieldDescriptorProto_submsgs[0], - &google_protobuf_FieldDescriptorProto__fields[0], - UPB_SIZE(80, 128), 11, false, -}; - -static const upb_msglayout *const google_protobuf_OneofDescriptorProto_submsgs[1] = { - &google_protobuf_OneofOptions_msginit, -}; - -static const upb_msglayout_field google_protobuf_OneofDescriptorProto__fields[2] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {2, UPB_SIZE(12, 24), 2, 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_OneofDescriptorProto_msginit = { - &google_protobuf_OneofDescriptorProto_submsgs[0], - &google_protobuf_OneofDescriptorProto__fields[0], - UPB_SIZE(16, 32), 2, false, -}; - -static const upb_msglayout *const google_protobuf_EnumDescriptorProto_submsgs[3] = { - &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, - &google_protobuf_EnumOptions_msginit, - &google_protobuf_EnumValueDescriptorProto_msginit, -}; - -static const upb_msglayout_field google_protobuf_EnumDescriptorProto__fields[5] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {2, UPB_SIZE(16, 32), 0, 2, 11, 3}, - {3, UPB_SIZE(12, 24), 2, 1, 11, 1}, - {4, UPB_SIZE(20, 40), 0, 0, 11, 3}, - {5, UPB_SIZE(24, 48), 0, 0, 9, 3}, -}; - -const upb_msglayout google_protobuf_EnumDescriptorProto_msginit = { - &google_protobuf_EnumDescriptorProto_submsgs[0], - &google_protobuf_EnumDescriptorProto__fields[0], - UPB_SIZE(32, 64), 5, false, -}; - -static const upb_msglayout_field google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[2] = { - {1, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {2, UPB_SIZE(8, 8), 2, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit = { - NULL, - &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields[0], - UPB_SIZE(12, 12), 2, false, -}; - -static const upb_msglayout *const google_protobuf_EnumValueDescriptorProto_submsgs[1] = { - &google_protobuf_EnumValueOptions_msginit, -}; - -static const upb_msglayout_field google_protobuf_EnumValueDescriptorProto__fields[3] = { - {1, UPB_SIZE(8, 8), 2, 0, 9, 1}, - {2, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {3, UPB_SIZE(16, 24), 3, 0, 11, 1}, -}; - -const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit = { - &google_protobuf_EnumValueDescriptorProto_submsgs[0], - &google_protobuf_EnumValueDescriptorProto__fields[0], - UPB_SIZE(24, 32), 3, false, -}; - -static const upb_msglayout *const google_protobuf_ServiceDescriptorProto_submsgs[2] = { - &google_protobuf_MethodDescriptorProto_msginit, - &google_protobuf_ServiceOptions_msginit, -}; - -static const upb_msglayout_field google_protobuf_ServiceDescriptorProto__fields[3] = { - {1, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {2, UPB_SIZE(16, 32), 0, 0, 11, 3}, - {3, UPB_SIZE(12, 24), 2, 1, 11, 1}, -}; - -const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit = { - &google_protobuf_ServiceDescriptorProto_submsgs[0], - &google_protobuf_ServiceDescriptorProto__fields[0], - UPB_SIZE(24, 48), 3, false, -}; - -static const upb_msglayout *const google_protobuf_MethodDescriptorProto_submsgs[1] = { - &google_protobuf_MethodOptions_msginit, -}; - -static const upb_msglayout_field google_protobuf_MethodDescriptorProto__fields[6] = { - {1, UPB_SIZE(4, 8), 3, 0, 9, 1}, - {2, UPB_SIZE(12, 24), 4, 0, 9, 1}, - {3, UPB_SIZE(20, 40), 5, 0, 9, 1}, - {4, UPB_SIZE(28, 56), 6, 0, 11, 1}, - {5, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {6, UPB_SIZE(2, 2), 2, 0, 8, 1}, -}; - -const upb_msglayout google_protobuf_MethodDescriptorProto_msginit = { - &google_protobuf_MethodDescriptorProto_submsgs[0], - &google_protobuf_MethodDescriptorProto__fields[0], - UPB_SIZE(32, 64), 6, false, -}; - -static const upb_msglayout *const google_protobuf_FileOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_FileOptions__fields[21] = { - {1, UPB_SIZE(28, 32), 11, 0, 9, 1}, - {8, UPB_SIZE(36, 48), 12, 0, 9, 1}, - {9, UPB_SIZE(8, 8), 1, 0, 14, 1}, - {10, UPB_SIZE(16, 16), 2, 0, 8, 1}, - {11, UPB_SIZE(44, 64), 13, 0, 9, 1}, - {16, UPB_SIZE(17, 17), 3, 0, 8, 1}, - {17, UPB_SIZE(18, 18), 4, 0, 8, 1}, - {18, UPB_SIZE(19, 19), 5, 0, 8, 1}, - {20, UPB_SIZE(20, 20), 6, 0, 8, 1}, - {23, UPB_SIZE(21, 21), 7, 0, 8, 1}, - {27, UPB_SIZE(22, 22), 8, 0, 8, 1}, - {31, UPB_SIZE(23, 23), 9, 0, 8, 1}, - {36, UPB_SIZE(52, 80), 14, 0, 9, 1}, - {37, UPB_SIZE(60, 96), 15, 0, 9, 1}, - {39, UPB_SIZE(68, 112), 16, 0, 9, 1}, - {40, UPB_SIZE(76, 128), 17, 0, 9, 1}, - {41, UPB_SIZE(84, 144), 18, 0, 9, 1}, - {42, UPB_SIZE(24, 24), 10, 0, 8, 1}, - {44, UPB_SIZE(92, 160), 19, 0, 9, 1}, - {45, UPB_SIZE(100, 176), 20, 0, 9, 1}, - {999, UPB_SIZE(108, 192), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_FileOptions_msginit = { - &google_protobuf_FileOptions_submsgs[0], - &google_protobuf_FileOptions__fields[0], - UPB_SIZE(112, 208), 21, false, -}; - -static const upb_msglayout *const google_protobuf_MessageOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_MessageOptions__fields[5] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {2, UPB_SIZE(2, 2), 2, 0, 8, 1}, - {3, UPB_SIZE(3, 3), 3, 0, 8, 1}, - {7, UPB_SIZE(4, 4), 4, 0, 8, 1}, - {999, UPB_SIZE(8, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_MessageOptions_msginit = { - &google_protobuf_MessageOptions_submsgs[0], - &google_protobuf_MessageOptions__fields[0], - UPB_SIZE(12, 16), 5, false, -}; - -static const upb_msglayout *const google_protobuf_FieldOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_FieldOptions__fields[7] = { - {1, UPB_SIZE(8, 8), 1, 0, 14, 1}, - {2, UPB_SIZE(24, 24), 3, 0, 8, 1}, - {3, UPB_SIZE(25, 25), 4, 0, 8, 1}, - {5, UPB_SIZE(26, 26), 5, 0, 8, 1}, - {6, UPB_SIZE(16, 16), 2, 0, 14, 1}, - {10, UPB_SIZE(27, 27), 6, 0, 8, 1}, - {999, UPB_SIZE(28, 32), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_FieldOptions_msginit = { - &google_protobuf_FieldOptions_submsgs[0], - &google_protobuf_FieldOptions__fields[0], - UPB_SIZE(32, 40), 7, false, -}; - -static const upb_msglayout *const google_protobuf_OneofOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_OneofOptions__fields[1] = { - {999, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_OneofOptions_msginit = { - &google_protobuf_OneofOptions_submsgs[0], - &google_protobuf_OneofOptions__fields[0], - UPB_SIZE(4, 8), 1, false, -}; - -static const upb_msglayout *const google_protobuf_EnumOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_EnumOptions__fields[3] = { - {2, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {3, UPB_SIZE(2, 2), 2, 0, 8, 1}, - {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_EnumOptions_msginit = { - &google_protobuf_EnumOptions_submsgs[0], - &google_protobuf_EnumOptions__fields[0], - UPB_SIZE(8, 16), 3, false, -}; - -static const upb_msglayout *const google_protobuf_EnumValueOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_EnumValueOptions__fields[2] = { - {1, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_EnumValueOptions_msginit = { - &google_protobuf_EnumValueOptions_submsgs[0], - &google_protobuf_EnumValueOptions__fields[0], - UPB_SIZE(8, 16), 2, false, -}; - -static const upb_msglayout *const google_protobuf_ServiceOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_ServiceOptions__fields[2] = { - {33, UPB_SIZE(1, 1), 1, 0, 8, 1}, - {999, UPB_SIZE(4, 8), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_ServiceOptions_msginit = { - &google_protobuf_ServiceOptions_submsgs[0], - &google_protobuf_ServiceOptions__fields[0], - UPB_SIZE(8, 16), 2, false, -}; - -static const upb_msglayout *const google_protobuf_MethodOptions_submsgs[1] = { - &google_protobuf_UninterpretedOption_msginit, -}; - -static const upb_msglayout_field google_protobuf_MethodOptions__fields[3] = { - {33, UPB_SIZE(16, 16), 2, 0, 8, 1}, - {34, UPB_SIZE(8, 8), 1, 0, 14, 1}, - {999, UPB_SIZE(20, 24), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_MethodOptions_msginit = { - &google_protobuf_MethodOptions_submsgs[0], - &google_protobuf_MethodOptions__fields[0], - UPB_SIZE(24, 32), 3, false, -}; - -static const upb_msglayout *const google_protobuf_UninterpretedOption_submsgs[1] = { - &google_protobuf_UninterpretedOption_NamePart_msginit, -}; - -static const upb_msglayout_field google_protobuf_UninterpretedOption__fields[7] = { - {2, UPB_SIZE(56, 80), 0, 0, 11, 3}, - {3, UPB_SIZE(32, 32), 4, 0, 9, 1}, - {4, UPB_SIZE(8, 8), 1, 0, 4, 1}, - {5, UPB_SIZE(16, 16), 2, 0, 3, 1}, - {6, UPB_SIZE(24, 24), 3, 0, 1, 1}, - {7, UPB_SIZE(40, 48), 5, 0, 12, 1}, - {8, UPB_SIZE(48, 64), 6, 0, 9, 1}, -}; - -const upb_msglayout google_protobuf_UninterpretedOption_msginit = { - &google_protobuf_UninterpretedOption_submsgs[0], - &google_protobuf_UninterpretedOption__fields[0], - UPB_SIZE(64, 96), 7, false, -}; - -static const upb_msglayout_field google_protobuf_UninterpretedOption_NamePart__fields[2] = { - {1, UPB_SIZE(4, 8), 2, 0, 9, 2}, - {2, UPB_SIZE(1, 1), 1, 0, 8, 2}, -}; - -const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit = { - NULL, - &google_protobuf_UninterpretedOption_NamePart__fields[0], - UPB_SIZE(16, 32), 2, false, -}; - -static const upb_msglayout *const google_protobuf_SourceCodeInfo_submsgs[1] = { - &google_protobuf_SourceCodeInfo_Location_msginit, -}; - -static const upb_msglayout_field google_protobuf_SourceCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_SourceCodeInfo_msginit = { - &google_protobuf_SourceCodeInfo_submsgs[0], - &google_protobuf_SourceCodeInfo__fields[0], - UPB_SIZE(4, 8), 1, false, -}; - -static const upb_msglayout_field google_protobuf_SourceCodeInfo_Location__fields[5] = { - {1, UPB_SIZE(20, 40), 0, 0, 5, _UPB_LABEL_PACKED}, - {2, UPB_SIZE(24, 48), 0, 0, 5, _UPB_LABEL_PACKED}, - {3, UPB_SIZE(4, 8), 1, 0, 9, 1}, - {4, UPB_SIZE(12, 24), 2, 0, 9, 1}, - {6, UPB_SIZE(28, 56), 0, 0, 9, 3}, -}; - -const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit = { - NULL, - &google_protobuf_SourceCodeInfo_Location__fields[0], - UPB_SIZE(32, 64), 5, false, -}; - -static const upb_msglayout *const google_protobuf_GeneratedCodeInfo_submsgs[1] = { - &google_protobuf_GeneratedCodeInfo_Annotation_msginit, -}; - -static const upb_msglayout_field google_protobuf_GeneratedCodeInfo__fields[1] = { - {1, UPB_SIZE(0, 0), 0, 0, 11, 3}, -}; - -const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit = { - &google_protobuf_GeneratedCodeInfo_submsgs[0], - &google_protobuf_GeneratedCodeInfo__fields[0], - UPB_SIZE(4, 8), 1, false, -}; - -static const upb_msglayout_field google_protobuf_GeneratedCodeInfo_Annotation__fields[4] = { - {1, UPB_SIZE(20, 32), 0, 0, 5, _UPB_LABEL_PACKED}, - {2, UPB_SIZE(12, 16), 3, 0, 9, 1}, - {3, UPB_SIZE(4, 4), 1, 0, 5, 1}, - {4, UPB_SIZE(8, 8), 2, 0, 5, 1}, -}; - -const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit = { - NULL, - &google_protobuf_GeneratedCodeInfo_Annotation__fields[0], - UPB_SIZE(24, 48), 4, false, -}; - - - - -#include -#include -#include -#include - - -typedef struct { - size_t len; - char str[1]; /* Null-terminated string data follows. */ -} str_t; - -static str_t *newstr(upb_alloc *alloc, const char *data, size_t len) { - str_t *ret = upb_malloc(alloc, sizeof(*ret) + len); - if (!ret) return NULL; - ret->len = len; - memcpy(ret->str, data, len); - ret->str[len] = '\0'; - return ret; -} - -struct upb_fielddef { - const upb_filedef *file; - const upb_msgdef *msgdef; - const char *full_name; - const char *json_name; - union { - int64_t sint; - uint64_t uint; - double dbl; - float flt; - bool boolean; - str_t *str; - } defaultval; - const upb_oneofdef *oneof; - union { - const upb_msgdef *msgdef; - const upb_enumdef *enumdef; - const google_protobuf_FieldDescriptorProto *unresolved; - } sub; - uint32_t number_; - uint16_t index_; - uint16_t layout_index; - uint32_t selector_base; /* Used to index into a upb::Handlers table. */ - bool is_extension_; - bool lazy_; - bool packed_; - bool proto3_optional_; - upb_descriptortype_t type_; - upb_label_t label_; -}; - -struct upb_msgdef { - const upb_msglayout *layout; - const upb_filedef *file; - const char *full_name; - uint32_t selector_count; - uint32_t submsg_field_count; - - /* Tables for looking up fields by number and name. */ - upb_inttable itof; - upb_strtable ntof; - - const upb_fielddef *fields; - const upb_oneofdef *oneofs; - int field_count; - int oneof_count; - int real_oneof_count; - - /* Is this a map-entry message? */ - bool map_entry; - upb_wellknowntype_t well_known_type; - - /* TODO(haberman): proper extension ranges (there can be multiple). */ -}; - -struct upb_enumdef { - const upb_filedef *file; - const char *full_name; - upb_strtable ntoi; - upb_inttable iton; - int32_t defaultval; -}; - -struct upb_oneofdef { - const upb_msgdef *parent; - const char *full_name; - uint32_t index; - upb_strtable ntof; - upb_inttable itof; -}; - -struct upb_filedef { - const char *name; - const char *package; - const char *phpprefix; - const char *phpnamespace; - upb_syntax_t syntax; - - const upb_filedef **deps; - const upb_msgdef *msgs; - const upb_enumdef *enums; - const upb_fielddef *exts; - - int dep_count; - int msg_count; - int enum_count; - int ext_count; -}; - -struct upb_symtab { - upb_arena *arena; - upb_strtable syms; /* full_name -> packed def ptr */ - upb_strtable files; /* file_name -> upb_filedef* */ -}; - -/* Inside a symtab we store tagged pointers to specific def types. */ -typedef enum { - UPB_DEFTYPE_FIELD = 0, - - /* Only inside symtab table. */ - UPB_DEFTYPE_MSG = 1, - UPB_DEFTYPE_ENUM = 2, - - /* Only inside message table. */ - UPB_DEFTYPE_ONEOF = 1, - UPB_DEFTYPE_FIELD_JSONNAME = 2 -} upb_deftype_t; - -static const void *unpack_def(upb_value v, upb_deftype_t type) { - uintptr_t num = (uintptr_t)upb_value_getconstptr(v); - return (num & 3) == type ? (const void*)(num & ~3) : NULL; -} - -static upb_value pack_def(const void *ptr, upb_deftype_t type) { - uintptr_t num = (uintptr_t)ptr | type; - return upb_value_constptr((const void*)num); -} - -/* isalpha() etc. from are locale-dependent, which we don't want. */ -static bool upb_isbetween(char c, char low, char high) { - return c >= low && c <= high; -} - -static bool upb_isletter(char c) { - return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_'; -} - -static bool upb_isalphanum(char c) { - return upb_isletter(c) || upb_isbetween(c, '0', '9'); -} - -static bool upb_isident(upb_strview name, bool full, upb_status *s) { - const char *str = name.data; - size_t len = name.size; - bool start = true; - size_t i; - for (i = 0; i < len; i++) { - char c = str[i]; - if (c == '.') { - if (start || !full) { - upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str); - return false; - } - start = true; - } else if (start) { - if (!upb_isletter(c)) { - upb_status_seterrf( - s, "invalid name: path components must start with a letter (%s)", - str); - return false; - } - start = false; - } else { - if (!upb_isalphanum(c)) { - upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)", - str); - return false; - } - } - } - return !start; -} - -static const char *shortdefname(const char *fullname) { - const char *p; - - if (fullname == NULL) { - return NULL; - } else if ((p = strrchr(fullname, '.')) == NULL) { - /* No '.' in the name, return the full string. */ - return fullname; - } else { - /* Return one past the last '.'. */ - return p + 1; - } -} - -/* All submessage fields are lower than all other fields. - * Secondly, fields are increasing in order. */ -uint32_t field_rank(const upb_fielddef *f) { - uint32_t ret = upb_fielddef_number(f); - const uint32_t high_bit = 1 << 30; - UPB_ASSERT(ret < high_bit); - if (!upb_fielddef_issubmsg(f)) - ret |= high_bit; - return ret; -} - -int cmp_fields(const void *p1, const void *p2) { - const upb_fielddef *f1 = *(upb_fielddef*const*)p1; - const upb_fielddef *f2 = *(upb_fielddef*const*)p2; - return field_rank(f1) - field_rank(f2); -} - -/* A few implementation details of handlers. We put these here to avoid - * a def -> handlers dependency. */ - -#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/handlers.h. */ - -static uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { - return upb_fielddef_isseq(f) ? 2 : 0; -} - -static uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { - uint32_t ret = 1; - if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ - if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ - if (upb_fielddef_issubmsg(f)) { - /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ - ret += 0; - if (upb_fielddef_lazy(f)) { - /* STARTSTR/ENDSTR/STRING (for lazy) */ - ret += 3; - } - } - return ret; -} - -static void upb_status_setoom(upb_status *status) { - upb_status_seterrmsg(status, "out of memory"); -} - -static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { - /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the - * lowest indexes, but we do not publicly guarantee this. */ - upb_msg_field_iter j; - int i; - uint32_t selector; - int n = upb_msgdef_numfields(m); - upb_fielddef **fields; - - if (n == 0) { - m->selector_count = UPB_STATIC_SELECTOR_COUNT; - m->submsg_field_count = 0; - return true; - } - - fields = upb_gmalloc(n * sizeof(*fields)); - if (!fields) { - upb_status_setoom(s); - return false; - } - - m->submsg_field_count = 0; - for(i = 0, upb_msg_field_begin(&j, m); - !upb_msg_field_done(&j); - upb_msg_field_next(&j), i++) { - upb_fielddef *f = upb_msg_iter_field(&j); - UPB_ASSERT(f->msgdef == m); - if (upb_fielddef_issubmsg(f)) { - m->submsg_field_count++; - } - fields[i] = f; - } - - qsort(fields, n, sizeof(*fields), cmp_fields); - - selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; - for (i = 0; i < n; i++) { - upb_fielddef *f = fields[i]; - f->index_ = i; - f->selector_base = selector + upb_handlers_selectorbaseoffset(f); - selector += upb_handlers_selectorcount(f); - } - m->selector_count = selector; - - upb_gfree(fields); - return true; -} - -static bool check_oneofs(upb_msgdef *m, upb_status *s) { - int i; - int first_synthetic = -1; - upb_oneofdef *mutable_oneofs = (upb_oneofdef*)m->oneofs; - - for (i = 0; i < m->oneof_count; i++) { - mutable_oneofs[i].index = i; - - if (upb_oneofdef_issynthetic(&mutable_oneofs[i])) { - if (first_synthetic == -1) { - first_synthetic = i; - } - } else { - if (first_synthetic != -1) { - upb_status_seterrf( - s, "Synthetic oneofs must be after all other oneofs: %s", - upb_oneofdef_name(&mutable_oneofs[i])); - return false; - } - } - } - - if (first_synthetic == -1) { - m->real_oneof_count = m->oneof_count; - } else { - m->real_oneof_count = first_synthetic; - } - - return true; -} - -static void assign_msg_wellknowntype(upb_msgdef *m) { - const char *name = upb_msgdef_fullname(m); - if (name == NULL) { - m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED; - return; - } - if (!strcmp(name, "google.protobuf.Any")) { - m->well_known_type = UPB_WELLKNOWN_ANY; - } else if (!strcmp(name, "google.protobuf.FieldMask")) { - m->well_known_type = UPB_WELLKNOWN_FIELDMASK; - } else if (!strcmp(name, "google.protobuf.Duration")) { - m->well_known_type = UPB_WELLKNOWN_DURATION; - } else if (!strcmp(name, "google.protobuf.Timestamp")) { - m->well_known_type = UPB_WELLKNOWN_TIMESTAMP; - } else if (!strcmp(name, "google.protobuf.DoubleValue")) { - m->well_known_type = UPB_WELLKNOWN_DOUBLEVALUE; - } else if (!strcmp(name, "google.protobuf.FloatValue")) { - m->well_known_type = UPB_WELLKNOWN_FLOATVALUE; - } else if (!strcmp(name, "google.protobuf.Int64Value")) { - m->well_known_type = UPB_WELLKNOWN_INT64VALUE; - } else if (!strcmp(name, "google.protobuf.UInt64Value")) { - m->well_known_type = UPB_WELLKNOWN_UINT64VALUE; - } else if (!strcmp(name, "google.protobuf.Int32Value")) { - m->well_known_type = UPB_WELLKNOWN_INT32VALUE; - } else if (!strcmp(name, "google.protobuf.UInt32Value")) { - m->well_known_type = UPB_WELLKNOWN_UINT32VALUE; - } else if (!strcmp(name, "google.protobuf.BoolValue")) { - m->well_known_type = UPB_WELLKNOWN_BOOLVALUE; - } else if (!strcmp(name, "google.protobuf.StringValue")) { - m->well_known_type = UPB_WELLKNOWN_STRINGVALUE; - } else if (!strcmp(name, "google.protobuf.BytesValue")) { - m->well_known_type = UPB_WELLKNOWN_BYTESVALUE; - } else if (!strcmp(name, "google.protobuf.Value")) { - m->well_known_type = UPB_WELLKNOWN_VALUE; - } else if (!strcmp(name, "google.protobuf.ListValue")) { - m->well_known_type = UPB_WELLKNOWN_LISTVALUE; - } else if (!strcmp(name, "google.protobuf.Struct")) { - m->well_known_type = UPB_WELLKNOWN_STRUCT; - } else { - m->well_known_type = UPB_WELLKNOWN_UNSPECIFIED; - } -} - - -/* upb_enumdef ****************************************************************/ - -const char *upb_enumdef_fullname(const upb_enumdef *e) { - return e->full_name; -} - -const char *upb_enumdef_name(const upb_enumdef *e) { - return shortdefname(e->full_name); -} - -const upb_filedef *upb_enumdef_file(const upb_enumdef *e) { - return e->file; -} - -int32_t upb_enumdef_default(const upb_enumdef *e) { - UPB_ASSERT(upb_enumdef_iton(e, e->defaultval)); - return e->defaultval; -} - -int upb_enumdef_numvals(const upb_enumdef *e) { - return (int)upb_strtable_count(&e->ntoi); -} - -void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) { - /* We iterate over the ntoi table, to account for duplicate numbers. */ - upb_strtable_begin(i, &e->ntoi); -} - -void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); } -bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); } - -bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, - size_t len, int32_t *num) { - upb_value v; - if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) { - return false; - } - if (num) *num = upb_value_getint32(v); - return true; -} - -const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { - upb_value v; - return upb_inttable_lookup32(&def->iton, num, &v) ? - upb_value_getcstr(v) : NULL; -} - -const char *upb_enum_iter_name(upb_enum_iter *iter) { - return upb_strtable_iter_key(iter).data; -} - -int32_t upb_enum_iter_number(upb_enum_iter *iter) { - return upb_value_getint32(upb_strtable_iter_value(iter)); -} - - -/* upb_fielddef ***************************************************************/ - -const char *upb_fielddef_fullname(const upb_fielddef *f) { - return f->full_name; -} - -upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) { - switch (f->type_) { - case UPB_DESCRIPTOR_TYPE_DOUBLE: - return UPB_TYPE_DOUBLE; - case UPB_DESCRIPTOR_TYPE_FLOAT: - return UPB_TYPE_FLOAT; - case UPB_DESCRIPTOR_TYPE_INT64: - case UPB_DESCRIPTOR_TYPE_SINT64: - case UPB_DESCRIPTOR_TYPE_SFIXED64: - return UPB_TYPE_INT64; - case UPB_DESCRIPTOR_TYPE_INT32: - case UPB_DESCRIPTOR_TYPE_SFIXED32: - case UPB_DESCRIPTOR_TYPE_SINT32: - return UPB_TYPE_INT32; - case UPB_DESCRIPTOR_TYPE_UINT64: - case UPB_DESCRIPTOR_TYPE_FIXED64: - return UPB_TYPE_UINT64; - case UPB_DESCRIPTOR_TYPE_UINT32: - case UPB_DESCRIPTOR_TYPE_FIXED32: - return UPB_TYPE_UINT32; - case UPB_DESCRIPTOR_TYPE_ENUM: - return UPB_TYPE_ENUM; - case UPB_DESCRIPTOR_TYPE_BOOL: - return UPB_TYPE_BOOL; - case UPB_DESCRIPTOR_TYPE_STRING: - return UPB_TYPE_STRING; - case UPB_DESCRIPTOR_TYPE_BYTES: - return UPB_TYPE_BYTES; - case UPB_DESCRIPTOR_TYPE_GROUP: - case UPB_DESCRIPTOR_TYPE_MESSAGE: - return UPB_TYPE_MESSAGE; - } - UPB_UNREACHABLE(); -} - -upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) { - return f->type_; -} - -uint32_t upb_fielddef_index(const upb_fielddef *f) { - return f->index_; -} - -upb_label_t upb_fielddef_label(const upb_fielddef *f) { - return f->label_; -} - -uint32_t upb_fielddef_number(const upb_fielddef *f) { - return f->number_; -} - -bool upb_fielddef_isextension(const upb_fielddef *f) { - return f->is_extension_; -} - -bool upb_fielddef_lazy(const upb_fielddef *f) { - return f->lazy_; -} - -bool upb_fielddef_packed(const upb_fielddef *f) { - return f->packed_; -} - -const char *upb_fielddef_name(const upb_fielddef *f) { - return shortdefname(f->full_name); -} - -const char *upb_fielddef_jsonname(const upb_fielddef *f) { - return f->json_name; -} - -uint32_t upb_fielddef_selectorbase(const upb_fielddef *f) { - return f->selector_base; -} - -const upb_filedef *upb_fielddef_file(const upb_fielddef *f) { - return f->file; -} - -const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) { - return f->msgdef; -} - -const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) { - return f->oneof; -} - -const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f) { - if (!f->oneof || upb_oneofdef_issynthetic(f->oneof)) return NULL; - return f->oneof; -} - -static void chkdefaulttype(const upb_fielddef *f, int ctype) { - UPB_UNUSED(f); - UPB_UNUSED(ctype); -} - -int64_t upb_fielddef_defaultint64(const upb_fielddef *f) { - chkdefaulttype(f, UPB_TYPE_INT64); - return f->defaultval.sint; -} - -int32_t upb_fielddef_defaultint32(const upb_fielddef *f) { - chkdefaulttype(f, UPB_TYPE_INT32); - return (int32_t)f->defaultval.sint; -} - -uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) { - chkdefaulttype(f, UPB_TYPE_UINT64); - return f->defaultval.uint; -} - -uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) { - chkdefaulttype(f, UPB_TYPE_UINT32); - return (uint32_t)f->defaultval.uint; -} - -bool upb_fielddef_defaultbool(const upb_fielddef *f) { - chkdefaulttype(f, UPB_TYPE_BOOL); - return f->defaultval.boolean; -} - -float upb_fielddef_defaultfloat(const upb_fielddef *f) { - chkdefaulttype(f, UPB_TYPE_FLOAT); - return f->defaultval.flt; -} - -double upb_fielddef_defaultdouble(const upb_fielddef *f) { - chkdefaulttype(f, UPB_TYPE_DOUBLE); - return f->defaultval.dbl; -} - -const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) { - str_t *str = f->defaultval.str; - UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_STRING || - upb_fielddef_type(f) == UPB_TYPE_BYTES || - upb_fielddef_type(f) == UPB_TYPE_ENUM); - if (str) { - if (len) *len = str->len; - return str->str; - } else { - if (len) *len = 0; - return NULL; - } -} - -const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) { - UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_MESSAGE); - return f->sub.msgdef; -} - -const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { - UPB_ASSERT(upb_fielddef_type(f) == UPB_TYPE_ENUM); - return f->sub.enumdef; -} - -const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f) { - return &f->msgdef->layout->fields[f->layout_index]; -} - -bool upb_fielddef_issubmsg(const upb_fielddef *f) { - return upb_fielddef_type(f) == UPB_TYPE_MESSAGE; -} - -bool upb_fielddef_isstring(const upb_fielddef *f) { - return upb_fielddef_type(f) == UPB_TYPE_STRING || - upb_fielddef_type(f) == UPB_TYPE_BYTES; -} - -bool upb_fielddef_isseq(const upb_fielddef *f) { - return upb_fielddef_label(f) == UPB_LABEL_REPEATED; -} - -bool upb_fielddef_isprimitive(const upb_fielddef *f) { - return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f); -} - -bool upb_fielddef_ismap(const upb_fielddef *f) { - return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) && - upb_msgdef_mapentry(upb_fielddef_msgsubdef(f)); -} - -bool upb_fielddef_hassubdef(const upb_fielddef *f) { - return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM; -} - -bool upb_fielddef_haspresence(const upb_fielddef *f) { - if (upb_fielddef_isseq(f)) return false; - return upb_fielddef_issubmsg(f) || upb_fielddef_containingoneof(f) || - f->file->syntax == UPB_SYNTAX_PROTO2; -} - -static bool between(int32_t x, int32_t low, int32_t high) { - return x >= low && x <= high; -} - -bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); } -bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); } -bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } - -bool upb_fielddef_checkdescriptortype(int32_t type) { - return between(type, 1, 18); -} - -/* upb_msgdef *****************************************************************/ - -const char *upb_msgdef_fullname(const upb_msgdef *m) { - return m->full_name; -} - -const upb_filedef *upb_msgdef_file(const upb_msgdef *m) { - return m->file; -} - -const char *upb_msgdef_name(const upb_msgdef *m) { - return shortdefname(m->full_name); -} - -upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) { - return m->file->syntax; -} - -size_t upb_msgdef_selectorcount(const upb_msgdef *m) { - return m->selector_count; -} - -uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m) { - return m->submsg_field_count; -} - -const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { - upb_value val; - return upb_inttable_lookup32(&m->itof, i, &val) ? - upb_value_getconstptr(val) : NULL; -} - -const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, - size_t len) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } - - return unpack_def(val, UPB_DEFTYPE_FIELD); -} - -const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, - size_t len) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } - - return unpack_def(val, UPB_DEFTYPE_ONEOF); -} - -bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, - const upb_fielddef **f, const upb_oneofdef **o) { - upb_value val; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return false; - } - - *o = unpack_def(val, UPB_DEFTYPE_ONEOF); - *f = unpack_def(val, UPB_DEFTYPE_FIELD); - return *o || *f; /* False if this was a JSON name. */ -} - -const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m, - const char *name, size_t len) { - upb_value val; - const upb_fielddef* f; - - if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { - return NULL; - } - - f = unpack_def(val, UPB_DEFTYPE_FIELD); - if (!f) f = unpack_def(val, UPB_DEFTYPE_FIELD_JSONNAME); - - return f; -} - -int upb_msgdef_numfields(const upb_msgdef *m) { - return m->field_count; -} - -int upb_msgdef_numoneofs(const upb_msgdef *m) { - return m->oneof_count; -} - -int upb_msgdef_numrealoneofs(const upb_msgdef *m) { - return m->real_oneof_count; -} - -const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m) { - return m->layout; -} - -const upb_fielddef *_upb_msgdef_field(const upb_msgdef *m, int i) { - if (i >= m->field_count) return NULL; - return &m->fields[i]; -} - -bool upb_msgdef_mapentry(const upb_msgdef *m) { - return m->map_entry; -} - -upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m) { - return m->well_known_type; -} - -bool upb_msgdef_isnumberwrapper(const upb_msgdef *m) { - upb_wellknowntype_t type = upb_msgdef_wellknowntype(m); - return type >= UPB_WELLKNOWN_DOUBLEVALUE && - type <= UPB_WELLKNOWN_UINT32VALUE; -} - -void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) { - upb_inttable_begin(iter, &m->itof); -} - -void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); } - -bool upb_msg_field_done(const upb_msg_field_iter *iter) { - return upb_inttable_done(iter); -} - -upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) { - return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter)); -} - -void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) { - upb_inttable_iter_setdone(iter); -} - -bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1, - const upb_msg_field_iter * iter2) { - return upb_inttable_iter_isequal(iter1, iter2); -} - -void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) { - upb_strtable_begin(iter, &m->ntof); - /* We need to skip past any initial fields. */ - while (!upb_strtable_done(iter) && - !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF)) { - upb_strtable_next(iter); - } -} - -void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { - /* We need to skip past fields to return only oneofs. */ - do { - upb_strtable_next(iter); - } while (!upb_strtable_done(iter) && - !unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF)); -} - -bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) { - return upb_strtable_done(iter); -} - -const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) { - return unpack_def(upb_strtable_iter_value(iter), UPB_DEFTYPE_ONEOF); -} - -void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) { - upb_strtable_iter_setdone(iter); -} - -bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1, - const upb_msg_oneof_iter *iter2) { - return upb_strtable_iter_isequal(iter1, iter2); -} - -/* upb_oneofdef ***************************************************************/ - -const char *upb_oneofdef_name(const upb_oneofdef *o) { - return shortdefname(o->full_name); -} - -const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) { - return o->parent; -} - -int upb_oneofdef_numfields(const upb_oneofdef *o) { - return (int)upb_strtable_count(&o->ntof); -} - -uint32_t upb_oneofdef_index(const upb_oneofdef *o) { - return o->index; -} - -bool upb_oneofdef_issynthetic(const upb_oneofdef *o) { - upb_inttable_iter iter; - const upb_fielddef *f; - upb_inttable_begin(&iter, &o->itof); - if (upb_oneofdef_numfields(o) != 1) return false; - f = upb_value_getptr(upb_inttable_iter_value(&iter)); - UPB_ASSERT(f); - return f->proto3_optional_; -} - -const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, - const char *name, size_t length) { - upb_value val; - return upb_strtable_lookup2(&o->ntof, name, length, &val) ? - upb_value_getptr(val) : NULL; -} - -const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) { - upb_value val; - return upb_inttable_lookup32(&o->itof, num, &val) ? - upb_value_getptr(val) : NULL; -} - -void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) { - upb_inttable_begin(iter, &o->itof); -} - -void upb_oneof_next(upb_oneof_iter *iter) { - upb_inttable_next(iter); -} - -bool upb_oneof_done(upb_oneof_iter *iter) { - return upb_inttable_done(iter); -} - -upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) { - return (upb_fielddef *)upb_value_getconstptr(upb_inttable_iter_value(iter)); -} - -void upb_oneof_iter_setdone(upb_oneof_iter *iter) { - upb_inttable_iter_setdone(iter); -} - -/* Dynamic Layout Generation. *************************************************/ - -static size_t div_round_up(size_t n, size_t d) { - return (n + d - 1) / d; -} - -static size_t upb_msgval_sizeof(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_DOUBLE: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - return 8; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_FLOAT: - return 4; - case UPB_TYPE_BOOL: - return 1; - case UPB_TYPE_MESSAGE: - return sizeof(void*); - case UPB_TYPE_BYTES: - case UPB_TYPE_STRING: - return sizeof(upb_strview); - } - UPB_UNREACHABLE(); -} - -static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { - if (upb_msgdef_mapentry(upb_fielddef_containingtype(f))) { - upb_map_entry ent; - UPB_ASSERT(sizeof(ent.k) == sizeof(ent.v)); - return sizeof(ent.k); - } else if (upb_fielddef_isseq(f)) { - return sizeof(void*); - } else { - return upb_msgval_sizeof(upb_fielddef_type(f)); - } -} - -static uint32_t upb_msglayout_place(upb_msglayout *l, size_t size) { - uint32_t ret; - - l->size = UPB_ALIGN_UP(l->size, size); - ret = l->size; - l->size += size; - return ret; -} - -/* This function is the dynamic equivalent of message_layout.{cc,h} in upbc. - * It computes a dynamic layout for all of the fields in |m|. */ -static bool make_layout(const upb_symtab *symtab, const upb_msgdef *m) { - upb_msglayout *l = (upb_msglayout*)m->layout; - upb_msg_field_iter it; - upb_msg_oneof_iter oit; - size_t hasbit; - size_t submsg_count = m->submsg_field_count; - const upb_msglayout **submsgs; - upb_msglayout_field *fields; - upb_alloc *alloc = upb_arena_alloc(symtab->arena); - - memset(l, 0, sizeof(*l)); - - fields = upb_malloc(alloc, upb_msgdef_numfields(m) * sizeof(*fields)); - submsgs = upb_malloc(alloc, submsg_count * sizeof(*submsgs)); - - if ((!fields && upb_msgdef_numfields(m)) || - (!submsgs && submsg_count)) { - /* OOM. */ - return false; - } - - l->field_count = upb_msgdef_numfields(m); - l->fields = fields; - l->submsgs = submsgs; - - if (upb_msgdef_mapentry(m)) { - /* TODO(haberman): refactor this method so this special case is more - * elegant. */ - const upb_fielddef *key = upb_msgdef_itof(m, 1); - const upb_fielddef *val = upb_msgdef_itof(m, 2); - fields[0].number = 1; - fields[1].number = 2; - fields[0].label = UPB_LABEL_OPTIONAL; - fields[1].label = UPB_LABEL_OPTIONAL; - fields[0].presence = 0; - fields[1].presence = 0; - fields[0].descriptortype = upb_fielddef_descriptortype(key); - fields[1].descriptortype = upb_fielddef_descriptortype(val); - fields[0].offset = 0; - fields[1].offset = sizeof(upb_strview); - fields[1].submsg_index = 0; - - if (upb_fielddef_type(val) == UPB_TYPE_MESSAGE) { - submsgs[0] = upb_fielddef_msgsubdef(val)->layout; - } - - l->field_count = 2; - l->size = 2 * sizeof(upb_strview); - l->size = UPB_ALIGN_UP(l->size, 8); - return true; - } - - /* Allocate data offsets in three stages: - * - * 1. hasbits. - * 2. regular fields. - * 3. oneof fields. - * - * OPT: There is a lot of room for optimization here to minimize the size. - */ - - /* Allocate hasbits and set basic field attributes. */ - submsg_count = 0; - for (upb_msg_field_begin(&it, m), hasbit = 0; - !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - upb_fielddef* f = upb_msg_iter_field(&it); - upb_msglayout_field *field = &fields[upb_fielddef_index(f)]; - - field->number = upb_fielddef_number(f); - field->descriptortype = upb_fielddef_descriptortype(f); - field->label = upb_fielddef_label(f); - - if (upb_fielddef_ismap(f)) { - field->label = _UPB_LABEL_MAP; - } else if (upb_fielddef_packed(f)) { - field->label = _UPB_LABEL_PACKED; - } - - /* TODO: we probably should sort the fields by field number to match the - * output of upbc, and to improve search speed for the table parser. */ - f->layout_index = f->index_; - - if (upb_fielddef_issubmsg(f)) { - const upb_msgdef *subm = upb_fielddef_msgsubdef(f); - field->submsg_index = submsg_count++; - submsgs[field->submsg_index] = subm->layout; - } - - if (upb_fielddef_haspresence(f) && !upb_fielddef_realcontainingoneof(f)) { - /* We don't use hasbit 0, so that 0 can indicate "no presence" in the - * table. This wastes one hasbit, but we don't worry about it for now. */ - field->presence = ++hasbit; - } else { - field->presence = 0; - } - } - - /* Account for space used by hasbits. */ - l->size = div_round_up(hasbit, 8); - - /* Allocate non-oneof fields. */ - for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* f = upb_msg_iter_field(&it); - size_t field_size = upb_msg_fielddefsize(f); - size_t index = upb_fielddef_index(f); - - if (upb_fielddef_realcontainingoneof(f)) { - /* Oneofs are handled separately below. */ - continue; - } - - fields[index].offset = upb_msglayout_place(l, field_size); - } - - /* Allocate oneof fields. Each oneof field consists of a uint32 for the case - * and space for the actual data. */ - for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* o = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ - size_t field_size = 0; - uint32_t case_offset; - uint32_t data_offset; - - if (upb_oneofdef_issynthetic(o)) continue; - - /* Calculate field size: the max of all field sizes. */ - for (upb_oneof_begin(&fit, o); - !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* f = upb_oneof_iter_field(&fit); - field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); - } - - /* Align and allocate case offset. */ - case_offset = upb_msglayout_place(l, case_size); - data_offset = upb_msglayout_place(l, field_size); - - for (upb_oneof_begin(&fit, o); - !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* f = upb_oneof_iter_field(&fit); - fields[upb_fielddef_index(f)].offset = data_offset; - fields[upb_fielddef_index(f)].presence = ~case_offset; - } - } - - /* Size of the entire structure should be a multiple of its greatest - * alignment. TODO: track overall alignment for real? */ - l->size = UPB_ALIGN_UP(l->size, 8); - - return true; -} - -/* Code to build defs from descriptor protos. *********************************/ - -/* There is a question of how much validation to do here. It will be difficult - * to perfectly match the amount of validation performed by proto2. But since - * this code is used to directly build defs from Ruby (for example) we do need - * to validate important constraints like uniqueness of names and numbers. */ - -#define CHK(x) if (!(x)) { return false; } -#define CHK_OOM(x) if (!(x)) { upb_status_setoom(ctx->status); return false; } - -typedef struct { - const upb_symtab *symtab; - upb_filedef *file; /* File we are building. */ - upb_alloc *alloc; /* Allocate defs here. */ - upb_alloc *tmp; /* Alloc for addtab and any other tmp data. */ - upb_strtable *addtab; /* full_name -> packed def ptr for new defs */ - const upb_msglayout **layouts; /* NULL if we should build layouts. */ - upb_status *status; /* Record errors here. */ -} symtab_addctx; - -static char* strviewdup(const symtab_addctx *ctx, upb_strview view) { - return upb_strdup2(view.data, view.size, ctx->alloc); -} - -static bool streql2(const char *a, size_t n, const char *b) { - return n == strlen(b) && memcmp(a, b, n) == 0; -} - -static bool streql_view(upb_strview view, const char *b) { - return streql2(view.data, view.size, b); -} - -static const char *makefullname(const symtab_addctx *ctx, const char *prefix, - upb_strview name) { - if (prefix) { - /* ret = prefix + '.' + name; */ - size_t n = strlen(prefix); - char *ret = upb_malloc(ctx->alloc, n + name.size + 2); - CHK_OOM(ret); - strcpy(ret, prefix); - ret[n] = '.'; - memcpy(&ret[n + 1], name.data, name.size); - ret[n + 1 + name.size] = '\0'; - return ret; - } else { - return strviewdup(ctx, name); - } -} - -size_t getjsonname(const char *name, char *buf, size_t len) { - size_t src, dst = 0; - bool ucase_next = false; - -#define WRITE(byte) \ - ++dst; \ - if (dst < len) buf[dst - 1] = byte; \ - else if (dst == len) buf[dst - 1] = '\0' - - if (!name) { - WRITE('\0'); - return 0; - } - - /* Implement the transformation as described in the spec: - * 1. upper case all letters after an underscore. - * 2. remove all underscores. - */ - for (src = 0; name[src]; src++) { - if (name[src] == '_') { - ucase_next = true; - continue; - } - - if (ucase_next) { - WRITE(toupper(name[src])); - ucase_next = false; - } else { - WRITE(name[src]); - } - } - - WRITE('\0'); - return dst; - -#undef WRITE -} - -static char* makejsonname(const char* name, upb_alloc *alloc) { - size_t size = getjsonname(name, NULL, 0); - char* json_name = upb_malloc(alloc, size); - getjsonname(name, json_name, size); - return json_name; -} - -static bool symtab_add(const symtab_addctx *ctx, const char *name, - upb_value v) { - upb_value tmp; - if (upb_strtable_lookup(ctx->addtab, name, &tmp) || - upb_strtable_lookup(&ctx->symtab->syms, name, &tmp)) { - upb_status_seterrf(ctx->status, "duplicate symbol '%s'", name); - return false; - } - - CHK_OOM(upb_strtable_insert3(ctx->addtab, name, strlen(name), v, ctx->tmp)); - return true; -} - -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static bool resolvename(const upb_strtable *t, const upb_fielddef *f, - const char *base, upb_strview sym, - upb_deftype_t type, upb_status *status, - const void **def) { - if(sym.size == 0) return NULL; - if(sym.data[0] == '.') { - /* Symbols starting with '.' are absolute, so we do a single lookup. - * Slice to omit the leading '.' */ - upb_value v; - if (!upb_strtable_lookup2(t, sym.data + 1, sym.size - 1, &v)) { - return false; - } - - *def = unpack_def(v, type); - - if (!*def) { - upb_status_seterrf(status, - "type mismatch when resolving field %s, name %s", - f->full_name, sym.data); - return false; - } - - return true; - } else { - /* Remove components from base until we find an entry or run out. - * TODO: This branch is totally broken, but currently not used. */ - (void)base; - UPB_ASSERT(false); - return false; - } -} - -const void *symtab_resolve(const symtab_addctx *ctx, const upb_fielddef *f, - const char *base, upb_strview sym, - upb_deftype_t type) { - const void *ret; - if (!resolvename(ctx->addtab, f, base, sym, type, ctx->status, &ret) && - !resolvename(&ctx->symtab->syms, f, base, sym, type, ctx->status, &ret)) { - if (upb_ok(ctx->status)) { - upb_status_seterrf(ctx->status, "couldn't resolve name '%s'", sym.data); - } - return false; - } - return ret; -} - -static bool create_oneofdef( - const symtab_addctx *ctx, upb_msgdef *m, - const google_protobuf_OneofDescriptorProto *oneof_proto) { - upb_oneofdef *o; - upb_strview name = google_protobuf_OneofDescriptorProto_name(oneof_proto); - upb_value v; - - o = (upb_oneofdef*)&m->oneofs[m->oneof_count++]; - o->parent = m; - o->full_name = makefullname(ctx, m->full_name, name); - - v = pack_def(o, UPB_DEFTYPE_ONEOF); - CHK_OOM(symtab_add(ctx, o->full_name, v)); - CHK_OOM(upb_strtable_insert3(&m->ntof, name.data, name.size, v, ctx->alloc)); - - CHK_OOM(upb_inttable_init2(&o->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - CHK_OOM(upb_strtable_init2(&o->ntof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - - return true; -} - -static bool parse_default(const symtab_addctx *ctx, const char *str, size_t len, - upb_fielddef *f) { - char *end; - char nullz[64]; - errno = 0; - - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - case UPB_TYPE_DOUBLE: - case UPB_TYPE_FLOAT: - /* Standard C number parsing functions expect null-terminated strings. */ - if (len >= sizeof(nullz) - 1) { - return false; - } - memcpy(nullz, str, len); - nullz[len] = '\0'; - str = nullz; - break; - default: - break; - } - - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: { - long val = strtol(str, &end, 0); - CHK(val <= INT32_MAX && val >= INT32_MIN && errno != ERANGE && !*end); - f->defaultval.sint = val; - break; - } - case UPB_TYPE_ENUM: { - const upb_enumdef *e = f->sub.enumdef; - int32_t val; - CHK(upb_enumdef_ntoi(e, str, len, &val)); - f->defaultval.sint = val; - break; - } - case UPB_TYPE_INT64: { - /* XXX: Need to write our own strtoll, since it's not available in c89. */ - int64_t val = strtol(str, &end, 0); - CHK(val <= INT64_MAX && val >= INT64_MIN && errno != ERANGE && !*end); - f->defaultval.sint = val; - break; - } - case UPB_TYPE_UINT32: { - unsigned long val = strtoul(str, &end, 0); - CHK(val <= UINT32_MAX && errno != ERANGE && !*end); - f->defaultval.uint = val; - break; - } - case UPB_TYPE_UINT64: { - /* XXX: Need to write our own strtoull, since it's not available in c89. */ - uint64_t val = strtoul(str, &end, 0); - CHK(val <= UINT64_MAX && errno != ERANGE && !*end); - f->defaultval.uint = val; - break; - } - case UPB_TYPE_DOUBLE: { - double val = strtod(str, &end); - CHK(errno != ERANGE && !*end); - f->defaultval.dbl = val; - break; - } - case UPB_TYPE_FLOAT: { - /* XXX: Need to write our own strtof, since it's not available in c89. */ - float val = strtod(str, &end); - CHK(errno != ERANGE && !*end); - f->defaultval.flt = val; - break; - } - case UPB_TYPE_BOOL: { - if (streql2(str, len, "false")) { - f->defaultval.boolean = false; - } else if (streql2(str, len, "true")) { - f->defaultval.boolean = true; - } else { - return false; - } - break; - } - case UPB_TYPE_STRING: - f->defaultval.str = newstr(ctx->alloc, str, len); - break; - case UPB_TYPE_BYTES: - /* XXX: need to interpret the C-escaped value. */ - f->defaultval.str = newstr(ctx->alloc, str, len); - break; - case UPB_TYPE_MESSAGE: - /* Should not have a default value. */ - return false; - } - return true; -} - -static void set_default_default(const symtab_addctx *ctx, upb_fielddef *f) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_ENUM: - f->defaultval.sint = 0; - break; - case UPB_TYPE_UINT64: - case UPB_TYPE_UINT32: - f->defaultval.uint = 0; - break; - case UPB_TYPE_DOUBLE: - case UPB_TYPE_FLOAT: - f->defaultval.dbl = 0; - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - f->defaultval.str = newstr(ctx->alloc, NULL, 0); - break; - case UPB_TYPE_BOOL: - f->defaultval.boolean = false; - break; - case UPB_TYPE_MESSAGE: - break; - } -} - -static bool create_fielddef( - const symtab_addctx *ctx, const char *prefix, upb_msgdef *m, - const google_protobuf_FieldDescriptorProto *field_proto) { - upb_alloc *alloc = ctx->alloc; - upb_fielddef *f; - const google_protobuf_FieldOptions *options; - upb_strview name; - const char *full_name; - const char *json_name; - const char *shortname; - uint32_t field_number; - - if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { - upb_status_seterrmsg(ctx->status, "field has no name"); - return false; - } - - name = google_protobuf_FieldDescriptorProto_name(field_proto); - CHK(upb_isident(name, false, ctx->status)); - full_name = makefullname(ctx, prefix, name); - shortname = shortdefname(full_name); - - if (google_protobuf_FieldDescriptorProto_has_json_name(field_proto)) { - json_name = strviewdup( - ctx, google_protobuf_FieldDescriptorProto_json_name(field_proto)); - } else { - json_name = makejsonname(shortname, ctx->alloc); - } - - field_number = google_protobuf_FieldDescriptorProto_number(field_proto); - - if (field_number == 0 || field_number > UPB_MAX_FIELDNUMBER) { - upb_status_seterrf(ctx->status, "invalid field number (%u)", field_number); - return false; - } - - if (m) { - /* direct message field. */ - upb_value v, field_v, json_v; - size_t json_size; - - f = (upb_fielddef*)&m->fields[m->field_count++]; - f->msgdef = m; - f->is_extension_ = false; - - if (upb_strtable_lookup(&m->ntof, shortname, NULL)) { - upb_status_seterrf(ctx->status, "duplicate field name (%s)", shortname); - return false; - } - - if (upb_strtable_lookup(&m->ntof, json_name, NULL)) { - upb_status_seterrf(ctx->status, "duplicate json_name (%s)", json_name); - return false; - } - - if (upb_inttable_lookup(&m->itof, field_number, NULL)) { - upb_status_seterrf(ctx->status, "duplicate field number (%u)", - field_number); - return false; - } - - field_v = pack_def(f, UPB_DEFTYPE_FIELD); - json_v = pack_def(f, UPB_DEFTYPE_FIELD_JSONNAME); - v = upb_value_constptr(f); - json_size = strlen(json_name); - - CHK_OOM( - upb_strtable_insert3(&m->ntof, name.data, name.size, field_v, alloc)); - CHK_OOM(upb_inttable_insert2(&m->itof, field_number, v, alloc)); - - if (strcmp(shortname, json_name) != 0) { - upb_strtable_insert3(&m->ntof, json_name, json_size, json_v, alloc); - } - - if (ctx->layouts) { - const upb_msglayout_field *fields = m->layout->fields; - int count = m->layout->field_count; - bool found = false; - int i; - for (i = 0; i < count; i++) { - if (fields[i].number == field_number) { - f->layout_index = i; - found = true; - break; - } - } - UPB_ASSERT(found); - } - } else { - /* extension field. */ - f = (upb_fielddef*)&ctx->file->exts[ctx->file->ext_count++]; - f->is_extension_ = true; - CHK_OOM(symtab_add(ctx, full_name, pack_def(f, UPB_DEFTYPE_FIELD))); - } - - f->full_name = full_name; - f->json_name = json_name; - f->file = ctx->file; - f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); - f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); - f->number_ = field_number; - f->oneof = NULL; - f->proto3_optional_ = - google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); - - /* We can't resolve the subdef or (in the case of extensions) the containing - * message yet, because it may not have been defined yet. We stash a pointer - * to the field_proto until later when we can properly resolve it. */ - f->sub.unresolved = field_proto; - - if (f->label_ == UPB_LABEL_REQUIRED && f->file->syntax == UPB_SYNTAX_PROTO3) { - upb_status_seterrf(ctx->status, "proto3 fields cannot be required (%s)", - f->full_name); - return false; - } - - if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { - int oneof_index = - google_protobuf_FieldDescriptorProto_oneof_index(field_proto); - upb_oneofdef *oneof; - upb_value v = upb_value_constptr(f); - - if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) { - upb_status_seterrf(ctx->status, - "fields in oneof must have OPTIONAL label (%s)", - f->full_name); - return false; - } - - if (!m) { - upb_status_seterrf(ctx->status, - "oneof_index provided for extension field (%s)", - f->full_name); - return false; - } - - if (oneof_index >= m->oneof_count) { - upb_status_seterrf(ctx->status, "oneof_index out of range (%s)", - f->full_name); - return false; - } - - oneof = (upb_oneofdef*)&m->oneofs[oneof_index]; - f->oneof = oneof; - - CHK(upb_inttable_insert2(&oneof->itof, f->number_, v, alloc)); - CHK(upb_strtable_insert3(&oneof->ntof, name.data, name.size, v, alloc)); - } else { - f->oneof = NULL; - } - - if (google_protobuf_FieldDescriptorProto_has_options(field_proto)) { - options = google_protobuf_FieldDescriptorProto_options(field_proto); - f->lazy_ = google_protobuf_FieldOptions_lazy(options); - f->packed_ = google_protobuf_FieldOptions_packed(options); - } else { - f->lazy_ = false; - f->packed_ = false; - } - - return true; -} - -static bool create_enumdef( - const symtab_addctx *ctx, const char *prefix, - const google_protobuf_EnumDescriptorProto *enum_proto) { - upb_enumdef *e; - const google_protobuf_EnumValueDescriptorProto *const *values; - upb_strview name; - size_t i, n; - - name = google_protobuf_EnumDescriptorProto_name(enum_proto); - CHK(upb_isident(name, false, ctx->status)); - - e = (upb_enumdef*)&ctx->file->enums[ctx->file->enum_count++]; - e->full_name = makefullname(ctx, prefix, name); - CHK_OOM(symtab_add(ctx, e->full_name, pack_def(e, UPB_DEFTYPE_ENUM))); - - CHK_OOM(upb_strtable_init2(&e->ntoi, UPB_CTYPE_INT32, ctx->alloc)); - CHK_OOM(upb_inttable_init2(&e->iton, UPB_CTYPE_CSTR, ctx->alloc)); - - e->file = ctx->file; - e->defaultval = 0; - - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); - - if (n == 0) { - upb_status_seterrf(ctx->status, - "enums must contain at least one value (%s)", - e->full_name); - return false; - } - - for (i = 0; i < n; i++) { - const google_protobuf_EnumValueDescriptorProto *value = values[i]; - upb_strview name = google_protobuf_EnumValueDescriptorProto_name(value); - char *name2 = strviewdup(ctx, name); - int32_t num = google_protobuf_EnumValueDescriptorProto_number(value); - upb_value v = upb_value_int32(num); - - if (i == 0 && e->file->syntax == UPB_SYNTAX_PROTO3 && num != 0) { - upb_status_seterrf(ctx->status, - "for proto3, the first enum value must be zero (%s)", - e->full_name); - return false; - } - - if (upb_strtable_lookup(&e->ntoi, name2, NULL)) { - upb_status_seterrf(ctx->status, "duplicate enum label '%s'", name2); - return false; - } - - CHK_OOM(name2) - CHK_OOM( - upb_strtable_insert3(&e->ntoi, name2, strlen(name2), v, ctx->alloc)); - - if (!upb_inttable_lookup(&e->iton, num, NULL)) { - upb_value v = upb_value_cstr(name2); - CHK_OOM(upb_inttable_insert2(&e->iton, num, v, ctx->alloc)); - } - } - - upb_inttable_compact2(&e->iton, ctx->alloc); - - return true; -} - -static bool create_msgdef(symtab_addctx *ctx, const char *prefix, - const google_protobuf_DescriptorProto *msg_proto) { - upb_msgdef *m; - const google_protobuf_MessageOptions *options; - const google_protobuf_OneofDescriptorProto *const *oneofs; - const google_protobuf_FieldDescriptorProto *const *fields; - const google_protobuf_EnumDescriptorProto *const *enums; - const google_protobuf_DescriptorProto *const *msgs; - size_t i, n; - upb_strview name; - - name = google_protobuf_DescriptorProto_name(msg_proto); - CHK(upb_isident(name, false, ctx->status)); - - m = (upb_msgdef*)&ctx->file->msgs[ctx->file->msg_count++]; - m->full_name = makefullname(ctx, prefix, name); - CHK_OOM(symtab_add(ctx, m->full_name, pack_def(m, UPB_DEFTYPE_MSG))); - - CHK_OOM(upb_inttable_init2(&m->itof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - CHK_OOM(upb_strtable_init2(&m->ntof, UPB_CTYPE_CONSTPTR, ctx->alloc)); - - m->file = ctx->file; - m->map_entry = false; - - options = google_protobuf_DescriptorProto_options(msg_proto); - - if (options) { - m->map_entry = google_protobuf_MessageOptions_map_entry(options); - } - - if (ctx->layouts) { - m->layout = *ctx->layouts; - ctx->layouts++; - } else { - /* Allocate now (to allow cross-linking), populate later. */ - m->layout = upb_malloc(ctx->alloc, sizeof(*m->layout)); - } - - oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n); - m->oneof_count = 0; - m->oneofs = upb_malloc(ctx->alloc, sizeof(*m->oneofs) * n); - for (i = 0; i < n; i++) { - CHK(create_oneofdef(ctx, m, oneofs[i])); - } - - fields = google_protobuf_DescriptorProto_field(msg_proto, &n); - m->field_count = 0; - m->fields = upb_malloc(ctx->alloc, sizeof(*m->fields) * n); - for (i = 0; i < n; i++) { - CHK(create_fielddef(ctx, m->full_name, m, fields[i])); - } - - CHK(assign_msg_indices(m, ctx->status)); - CHK(check_oneofs(m, ctx->status)); - assign_msg_wellknowntype(m); - upb_inttable_compact2(&m->itof, ctx->alloc); - - /* This message is built. Now build nested messages and enums. */ - - enums = google_protobuf_DescriptorProto_enum_type(msg_proto, &n); - for (i = 0; i < n; i++) { - CHK(create_enumdef(ctx, m->full_name, enums[i])); - } - - msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - for (i = 0; i < n; i++) { - CHK(create_msgdef(ctx, m->full_name, msgs[i])); - } - - return true; -} - -typedef struct { - int msg_count; - int enum_count; - int ext_count; -} decl_counts; - -static void count_types_in_msg(const google_protobuf_DescriptorProto *msg_proto, - decl_counts *counts) { - const google_protobuf_DescriptorProto *const *msgs; - size_t i, n; - - counts->msg_count++; - - msgs = google_protobuf_DescriptorProto_nested_type(msg_proto, &n); - for (i = 0; i < n; i++) { - count_types_in_msg(msgs[i], counts); - } - - google_protobuf_DescriptorProto_enum_type(msg_proto, &n); - counts->enum_count += n; - - google_protobuf_DescriptorProto_extension(msg_proto, &n); - counts->ext_count += n; -} - -static void count_types_in_file( - const google_protobuf_FileDescriptorProto *file_proto, - decl_counts *counts) { - const google_protobuf_DescriptorProto *const *msgs; - size_t i, n; - - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - for (i = 0; i < n; i++) { - count_types_in_msg(msgs[i], counts); - } - - google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - counts->enum_count += n; - - google_protobuf_FileDescriptorProto_extension(file_proto, &n); - counts->ext_count += n; -} - -static bool resolve_fielddef(const symtab_addctx *ctx, const char *prefix, - upb_fielddef *f) { - upb_strview name; - const google_protobuf_FieldDescriptorProto *field_proto = f->sub.unresolved; - - if (f->is_extension_) { - if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { - upb_status_seterrf(ctx->status, - "extension for field '%s' had no extendee", - f->full_name); - return false; - } - - name = google_protobuf_FieldDescriptorProto_extendee(field_proto); - f->msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG); - CHK(f->msgdef); - } - - if ((upb_fielddef_issubmsg(f) || f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) && - !google_protobuf_FieldDescriptorProto_has_type_name(field_proto)) { - upb_status_seterrf(ctx->status, "field '%s' is missing type name", - f->full_name); - return false; - } - - name = google_protobuf_FieldDescriptorProto_type_name(field_proto); - - if (upb_fielddef_issubmsg(f)) { - f->sub.msgdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_MSG); - CHK(f->sub.msgdef); - } else if (f->type_ == UPB_DESCRIPTOR_TYPE_ENUM) { - f->sub.enumdef = symtab_resolve(ctx, f, prefix, name, UPB_DEFTYPE_ENUM); - CHK(f->sub.enumdef); - } - - /* Have to delay resolving of the default value until now because of the enum - * case, since enum defaults are specified with a label. */ - if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { - upb_strview defaultval = - google_protobuf_FieldDescriptorProto_default_value(field_proto); - - if (f->file->syntax == UPB_SYNTAX_PROTO3) { - upb_status_seterrf(ctx->status, - "proto3 fields cannot have explicit defaults (%s)", - f->full_name); - return false; - } - - if (upb_fielddef_issubmsg(f)) { - upb_status_seterrf(ctx->status, - "message fields cannot have explicit defaults (%s)", - f->full_name); - return false; - } - - if (!parse_default(ctx, defaultval.data, defaultval.size, f)) { - upb_status_seterrf(ctx->status, - "couldn't parse default '" UPB_STRVIEW_FORMAT - "' for field (%s)", - UPB_STRVIEW_ARGS(defaultval), f->full_name); - return false; - } - } else { - set_default_default(ctx, f); - } - - return true; -} - -static bool build_filedef( - symtab_addctx *ctx, upb_filedef *file, - const google_protobuf_FileDescriptorProto *file_proto) { - upb_alloc *alloc = ctx->alloc; - const google_protobuf_FileOptions *file_options_proto; - const google_protobuf_DescriptorProto *const *msgs; - const google_protobuf_EnumDescriptorProto *const *enums; - const google_protobuf_FieldDescriptorProto *const *exts; - const upb_strview* strs; - size_t i, n; - decl_counts counts = {0}; - - count_types_in_file(file_proto, &counts); - - file->msgs = upb_malloc(alloc, sizeof(*file->msgs) * counts.msg_count); - file->enums = upb_malloc(alloc, sizeof(*file->enums) * counts.enum_count); - file->exts = upb_malloc(alloc, sizeof(*file->exts) * counts.ext_count); - - CHK_OOM(counts.msg_count == 0 || file->msgs); - CHK_OOM(counts.enum_count == 0 || file->enums); - CHK_OOM(counts.ext_count == 0 || file->exts); - - /* We increment these as defs are added. */ - file->msg_count = 0; - file->enum_count = 0; - file->ext_count = 0; - - if (!google_protobuf_FileDescriptorProto_has_name(file_proto)) { - upb_status_seterrmsg(ctx->status, "File has no name"); - return false; - } - - file->name = - strviewdup(ctx, google_protobuf_FileDescriptorProto_name(file_proto)); - file->phpprefix = NULL; - file->phpnamespace = NULL; - - if (google_protobuf_FileDescriptorProto_has_package(file_proto)) { - upb_strview package = - google_protobuf_FileDescriptorProto_package(file_proto); - CHK(upb_isident(package, true, ctx->status)); - file->package = strviewdup(ctx, package); - } else { - file->package = NULL; - } - - if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { - upb_strview syntax = - google_protobuf_FileDescriptorProto_syntax(file_proto); - - if (streql_view(syntax, "proto2")) { - file->syntax = UPB_SYNTAX_PROTO2; - } else if (streql_view(syntax, "proto3")) { - file->syntax = UPB_SYNTAX_PROTO3; - } else { - upb_status_seterrf(ctx->status, "Invalid syntax '" UPB_STRVIEW_FORMAT "'", - UPB_STRVIEW_ARGS(syntax)); - return false; - } - } else { - file->syntax = UPB_SYNTAX_PROTO2; - } - - /* Read options. */ - file_options_proto = google_protobuf_FileDescriptorProto_options(file_proto); - if (file_options_proto) { - if (google_protobuf_FileOptions_has_php_class_prefix(file_options_proto)) { - file->phpprefix = strviewdup( - ctx, - google_protobuf_FileOptions_php_class_prefix(file_options_proto)); - } - if (google_protobuf_FileOptions_has_php_namespace(file_options_proto)) { - file->phpnamespace = strviewdup( - ctx, google_protobuf_FileOptions_php_namespace(file_options_proto)); - } - } - - /* Verify dependencies. */ - strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); - file->deps = upb_malloc(alloc, sizeof(*file->deps) * n) ; - CHK_OOM(n == 0 || file->deps); - - for (i = 0; i < n; i++) { - upb_strview dep_name = strs[i]; - upb_value v; - if (!upb_strtable_lookup2(&ctx->symtab->files, dep_name.data, - dep_name.size, &v)) { - upb_status_seterrf(ctx->status, - "Depends on file '" UPB_STRVIEW_FORMAT - "', but it has not been loaded", - UPB_STRVIEW_ARGS(dep_name)); - return false; - } - file->deps[i] = upb_value_getconstptr(v); - } - - /* Create messages. */ - msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); - for (i = 0; i < n; i++) { - CHK(create_msgdef(ctx, file->package, msgs[i])); - } - - /* Create enums. */ - enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); - for (i = 0; i < n; i++) { - CHK(create_enumdef(ctx, file->package, enums[i])); - } - - /* Create extensions. */ - exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); - file->exts = upb_malloc(alloc, sizeof(*file->exts) * n); - CHK_OOM(n == 0 || file->exts); - for (i = 0; i < n; i++) { - CHK(create_fielddef(ctx, file->package, NULL, exts[i])); - } - - /* Now that all names are in the table, build layouts and resolve refs. */ - for (i = 0; i < file->ext_count; i++) { - CHK(resolve_fielddef(ctx, file->package, (upb_fielddef*)&file->exts[i])); - } - - for (i = 0; i < file->msg_count; i++) { - const upb_msgdef *m = &file->msgs[i]; - int j; - for (j = 0; j < m->field_count; j++) { - CHK(resolve_fielddef(ctx, m->full_name, (upb_fielddef*)&m->fields[j])); - } - } - - if (!ctx->layouts) { - for (i = 0; i < file->msg_count; i++) { - const upb_msgdef *m = &file->msgs[i]; - make_layout(ctx->symtab, m); - } - } - - return true; - } - -static bool upb_symtab_addtotabs(upb_symtab *s, symtab_addctx *ctx, - upb_status *status) { - const upb_filedef *file = ctx->file; - upb_alloc *alloc = upb_arena_alloc(s->arena); - upb_strtable_iter iter; - - CHK_OOM(upb_strtable_insert3(&s->files, file->name, strlen(file->name), - upb_value_constptr(file), alloc)); - - upb_strtable_begin(&iter, ctx->addtab); - for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { - upb_strview key = upb_strtable_iter_key(&iter); - upb_value value = upb_strtable_iter_value(&iter); - CHK_OOM(upb_strtable_insert3(&s->syms, key.data, key.size, value, alloc)); - } - - return true; -} - -/* upb_filedef ****************************************************************/ - -const char *upb_filedef_name(const upb_filedef *f) { - return f->name; -} - -const char *upb_filedef_package(const upb_filedef *f) { - return f->package; -} - -const char *upb_filedef_phpprefix(const upb_filedef *f) { - return f->phpprefix; -} - -const char *upb_filedef_phpnamespace(const upb_filedef *f) { - return f->phpnamespace; -} - -upb_syntax_t upb_filedef_syntax(const upb_filedef *f) { - return f->syntax; -} - -int upb_filedef_msgcount(const upb_filedef *f) { - return f->msg_count; -} - -int upb_filedef_depcount(const upb_filedef *f) { - return f->dep_count; -} - -int upb_filedef_enumcount(const upb_filedef *f) { - return f->enum_count; -} - -const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i) { - return i < 0 || i >= f->dep_count ? NULL : f->deps[i]; -} - -const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i) { - return i < 0 || i >= f->msg_count ? NULL : &f->msgs[i]; -} - -const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i) { - return i < 0 || i >= f->enum_count ? NULL : &f->enums[i]; -} - -void upb_symtab_free(upb_symtab *s) { - upb_arena_free(s->arena); - upb_gfree(s); -} - -upb_symtab *upb_symtab_new(void) { - upb_symtab *s = upb_gmalloc(sizeof(*s)); - upb_alloc *alloc; - - if (!s) { - return NULL; - } - - s->arena = upb_arena_new(); - alloc = upb_arena_alloc(s->arena); - - if (!upb_strtable_init2(&s->syms, UPB_CTYPE_CONSTPTR, alloc) || - !upb_strtable_init2(&s->files, UPB_CTYPE_CONSTPTR, alloc)) { - upb_arena_free(s->arena); - upb_gfree(s); - s = NULL; - } - return s; -} - -const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) { - upb_value v; - return upb_strtable_lookup(&s->syms, sym, &v) ? - unpack_def(v, UPB_DEFTYPE_MSG) : NULL; -} - -const upb_msgdef *upb_symtab_lookupmsg2(const upb_symtab *s, const char *sym, - size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->syms, sym, len, &v) ? - unpack_def(v, UPB_DEFTYPE_MSG) : NULL; -} - -const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) { - upb_value v; - return upb_strtable_lookup(&s->syms, sym, &v) ? - unpack_def(v, UPB_DEFTYPE_ENUM) : NULL; -} - -const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) { - upb_value v; - return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) - : NULL; -} - -const upb_filedef *upb_symtab_lookupfile2( - const upb_symtab *s, const char *name, size_t len) { - upb_value v; - return upb_strtable_lookup2(&s->files, name, len, &v) ? - upb_value_getconstptr(v) : NULL; -} - -int upb_symtab_filecount(const upb_symtab *s) { - return (int)upb_strtable_count(&s->files); -} - -static const upb_filedef *_upb_symtab_addfile( - upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, - const upb_msglayout **layouts, upb_status *status) { - upb_arena *tmparena = upb_arena_new(); - upb_strtable addtab; - upb_alloc *alloc = upb_arena_alloc(s->arena); - upb_filedef *file = upb_malloc(alloc, sizeof(*file)); - bool ok; - symtab_addctx ctx; - - ctx.file = file; - ctx.symtab = s; - ctx.alloc = alloc; - ctx.tmp = upb_arena_alloc(tmparena); - ctx.addtab = &addtab; - ctx.layouts = layouts; - ctx.status = status; - - ok = file && - upb_strtable_init2(&addtab, UPB_CTYPE_CONSTPTR, ctx.tmp) && - build_filedef(&ctx, file, file_proto) && - upb_symtab_addtotabs(s, &ctx, status); - - upb_arena_free(tmparena); - return ok ? file : NULL; -} - -const upb_filedef *upb_symtab_addfile( - upb_symtab *s, const google_protobuf_FileDescriptorProto *file_proto, - upb_status *status) { - return _upb_symtab_addfile(s, file_proto, NULL, status); -} - -/* Include here since we want most of this file to be stdio-free. */ -#include - -bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init) { - /* Since this function should never fail (it would indicate a bug in upb) we - * print errors to stderr instead of returning error status to the user. */ - upb_def_init **deps = init->deps; - google_protobuf_FileDescriptorProto *file; - upb_arena *arena; - upb_status status; - - upb_status_clear(&status); - - if (upb_strtable_lookup(&s->files, init->filename, NULL)) { - return true; - } - - arena = upb_arena_new(); - - for (; *deps; deps++) { - if (!_upb_symtab_loaddefinit(s, *deps)) goto err; - } - - file = google_protobuf_FileDescriptorProto_parse( - init->descriptor.data, init->descriptor.size, arena); - - if (!file) { - upb_status_seterrf( - &status, - "Failed to parse compiled-in descriptor for file '%s'. This should " - "never happen.", - init->filename); - goto err; - } - - if (!_upb_symtab_addfile(s, file, init->layouts, &status)) goto err; - - upb_arena_free(arena); - return true; - -err: - fprintf(stderr, "Error loading compiled-in descriptor: %s\n", - upb_status_errmsg(&status)); - upb_arena_free(arena); - return false; -} - -#undef CHK -#undef CHK_OOM - - -#include - - -static char field_size[] = { - 0,/* 0 */ - 8, /* UPB_DESCRIPTOR_TYPE_DOUBLE */ - 4, /* UPB_DESCRIPTOR_TYPE_FLOAT */ - 8, /* UPB_DESCRIPTOR_TYPE_INT64 */ - 8, /* UPB_DESCRIPTOR_TYPE_UINT64 */ - 4, /* UPB_DESCRIPTOR_TYPE_INT32 */ - 8, /* UPB_DESCRIPTOR_TYPE_FIXED64 */ - 4, /* UPB_DESCRIPTOR_TYPE_FIXED32 */ - 1, /* UPB_DESCRIPTOR_TYPE_BOOL */ - sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_STRING */ - sizeof(void*), /* UPB_DESCRIPTOR_TYPE_GROUP */ - sizeof(void*), /* UPB_DESCRIPTOR_TYPE_MESSAGE */ - sizeof(upb_strview), /* UPB_DESCRIPTOR_TYPE_BYTES */ - 4, /* UPB_DESCRIPTOR_TYPE_UINT32 */ - 4, /* UPB_DESCRIPTOR_TYPE_ENUM */ - 4, /* UPB_DESCRIPTOR_TYPE_SFIXED32 */ - 8, /* UPB_DESCRIPTOR_TYPE_SFIXED64 */ - 4, /* UPB_DESCRIPTOR_TYPE_SINT32 */ - 8, /* UPB_DESCRIPTOR_TYPE_SINT64 */ -}; - -/* Strings/bytes are special-cased in maps. */ -static char _upb_fieldtype_to_mapsize[12] = { - 0, - 1, /* UPB_TYPE_BOOL */ - 4, /* UPB_TYPE_FLOAT */ - 4, /* UPB_TYPE_INT32 */ - 4, /* UPB_TYPE_UINT32 */ - 4, /* UPB_TYPE_ENUM */ - sizeof(void*), /* UPB_TYPE_MESSAGE */ - 8, /* UPB_TYPE_DOUBLE */ - 8, /* UPB_TYPE_INT64 */ - 8, /* UPB_TYPE_UINT64 */ - 0, /* UPB_TYPE_STRING */ - 0, /* UPB_TYPE_BYTES */ -}; - -/** upb_msg *******************************************************************/ - -upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a) { - return _upb_msg_new(upb_msgdef_layout(m), a); -} - -static bool in_oneof(const upb_msglayout_field *field) { - return field->presence < 0; -} - -static uint32_t *oneofcase(const upb_msg *msg, - const upb_msglayout_field *field) { - UPB_ASSERT(in_oneof(field)); - return UPB_PTR_AT(msg, -field->presence, uint32_t); -} - -static upb_msgval _upb_msg_getraw(const upb_msg *msg, const upb_fielddef *f) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - const char *mem = UPB_PTR_AT(msg, field->offset, char); - upb_msgval val = {0}; - int size = upb_fielddef_isseq(f) ? sizeof(void *) - : field_size[field->descriptortype]; - memcpy(&val, mem, size); - return val; -} - -bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - if (in_oneof(field)) { - return *oneofcase(msg, field) == field->number; - } else if (field->presence > 0) { - uint32_t hasbit = field->presence; - return *UPB_PTR_AT(msg, hasbit / 8, uint8_t) & (1 << (hasbit % 8)); - } else { - UPB_ASSERT(field->descriptortype == UPB_DESCRIPTOR_TYPE_MESSAGE || - field->descriptortype == UPB_DESCRIPTOR_TYPE_GROUP); - return _upb_msg_getraw(msg, f).msg_val != NULL; - } -} - -bool upb_msg_hasoneof(const upb_msg *msg, const upb_oneofdef *o) { - upb_oneof_iter i; - const upb_fielddef *f; - const upb_msglayout_field *field; - - upb_oneof_begin(&i, o); - if (upb_oneof_done(&i)) return false; - f = upb_oneof_iter_field(&i); - field = upb_fielddef_layout(f); - return *oneofcase(msg, field) != 0; -} - -upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f) { - if (!upb_fielddef_haspresence(f) || upb_msg_has(msg, f)) { - return _upb_msg_getraw(msg, f); - } else { - /* TODO(haberman): change upb_fielddef to not require this switch(). */ - upb_msgval val = {0}; - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: - case UPB_TYPE_ENUM: - val.int32_val = upb_fielddef_defaultint32(f); - break; - case UPB_TYPE_INT64: - val.int64_val = upb_fielddef_defaultint64(f); - break; - case UPB_TYPE_UINT32: - val.uint32_val = upb_fielddef_defaultuint32(f); - break; - case UPB_TYPE_UINT64: - val.uint64_val = upb_fielddef_defaultuint64(f); - break; - case UPB_TYPE_FLOAT: - val.float_val = upb_fielddef_defaultfloat(f); - break; - case UPB_TYPE_DOUBLE: - val.double_val = upb_fielddef_defaultdouble(f); - break; - case UPB_TYPE_BOOL: - val.double_val = upb_fielddef_defaultbool(f); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - val.str_val.data = upb_fielddef_defaultstr(f, &val.str_val.size); - break; - case UPB_TYPE_MESSAGE: - val.msg_val = NULL; - break; - } - return val; - } -} - -upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, - upb_arena *a) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - upb_mutmsgval ret; - char *mem = UPB_PTR_AT(msg, field->offset, char); - bool wrong_oneof = in_oneof(field) && *oneofcase(msg, field) != field->number; - - memcpy(&ret, mem, sizeof(void*)); - - if (a && (!ret.msg || wrong_oneof)) { - if (upb_fielddef_ismap(f)) { - const upb_msgdef *entry = upb_fielddef_msgsubdef(f); - const upb_fielddef *key = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); - const upb_fielddef *value = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); - ret.map = upb_map_new(a, upb_fielddef_type(key), upb_fielddef_type(value)); - } else if (upb_fielddef_isseq(f)) { - ret.array = upb_array_new(a, upb_fielddef_type(f)); - } else { - UPB_ASSERT(upb_fielddef_issubmsg(f)); - ret.msg = upb_msg_new(upb_fielddef_msgsubdef(f), a); - } - - memcpy(mem, &ret, sizeof(void*)); - - if (wrong_oneof) { - *oneofcase(msg, field) = field->number; - } - } - return ret; -} - -void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, - upb_arena *a) { - const upb_msglayout_field *field = upb_fielddef_layout(f); - char *mem = UPB_PTR_AT(msg, field->offset, char); - int size = upb_fielddef_isseq(f) ? sizeof(void *) - : field_size[field->descriptortype]; - memcpy(mem, &val, size); - if (in_oneof(field)) { - *oneofcase(msg, field) = field->number; - } -} - -bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, - const upb_symtab *ext_pool, const upb_fielddef **out_f, - upb_msgval *out_val, size_t *iter) { - size_t i = *iter; - const upb_msgval zero = {0}; - const upb_fielddef *f; - while ((f = _upb_msgdef_field(m, (int)++i)) != NULL) { - upb_msgval val = _upb_msg_getraw(msg, f); - - /* Skip field if unset or empty. */ - if (upb_fielddef_haspresence(f)) { - if (!upb_msg_has(msg, f)) continue; - } else { - upb_msgval test = val; - if (upb_fielddef_isstring(f) && !upb_fielddef_isseq(f)) { - /* Clear string pointer, only size matters (ptr could be non-NULL). */ - test.str_val.data = NULL; - } - /* Continue if NULL or 0. */ - if (memcmp(&test, &zero, sizeof(test)) == 0) continue; - - /* Continue on empty array or map. */ - if (upb_fielddef_ismap(f)) { - if (upb_map_size(test.map_val) == 0) continue; - } else if (upb_fielddef_isseq(f)) { - if (upb_array_size(test.array_val) == 0) continue; - } - } - - *out_val = val; - *out_f = f; - *iter = i; - return true; - } - *iter = i; - return false; -} - -/** upb_array *****************************************************************/ - -upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type) { - return _upb_array_new(a, type); -} - -size_t upb_array_size(const upb_array *arr) { - return arr->len; -} - -upb_msgval upb_array_get(const upb_array *arr, size_t i) { - upb_msgval ret; - const char* data = _upb_array_constptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(&ret, data + (i << lg2), 1 << lg2); - return ret; -} - -void upb_array_set(upb_array *arr, size_t i, upb_msgval val) { - char* data = _upb_array_ptr(arr); - int lg2 = arr->data & 7; - UPB_ASSERT(i < arr->len); - memcpy(data + (i << lg2), &val, 1 << lg2); -} - -bool upb_array_append(upb_array *arr, upb_msgval val, upb_arena *arena) { - if (!_upb_array_realloc(arr, arr->len + 1, arena)) { - return false; - } - arr->len++; - upb_array_set(arr, arr->len - 1, val); - return true; -} - -/* Resizes the array to the given size, reallocating if necessary, and returns a - * pointer to the new array elements. */ -bool upb_array_resize(upb_array *arr, size_t size, upb_arena *arena) { - return _upb_array_realloc(arr, size, arena); -} - -/** upb_map *******************************************************************/ - -upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, - upb_fieldtype_t value_type) { - return _upb_map_new(a, _upb_fieldtype_to_mapsize[key_type], - _upb_fieldtype_to_mapsize[value_type]); -} - -size_t upb_map_size(const upb_map *map) { - return _upb_map_size(map); -} - -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val) { - return _upb_map_get(map, &key, map->key_size, val, map->val_size); -} - -bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, - upb_arena *arena) { - return _upb_map_set(map, &key, map->key_size, &val, map->val_size, arena); -} - -bool upb_map_delete(upb_map *map, upb_msgval key) { - return _upb_map_delete(map, &key, map->key_size); -} - -bool upb_mapiter_next(const upb_map *map, size_t *iter) { - return _upb_map_next(map, iter); -} - -/* Returns the key and value for this entry of the map. */ -upb_msgval upb_mapiter_key(const upb_map *map, size_t iter) { - upb_strtable_iter i; - upb_msgval ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); - return ret; -} - -upb_msgval upb_mapiter_value(const upb_map *map, size_t iter) { - upb_strtable_iter i; - upb_msgval ret; - i.t = &map->table; - i.index = iter; - _upb_map_fromvalue(upb_strtable_iter_value(&i), &ret, map->val_size); - return ret; -} - -/* void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); */ -/* -** TODO(haberman): it's unclear whether a lot of the consistency checks should -** UPB_ASSERT() or return false. -*/ - - -#include - - - -struct upb_handlers { - upb_handlercache *cache; - const upb_msgdef *msg; - const upb_handlers **sub; - const void *top_closure_type; - upb_handlers_tabent table[1]; /* Dynamically-sized field handler array. */ -}; - -static void *upb_calloc(upb_arena *arena, size_t size) { - void *mem = upb_malloc(upb_arena_alloc(arena), size); - if (mem) { - memset(mem, 0, size); - } - return mem; -} - -/* Defined for the sole purpose of having a unique pointer value for - * UPB_NO_CLOSURE. */ -char _upb_noclosure; - -/* Given a selector for a STARTSUBMSG handler, resolves to a pointer to the - * subhandlers for this submessage field. */ -#define SUBH(h, selector) (h->sub[selector]) - -/* The selector for a submessage field is the field index. */ -#define SUBH_F(h, f) SUBH(h, upb_fielddef_index(f)) - -static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { - upb_selector_t sel; - bool ok; - - ok = upb_handlers_getselector(f, type, &sel); - - UPB_ASSERT(upb_handlers_msgdef(h) == upb_fielddef_containingtype(f)); - UPB_ASSERT(ok); - - return sel; -} - -static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { - int32_t sel = trygetsel(h, f, type); - UPB_ASSERT(sel >= 0); - return sel; -} - -static const void **returntype(upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { - return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type; -} - -static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f, - upb_handlertype_t type, upb_func *func, - const upb_handlerattr *attr) { - upb_handlerattr set_attr = UPB_HANDLERATTR_INIT; - const void *closure_type; - const void **context_closure_type; - - UPB_ASSERT(!h->table[sel].func); - - if (attr) { - set_attr = *attr; - } - - /* Check that the given closure type matches the closure type that has been - * established for this context (if any). */ - closure_type = set_attr.closure_type; - - if (type == UPB_HANDLER_STRING) { - context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR); - } else if (f && upb_fielddef_isseq(f) && - type != UPB_HANDLER_STARTSEQ && - type != UPB_HANDLER_ENDSEQ) { - context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ); - } else { - context_closure_type = &h->top_closure_type; - } - - if (closure_type && *context_closure_type && - closure_type != *context_closure_type) { - return false; - } - - if (closure_type) - *context_closure_type = closure_type; - - /* If this is a STARTSEQ or STARTSTR handler, check that the returned pointer - * matches any pre-existing expectations about what type is expected. */ - if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) { - const void *return_type = set_attr.return_closure_type; - const void *table_return_type = h->table[sel].attr.return_closure_type; - if (return_type && table_return_type && return_type != table_return_type) { - return false; - } - - if (table_return_type && !return_type) { - set_attr.return_closure_type = table_return_type; - } - } - - h->table[sel].func = (upb_func*)func; - h->table[sel].attr = set_attr; - return true; -} - -/* Returns the effective closure type for this handler (which will propagate - * from outer frames if this frame has no START* handler). Not implemented for - * UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is - * the effective closure type is unspecified (either no handler was registered - * to specify it or the handler that was registered did not specify the closure - * type). */ -const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { - const void *ret; - upb_selector_t sel; - - UPB_ASSERT(type != UPB_HANDLER_STRING); - ret = h->top_closure_type; - - if (upb_fielddef_isseq(f) && - type != UPB_HANDLER_STARTSEQ && - type != UPB_HANDLER_ENDSEQ && - h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) { - ret = h->table[sel].attr.return_closure_type; - } - - if (type == UPB_HANDLER_STRING && - h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) { - ret = h->table[sel].attr.return_closure_type; - } - - /* The effective type of the submessage; not used yet. - * if (type == SUBMESSAGE && - * h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) { - * ret = h->table[sel].attr.return_closure_type; - * } */ - - return ret; -} - -/* Checks whether the START* handler specified by f & type is missing even - * though it is required to convert the established type of an outer frame - * ("closure_type") into the established type of an inner frame (represented in - * the return closure type of this handler's attr. */ -bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type, - upb_status *status) { - const void *closure_type; - const upb_handlerattr *attr; - const void *return_closure_type; - - upb_selector_t sel = handlers_getsel(h, f, type); - if (h->table[sel].func) return true; - closure_type = effective_closure_type(h, f, type); - attr = &h->table[sel].attr; - return_closure_type = attr->return_closure_type; - if (closure_type && return_closure_type && - closure_type != return_closure_type) { - return false; - } - return true; -} - -static upb_handlers *upb_handlers_new(const upb_msgdef *md, - upb_handlercache *cache, - upb_arena *arena) { - int extra; - upb_handlers *h; - - extra = - (int)(sizeof(upb_handlers_tabent) * (upb_msgdef_selectorcount(md) - 1)); - h = upb_calloc(arena, sizeof(*h) + extra); - if (!h) return NULL; - - h->cache = cache; - h->msg = md; - - if (upb_msgdef_submsgfieldcount(md) > 0) { - size_t bytes = upb_msgdef_submsgfieldcount(md) * sizeof(*h->sub); - h->sub = upb_calloc(arena, bytes); - if (!h->sub) return NULL; - } else { - h->sub = 0; - } - - /* calloc() above initialized all handlers to NULL. */ - return h; -} - -/* Public interface ***********************************************************/ - -#define SETTER(name, handlerctype, handlertype) \ - bool upb_handlers_set##name(upb_handlers *h, const upb_fielddef *f, \ - handlerctype func, \ - const upb_handlerattr *attr) { \ - int32_t sel = trygetsel(h, f, handlertype); \ - return doset(h, sel, f, handlertype, (upb_func *)func, attr); \ - } - -SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32) -SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64) -SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32) -SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64) -SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT) -SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE) -SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL) -SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR) -SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING) -SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR) -SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ) -SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG) -SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG) -SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ) - -#undef SETTER - -bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func, - const upb_handlerattr *attr) { - return doset(h, UPB_UNKNOWN_SELECTOR, NULL, UPB_HANDLER_INT32, - (upb_func *)func, attr); -} - -bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, - const upb_handlerattr *attr) { - return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32, - (upb_func *)func, attr); -} - -bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, - const upb_handlerattr *attr) { - return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32, - (upb_func *)func, attr); -} - -bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, - const upb_handlers *sub) { - UPB_ASSERT(sub); - UPB_ASSERT(upb_fielddef_issubmsg(f)); - if (SUBH_F(h, f)) return false; /* Can't reset. */ - if (upb_handlers_msgdef(sub) != upb_fielddef_msgsubdef(f)) { - return false; - } - SUBH_F(h, f) = sub; - return true; -} - -const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, - const upb_fielddef *f) { - UPB_ASSERT(upb_fielddef_issubmsg(f)); - return SUBH_F(h, f); -} - -upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s, - const void **handler_data) { - upb_func *ret = (upb_func *)h->table[s].func; - if (ret && handler_data) { - *handler_data = h->table[s].attr.handler_data; - } - return ret; -} - -bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel, - upb_handlerattr *attr) { - if (!upb_handlers_gethandler(h, sel, NULL)) - return false; - *attr = h->table[sel].attr; - return true; -} - -const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, - upb_selector_t sel) { - /* STARTSUBMSG selector in sel is the field's selector base. */ - return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT); -} - -const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } - -bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) { - return upb_handlercache_addcleanup(h->cache, p, func); -} - -upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: - case UPB_TYPE_ENUM: return UPB_HANDLER_INT32; - case UPB_TYPE_INT64: return UPB_HANDLER_INT64; - case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32; - case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64; - case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT; - case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE; - case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL; - default: UPB_ASSERT(false); return -1; /* Invalid input. */ - } -} - -bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, - upb_selector_t *s) { - uint32_t selector_base = upb_fielddef_selectorbase(f); - switch (type) { - case UPB_HANDLER_INT32: - case UPB_HANDLER_INT64: - case UPB_HANDLER_UINT32: - case UPB_HANDLER_UINT64: - case UPB_HANDLER_FLOAT: - case UPB_HANDLER_DOUBLE: - case UPB_HANDLER_BOOL: - if (!upb_fielddef_isprimitive(f) || - upb_handlers_getprimitivehandlertype(f) != type) - return false; - *s = selector_base; - break; - case UPB_HANDLER_STRING: - if (upb_fielddef_isstring(f)) { - *s = selector_base; - } else if (upb_fielddef_lazy(f)) { - *s = selector_base + 3; - } else { - return false; - } - break; - case UPB_HANDLER_STARTSTR: - if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) { - *s = selector_base + 1; - } else { - return false; - } - break; - case UPB_HANDLER_ENDSTR: - if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) { - *s = selector_base + 2; - } else { - return false; - } - break; - case UPB_HANDLER_STARTSEQ: - if (!upb_fielddef_isseq(f)) return false; - *s = selector_base - 2; - break; - case UPB_HANDLER_ENDSEQ: - if (!upb_fielddef_isseq(f)) return false; - *s = selector_base - 1; - break; - case UPB_HANDLER_STARTSUBMSG: - if (!upb_fielddef_issubmsg(f)) return false; - /* Selectors for STARTSUBMSG are at the beginning of the table so that the - * selector can also be used as an index into the "sub" array of - * subhandlers. The indexes for the two into these two tables are the - * same, except that in the handler table the static selectors come first. */ - *s = upb_fielddef_index(f) + UPB_STATIC_SELECTOR_COUNT; - break; - case UPB_HANDLER_ENDSUBMSG: - if (!upb_fielddef_issubmsg(f)) return false; - *s = selector_base; - break; - } - UPB_ASSERT((size_t)*s < upb_msgdef_selectorcount(upb_fielddef_containingtype(f))); - return true; -} - -/* upb_handlercache ***********************************************************/ - -struct upb_handlercache { - upb_arena *arena; - upb_inttable tab; /* maps upb_msgdef* -> upb_handlers*. */ - upb_handlers_callback *callback; - const void *closure; -}; - -const upb_handlers *upb_handlercache_get(upb_handlercache *c, - const upb_msgdef *md) { - upb_msg_field_iter i; - upb_value v; - upb_handlers *h; - - if (upb_inttable_lookupptr(&c->tab, md, &v)) { - return upb_value_getptr(v); - } - - h = upb_handlers_new(md, c, c->arena); - v = upb_value_ptr(h); - - if (!h) return NULL; - if (!upb_inttable_insertptr(&c->tab, md, v)) return NULL; - - c->callback(c->closure, h); - - /* For each submessage field, get or create a handlers object and set it as - * the subhandlers. */ - for(upb_msg_field_begin(&i, md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - - if (upb_fielddef_issubmsg(f)) { - const upb_msgdef *subdef = upb_fielddef_msgsubdef(f); - const upb_handlers *sub_mh = upb_handlercache_get(c, subdef); - - if (!sub_mh) return NULL; - - upb_handlers_setsubhandlers(h, f, sub_mh); - } - } - - return h; -} - - -upb_handlercache *upb_handlercache_new(upb_handlers_callback *callback, - const void *closure) { - upb_handlercache *cache = upb_gmalloc(sizeof(*cache)); - - if (!cache) return NULL; - - cache->arena = upb_arena_new(); - - cache->callback = callback; - cache->closure = closure; - - if (!upb_inttable_init(&cache->tab, UPB_CTYPE_PTR)) goto oom; - - return cache; - -oom: - upb_gfree(cache); - return NULL; -} - -void upb_handlercache_free(upb_handlercache *cache) { - upb_inttable_uninit(&cache->tab); - upb_arena_free(cache->arena); - upb_gfree(cache); -} - -bool upb_handlercache_addcleanup(upb_handlercache *c, void *p, - upb_handlerfree *func) { - return upb_arena_addcleanup(c->arena, p, func); -} - -/* upb_byteshandler ***********************************************************/ - -bool upb_byteshandler_setstartstr(upb_byteshandler *h, - upb_startstr_handlerfunc *func, void *d) { - h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func; - h->table[UPB_STARTSTR_SELECTOR].attr.handler_data = d; - return true; -} - -bool upb_byteshandler_setstring(upb_byteshandler *h, - upb_string_handlerfunc *func, void *d) { - h->table[UPB_STRING_SELECTOR].func = (upb_func*)func; - h->table[UPB_STRING_SELECTOR].attr.handler_data = d; - return true; -} - -bool upb_byteshandler_setendstr(upb_byteshandler *h, - upb_endfield_handlerfunc *func, void *d) { - h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func; - h->table[UPB_ENDSTR_SELECTOR].attr.handler_data = d; - return true; -} - -/** Handlers for upb_msg ******************************************************/ - -typedef struct { - size_t offset; - int32_t hasbit; -} upb_msg_handlerdata; - -/* Fallback implementation if the handler is not specialized by the producer. */ -#define MSG_WRITER(type, ctype) \ - bool upb_msg_set ## type (void *c, const void *hd, ctype val) { \ - uint8_t *m = c; \ - const upb_msg_handlerdata *d = hd; \ - if (d->hasbit > 0) \ - *(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8); \ - *(ctype*)&m[d->offset] = val; \ - return true; \ - } \ - -MSG_WRITER(double, double) -MSG_WRITER(float, float) -MSG_WRITER(int32, int32_t) -MSG_WRITER(int64, int64_t) -MSG_WRITER(uint32, uint32_t) -MSG_WRITER(uint64, uint64_t) -MSG_WRITER(bool, bool) - -bool upb_msg_setscalarhandler(upb_handlers *h, const upb_fielddef *f, - size_t offset, int32_t hasbit) { - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - bool ok; - - upb_msg_handlerdata *d = upb_gmalloc(sizeof(*d)); - if (!d) return false; - d->offset = offset; - d->hasbit = hasbit; - - attr.handler_data = d; - attr.alwaysok = true; - upb_handlers_addcleanup(h, d, upb_gfree); - -#define TYPE(u, l) \ - case UPB_TYPE_##u: \ - ok = upb_handlers_set##l(h, f, upb_msg_set##l, &attr); break; - - ok = false; - - switch (upb_fielddef_type(f)) { - TYPE(INT64, int64); - TYPE(INT32, int32); - TYPE(ENUM, int32); - TYPE(UINT64, uint64); - TYPE(UINT32, uint32); - TYPE(DOUBLE, double); - TYPE(FLOAT, float); - TYPE(BOOL, bool); - default: UPB_ASSERT(false); break; - } -#undef TYPE - - return ok; -} - -bool upb_msg_getscalarhandlerdata(const upb_handlers *h, - upb_selector_t s, - upb_fieldtype_t *type, - size_t *offset, - int32_t *hasbit) { - const upb_msg_handlerdata *d; - const void *p; - upb_func *f = upb_handlers_gethandler(h, s, &p); - - if ((upb_int64_handlerfunc*)f == upb_msg_setint64) { - *type = UPB_TYPE_INT64; - } else if ((upb_int32_handlerfunc*)f == upb_msg_setint32) { - *type = UPB_TYPE_INT32; - } else if ((upb_uint64_handlerfunc*)f == upb_msg_setuint64) { - *type = UPB_TYPE_UINT64; - } else if ((upb_uint32_handlerfunc*)f == upb_msg_setuint32) { - *type = UPB_TYPE_UINT32; - } else if ((upb_double_handlerfunc*)f == upb_msg_setdouble) { - *type = UPB_TYPE_DOUBLE; - } else if ((upb_float_handlerfunc*)f == upb_msg_setfloat) { - *type = UPB_TYPE_FLOAT; - } else if ((upb_bool_handlerfunc*)f == upb_msg_setbool) { - *type = UPB_TYPE_BOOL; - } else { - return false; - } - - d = p; - *offset = d->offset; - *hasbit = d->hasbit; - return true; -} - - -bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink sink) { - void *subc; - bool ret; - upb_bufhandle handle = UPB_BUFHANDLE_INIT; - handle.buf = buf; - ret = upb_bytessink_start(sink, len, &subc); - if (ret && len != 0) { - ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len); - } - if (ret) { - ret = upb_bytessink_end(sink); - } - return ret; -} - - -#ifdef UPB_MSVC_VSNPRINTF -/* Visual C++ earlier than 2015 doesn't have standard C99 snprintf and - * vsnprintf. To support them, missing functions are manually implemented - * using the existing secure functions. */ -int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg) { - if (!s) { - return _vscprintf(format, arg); - } - int ret = _vsnprintf_s(s, n, _TRUNCATE, format, arg); - if (ret < 0) { - ret = _vscprintf(format, arg); - } - return ret; -} - -int msvc_snprintf(char* s, size_t n, const char* format, ...) { - va_list arg; - va_start(arg, format); - int ret = msvc_vsnprintf(s, n, format, arg); - va_end(arg); - return ret; -} -#endif -/* -** protobuf decoder bytecode compiler -** -** Code to compile a upb::Handlers into bytecode for decoding a protobuf -** according to that specific schema and destination handlers. -** -** Bytecode definition is in decoder.int.h. -*/ - -#include - -#ifdef UPB_DUMP_BYTECODE -#include -#endif - - -#define MAXLABEL 5 -#define EMPTYLABEL -1 - -/* upb_pbdecodermethod ********************************************************/ - -static void freemethod(upb_pbdecodermethod *method) { - upb_inttable_uninit(&method->dispatch); - upb_gfree(method); -} - -static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers, - mgroup *group) { - upb_pbdecodermethod *ret = upb_gmalloc(sizeof(*ret)); - upb_byteshandler_init(&ret->input_handler_); - - ret->group = group; - ret->dest_handlers_ = dest_handlers; - upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64); - - return ret; -} - -const upb_handlers *upb_pbdecodermethod_desthandlers( - const upb_pbdecodermethod *m) { - return m->dest_handlers_; -} - -const upb_byteshandler *upb_pbdecodermethod_inputhandler( - const upb_pbdecodermethod *m) { - return &m->input_handler_; -} - -bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) { - return m->is_native_; -} - - -/* mgroup *********************************************************************/ - -static void freegroup(mgroup *g) { - upb_inttable_iter i; - - upb_inttable_begin(&i, &g->methods); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - freemethod(upb_value_getptr(upb_inttable_iter_value(&i))); - } - - upb_inttable_uninit(&g->methods); - upb_gfree(g->bytecode); - upb_gfree(g); -} - -mgroup *newgroup(void) { - mgroup *g = upb_gmalloc(sizeof(*g)); - upb_inttable_init(&g->methods, UPB_CTYPE_PTR); - g->bytecode = NULL; - g->bytecode_end = NULL; - return g; -} - - -/* bytecode compiler **********************************************************/ - -/* Data used only at compilation time. */ -typedef struct { - mgroup *group; - - uint32_t *pc; - int fwd_labels[MAXLABEL]; - int back_labels[MAXLABEL]; - - /* For fields marked "lazy", parse them lazily or eagerly? */ - bool lazy; -} compiler; - -static compiler *newcompiler(mgroup *group, bool lazy) { - compiler *ret = upb_gmalloc(sizeof(*ret)); - int i; - - ret->group = group; - ret->lazy = lazy; - for (i = 0; i < MAXLABEL; i++) { - ret->fwd_labels[i] = EMPTYLABEL; - ret->back_labels[i] = EMPTYLABEL; - } - return ret; -} - -static void freecompiler(compiler *c) { - upb_gfree(c); -} - -const size_t ptr_words = sizeof(void*) / sizeof(uint32_t); - -/* How many words an instruction is. */ -static int instruction_len(uint32_t instr) { - switch (getop(instr)) { - case OP_SETDISPATCH: return 1 + ptr_words; - case OP_TAGN: return 3; - case OP_SETBIGGROUPNUM: return 2; - default: return 1; - } -} - -bool op_has_longofs(int32_t instruction) { - switch (getop(instruction)) { - case OP_CALL: - case OP_BRANCH: - case OP_CHECKDELIM: - return true; - /* The "tag" instructions only have 8 bytes available for the jump target, - * but that is ok because these opcodes only require short jumps. */ - case OP_TAG1: - case OP_TAG2: - case OP_TAGN: - return false; - default: - UPB_ASSERT(false); - return false; - } -} - -static int32_t getofs(uint32_t instruction) { - if (op_has_longofs(instruction)) { - return (int32_t)instruction >> 8; - } else { - return (int8_t)(instruction >> 8); - } -} - -static void setofs(uint32_t *instruction, int32_t ofs) { - if (op_has_longofs(*instruction)) { - *instruction = getop(*instruction) | (uint32_t)ofs << 8; - } else { - *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8); - } - UPB_ASSERT(getofs(*instruction) == ofs); /* Would fail in cases of overflow. */ -} - -static uint32_t pcofs(compiler *c) { - return (uint32_t)(c->pc - c->group->bytecode); -} - -/* Defines a local label at the current PC location. All previous forward - * references are updated to point to this location. The location is noted - * for any future backward references. */ -static void label(compiler *c, unsigned int label) { - int val; - uint32_t *codep; - - UPB_ASSERT(label < MAXLABEL); - val = c->fwd_labels[label]; - codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val; - while (codep) { - int ofs = getofs(*codep); - setofs(codep, (int32_t)(c->pc - codep - instruction_len(*codep))); - codep = ofs ? codep + ofs : NULL; - } - c->fwd_labels[label] = EMPTYLABEL; - c->back_labels[label] = pcofs(c); -} - -/* Creates a reference to a numbered label; either a forward reference - * (positive arg) or backward reference (negative arg). For forward references - * the value returned now is actually a "next" pointer into a linked list of all - * instructions that use this label and will be patched later when the label is - * defined with label(). - * - * The returned value is the offset that should be written into the instruction. - */ -static int32_t labelref(compiler *c, int label) { - UPB_ASSERT(label < MAXLABEL); - if (label == LABEL_DISPATCH) { - /* No resolving required. */ - return 0; - } else if (label < 0) { - /* Backward local label. Relative to the next instruction. */ - uint32_t from = (uint32_t)((c->pc + 1) - c->group->bytecode); - return c->back_labels[-label] - from; - } else { - /* Forward local label: prepend to (possibly-empty) linked list. */ - int *lptr = &c->fwd_labels[label]; - int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c); - *lptr = pcofs(c); - return ret; - } -} - -static void put32(compiler *c, uint32_t v) { - mgroup *g = c->group; - if (c->pc == g->bytecode_end) { - int ofs = pcofs(c); - size_t oldsize = g->bytecode_end - g->bytecode; - size_t newsize = UPB_MAX(oldsize * 2, 64); - /* TODO(haberman): handle OOM. */ - g->bytecode = upb_grealloc(g->bytecode, oldsize * sizeof(uint32_t), - newsize * sizeof(uint32_t)); - g->bytecode_end = g->bytecode + newsize; - c->pc = g->bytecode + ofs; - } - *c->pc++ = v; -} - -static void putop(compiler *c, int op, ...) { - va_list ap; - va_start(ap, op); - - switch (op) { - case OP_SETDISPATCH: { - uintptr_t ptr = (uintptr_t)va_arg(ap, void*); - put32(c, OP_SETDISPATCH); - put32(c, (uint32_t)ptr); - if (sizeof(uintptr_t) > sizeof(uint32_t)) - put32(c, (uint64_t)ptr >> 32); - break; - } - case OP_STARTMSG: - case OP_ENDMSG: - case OP_PUSHLENDELIM: - case OP_POP: - case OP_SETDELIM: - case OP_HALT: - case OP_RET: - case OP_DISPATCH: - put32(c, op); - break; - case OP_PARSE_DOUBLE: - case OP_PARSE_FLOAT: - case OP_PARSE_INT64: - case OP_PARSE_UINT64: - case OP_PARSE_INT32: - case OP_PARSE_FIXED64: - case OP_PARSE_FIXED32: - case OP_PARSE_BOOL: - case OP_PARSE_UINT32: - case OP_PARSE_SFIXED32: - case OP_PARSE_SFIXED64: - case OP_PARSE_SINT32: - case OP_PARSE_SINT64: - case OP_STARTSEQ: - case OP_ENDSEQ: - case OP_STARTSUBMSG: - case OP_ENDSUBMSG: - case OP_STARTSTR: - case OP_STRING: - case OP_ENDSTR: - case OP_PUSHTAGDELIM: - put32(c, op | va_arg(ap, upb_selector_t) << 8); - break; - case OP_SETBIGGROUPNUM: - put32(c, op); - put32(c, va_arg(ap, int)); - break; - case OP_CALL: { - const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *); - put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8); - break; - } - case OP_CHECKDELIM: - case OP_BRANCH: { - uint32_t instruction = op; - int label = va_arg(ap, int); - setofs(&instruction, labelref(c, label)); - put32(c, instruction); - break; - } - case OP_TAG1: - case OP_TAG2: { - int label = va_arg(ap, int); - uint64_t tag = va_arg(ap, uint64_t); - uint32_t instruction = (uint32_t)(op | (tag << 16)); - UPB_ASSERT(tag <= 0xffff); - setofs(&instruction, labelref(c, label)); - put32(c, instruction); - break; - } - case OP_TAGN: { - int label = va_arg(ap, int); - uint64_t tag = va_arg(ap, uint64_t); - uint32_t instruction = op | (upb_value_size(tag) << 16); - setofs(&instruction, labelref(c, label)); - put32(c, instruction); - put32(c, (uint32_t)tag); - put32(c, tag >> 32); - break; - } - } - - va_end(ap); -} - -#if defined(UPB_DUMP_BYTECODE) - -const char *upb_pbdecoder_getopname(unsigned int op) { -#define QUOTE(x) #x -#define EXPAND_AND_QUOTE(x) QUOTE(x) -#define OPNAME(x) OP_##x -#define OP(x) case OPNAME(x): return EXPAND_AND_QUOTE(OPNAME(x)); -#define T(x) OP(PARSE_##x) - /* Keep in sync with list in decoder.int.h. */ - switch ((opcode)op) { - T(DOUBLE) T(FLOAT) T(INT64) T(UINT64) T(INT32) T(FIXED64) T(FIXED32) - T(BOOL) T(UINT32) T(SFIXED32) T(SFIXED64) T(SINT32) T(SINT64) - OP(STARTMSG) OP(ENDMSG) OP(STARTSEQ) OP(ENDSEQ) OP(STARTSUBMSG) - OP(ENDSUBMSG) OP(STARTSTR) OP(STRING) OP(ENDSTR) OP(CALL) OP(RET) - OP(PUSHLENDELIM) OP(PUSHTAGDELIM) OP(SETDELIM) OP(CHECKDELIM) - OP(BRANCH) OP(TAG1) OP(TAG2) OP(TAGN) OP(SETDISPATCH) OP(POP) - OP(SETBIGGROUPNUM) OP(DISPATCH) OP(HALT) - } - return ""; -#undef OP -#undef T -} - -#endif - -#ifdef UPB_DUMP_BYTECODE - -static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) { - - uint32_t *begin = p; - - while (p < end) { - fprintf(f, "%p %8tx", p, p - begin); - uint32_t instr = *p++; - uint8_t op = getop(instr); - fprintf(f, " %s", upb_pbdecoder_getopname(op)); - switch ((opcode)op) { - case OP_SETDISPATCH: { - const upb_inttable *dispatch; - memcpy(&dispatch, p, sizeof(void*)); - p += ptr_words; - const upb_pbdecodermethod *method = - (void *)((char *)dispatch - - offsetof(upb_pbdecodermethod, dispatch)); - fprintf(f, " %s", upb_msgdef_fullname( - upb_handlers_msgdef(method->dest_handlers_))); - break; - } - case OP_DISPATCH: - case OP_STARTMSG: - case OP_ENDMSG: - case OP_PUSHLENDELIM: - case OP_POP: - case OP_SETDELIM: - case OP_HALT: - case OP_RET: - break; - case OP_PARSE_DOUBLE: - case OP_PARSE_FLOAT: - case OP_PARSE_INT64: - case OP_PARSE_UINT64: - case OP_PARSE_INT32: - case OP_PARSE_FIXED64: - case OP_PARSE_FIXED32: - case OP_PARSE_BOOL: - case OP_PARSE_UINT32: - case OP_PARSE_SFIXED32: - case OP_PARSE_SFIXED64: - case OP_PARSE_SINT32: - case OP_PARSE_SINT64: - case OP_STARTSEQ: - case OP_ENDSEQ: - case OP_STARTSUBMSG: - case OP_ENDSUBMSG: - case OP_STARTSTR: - case OP_STRING: - case OP_ENDSTR: - case OP_PUSHTAGDELIM: - fprintf(f, " %d", instr >> 8); - break; - case OP_SETBIGGROUPNUM: - fprintf(f, " %d", *p++); - break; - case OP_CHECKDELIM: - case OP_CALL: - case OP_BRANCH: - fprintf(f, " =>0x%tx", p + getofs(instr) - begin); - break; - case OP_TAG1: - case OP_TAG2: { - fprintf(f, " tag:0x%x", instr >> 16); - if (getofs(instr)) { - fprintf(f, " =>0x%tx", p + getofs(instr) - begin); - } - break; - } - case OP_TAGN: { - uint64_t tag = *p++; - tag |= (uint64_t)*p++ << 32; - fprintf(f, " tag:0x%llx", (long long)tag); - fprintf(f, " n:%d", instr >> 16); - if (getofs(instr)) { - fprintf(f, " =>0x%tx", p + getofs(instr) - begin); - } - break; - } - } - fputs("\n", f); - } -} - -#endif - -static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) { - uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type; - uint64_t encoded_tag = upb_vencode32(tag); - /* No tag should be greater than 5 bytes. */ - UPB_ASSERT(encoded_tag <= 0xffffffffff); - return encoded_tag; -} - -static void putchecktag(compiler *c, const upb_fielddef *f, - int wire_type, int dest) { - uint64_t tag = get_encoded_tag(f, wire_type); - switch (upb_value_size(tag)) { - case 1: - putop(c, OP_TAG1, dest, tag); - break; - case 2: - putop(c, OP_TAG2, dest, tag); - break; - default: - putop(c, OP_TAGN, dest, tag); - break; - } -} - -static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { - upb_selector_t selector; - bool ok = upb_handlers_getselector(f, type, &selector); - UPB_ASSERT(ok); - return selector; -} - -/* Takes an existing, primary dispatch table entry and repacks it with a - * different alternate wire type. Called when we are inserting a secondary - * dispatch table entry for an alternate wire type. */ -static uint64_t repack(uint64_t dispatch, int new_wt2) { - uint64_t ofs; - uint8_t wt1; - uint8_t old_wt2; - upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2); - UPB_ASSERT(old_wt2 == NO_WIRE_TYPE); /* wt2 should not be set yet. */ - return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2); -} - -/* Marks the current bytecode position as the dispatch target for this message, - * field, and wire type. */ -static void dispatchtarget(compiler *c, upb_pbdecodermethod *method, - const upb_fielddef *f, int wire_type) { - /* Offset is relative to msg base. */ - uint64_t ofs = pcofs(c) - method->code_base.ofs; - uint32_t fn = upb_fielddef_number(f); - upb_inttable *d = &method->dispatch; - upb_value v; - if (upb_inttable_remove(d, fn, &v)) { - /* TODO: prioritize based on packed setting in .proto file. */ - uint64_t repacked = repack(upb_value_getuint64(v), wire_type); - upb_inttable_insert(d, fn, upb_value_uint64(repacked)); - upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs)); - } else { - uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE); - upb_inttable_insert(d, fn, upb_value_uint64(val)); - } -} - -static void putpush(compiler *c, const upb_fielddef *f) { - if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) { - putop(c, OP_PUSHLENDELIM); - } else { - uint32_t fn = upb_fielddef_number(f); - if (fn >= 1 << 24) { - putop(c, OP_PUSHTAGDELIM, 0); - putop(c, OP_SETBIGGROUPNUM, fn); - } else { - putop(c, OP_PUSHTAGDELIM, fn); - } - } -} - -static upb_pbdecodermethod *find_submethod(const compiler *c, - const upb_pbdecodermethod *method, - const upb_fielddef *f) { - const upb_handlers *sub = - upb_handlers_getsubhandlers(method->dest_handlers_, f); - upb_value v; - return upb_inttable_lookupptr(&c->group->methods, sub, &v) - ? upb_value_getptr(v) - : NULL; -} - -static void putsel(compiler *c, opcode op, upb_selector_t sel, - const upb_handlers *h) { - if (upb_handlers_gethandler(h, sel, NULL)) { - putop(c, op, sel); - } -} - -/* Puts an opcode to call a callback, but only if a callback actually exists for - * this field and handler type. */ -static void maybeput(compiler *c, opcode op, const upb_handlers *h, - const upb_fielddef *f, upb_handlertype_t type) { - putsel(c, op, getsel(f, type), h); -} - -static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) { - if (!upb_fielddef_lazy(f)) - return false; - - return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR), NULL) || - upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING), NULL) || - upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR), NULL); -} - - -/* bytecode compiler code generation ******************************************/ - -/* Symbolic names for our local labels. */ -#define LABEL_LOOPSTART 1 /* Top of a repeated field loop. */ -#define LABEL_LOOPBREAK 2 /* To jump out of a repeated loop */ -#define LABEL_FIELD 3 /* Jump backward to find the most recent field. */ -#define LABEL_ENDMSG 4 /* To reach the OP_ENDMSG instr for this msg. */ - -/* Generates bytecode to parse a single non-lazy message field. */ -static void generate_msgfield(compiler *c, const upb_fielddef *f, - upb_pbdecodermethod *method) { - const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); - const upb_pbdecodermethod *sub_m = find_submethod(c, method, f); - int wire_type; - - if (!sub_m) { - /* Don't emit any code for this field at all; it will be parsed as an - * unknown field. - * - * TODO(haberman): we should change this to parse it as a string field - * instead. It will probably be faster, but more importantly, once we - * start vending unknown fields, a field shouldn't be treated as unknown - * just because it doesn't have subhandlers registered. */ - return; - } - - label(c, LABEL_FIELD); - - wire_type = - (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) - ? UPB_WIRE_TYPE_DELIMITED - : UPB_WIRE_TYPE_START_GROUP; - - if (upb_fielddef_isseq(f)) { - putop(c, OP_CHECKDELIM, LABEL_ENDMSG); - putchecktag(c, f, wire_type, LABEL_DISPATCH); - dispatchtarget(c, method, f, wire_type); - putop(c, OP_PUSHTAGDELIM, 0); - putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); - label(c, LABEL_LOOPSTART); - putpush(c, f); - putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); - putop(c, OP_CALL, sub_m); - putop(c, OP_POP); - maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG); - if (wire_type == UPB_WIRE_TYPE_DELIMITED) { - putop(c, OP_SETDELIM); - } - putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); - putchecktag(c, f, wire_type, LABEL_LOOPBREAK); - putop(c, OP_BRANCH, -LABEL_LOOPSTART); - label(c, LABEL_LOOPBREAK); - putop(c, OP_POP); - maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); - } else { - putop(c, OP_CHECKDELIM, LABEL_ENDMSG); - putchecktag(c, f, wire_type, LABEL_DISPATCH); - dispatchtarget(c, method, f, wire_type); - putpush(c, f); - putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); - putop(c, OP_CALL, sub_m); - putop(c, OP_POP); - maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG); - if (wire_type == UPB_WIRE_TYPE_DELIMITED) { - putop(c, OP_SETDELIM); - } - } -} - -/* Generates bytecode to parse a single string or lazy submessage field. */ -static void generate_delimfield(compiler *c, const upb_fielddef *f, - upb_pbdecodermethod *method) { - const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); - - label(c, LABEL_FIELD); - if (upb_fielddef_isseq(f)) { - putop(c, OP_CHECKDELIM, LABEL_ENDMSG); - putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); - dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); - putop(c, OP_PUSHTAGDELIM, 0); - putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); - label(c, LABEL_LOOPSTART); - putop(c, OP_PUSHLENDELIM); - putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); - /* Need to emit even if no handler to skip past the string. */ - putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); - maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR); - putop(c, OP_POP); - putop(c, OP_SETDELIM); - putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); - putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK); - putop(c, OP_BRANCH, -LABEL_LOOPSTART); - label(c, LABEL_LOOPBREAK); - putop(c, OP_POP); - maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); - } else { - putop(c, OP_CHECKDELIM, LABEL_ENDMSG); - putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); - dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); - putop(c, OP_PUSHLENDELIM); - putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); - putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); - maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR); - putop(c, OP_POP); - putop(c, OP_SETDELIM); - } -} - -/* Generates bytecode to parse a single primitive field. */ -static void generate_primitivefield(compiler *c, const upb_fielddef *f, - upb_pbdecodermethod *method) { - const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); - upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f); - opcode parse_type; - upb_selector_t sel; - int wire_type; - - label(c, LABEL_FIELD); - - /* From a decoding perspective, ENUM is the same as INT32. */ - if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM) - descriptor_type = UPB_DESCRIPTOR_TYPE_INT32; - - parse_type = (opcode)descriptor_type; - - /* TODO(haberman): generate packed or non-packed first depending on "packed" - * setting in the fielddef. This will favor (in speed) whichever was - * specified. */ - - UPB_ASSERT((int)parse_type >= 0 && parse_type <= OP_MAX); - sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); - wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)]; - if (upb_fielddef_isseq(f)) { - putop(c, OP_CHECKDELIM, LABEL_ENDMSG); - putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); - dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); - putop(c, OP_PUSHLENDELIM); - putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Packed */ - label(c, LABEL_LOOPSTART); - putop(c, parse_type, sel); - putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); - putop(c, OP_BRANCH, -LABEL_LOOPSTART); - dispatchtarget(c, method, f, wire_type); - putop(c, OP_PUSHTAGDELIM, 0); - putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Non-packed */ - label(c, LABEL_LOOPSTART); - putop(c, parse_type, sel); - putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); - putchecktag(c, f, wire_type, LABEL_LOOPBREAK); - putop(c, OP_BRANCH, -LABEL_LOOPSTART); - label(c, LABEL_LOOPBREAK); - putop(c, OP_POP); /* Packed and non-packed join. */ - maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); - putop(c, OP_SETDELIM); /* Could remove for non-packed by dup ENDSEQ. */ - } else { - putop(c, OP_CHECKDELIM, LABEL_ENDMSG); - putchecktag(c, f, wire_type, LABEL_DISPATCH); - dispatchtarget(c, method, f, wire_type); - putop(c, parse_type, sel); - } -} - -/* Adds bytecode for parsing the given message to the given decoderplan, - * while adding all dispatch targets to this message's dispatch table. */ -static void compile_method(compiler *c, upb_pbdecodermethod *method) { - const upb_handlers *h; - const upb_msgdef *md; - uint32_t* start_pc; - upb_msg_field_iter i; - upb_value val; - - UPB_ASSERT(method); - - /* Clear all entries in the dispatch table. */ - upb_inttable_uninit(&method->dispatch); - upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64); - - h = upb_pbdecodermethod_desthandlers(method); - md = upb_handlers_msgdef(h); - - method->code_base.ofs = pcofs(c); - putop(c, OP_SETDISPATCH, &method->dispatch); - putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h); - label(c, LABEL_FIELD); - start_pc = c->pc; - for(upb_msg_field_begin(&i, md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - upb_fieldtype_t type = upb_fielddef_type(f); - - if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) { - generate_msgfield(c, f, method); - } else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES || - type == UPB_TYPE_MESSAGE) { - generate_delimfield(c, f, method); - } else { - generate_primitivefield(c, f, method); - } - } - - /* If there were no fields, or if no handlers were defined, we need to - * generate a non-empty loop body so that we can at least dispatch for unknown - * fields and check for the end of the message. */ - if (c->pc == start_pc) { - /* Check for end-of-message. */ - putop(c, OP_CHECKDELIM, LABEL_ENDMSG); - /* Unconditionally dispatch. */ - putop(c, OP_DISPATCH, 0); - } - - /* For now we just loop back to the last field of the message (or if none, - * the DISPATCH opcode for the message). */ - putop(c, OP_BRANCH, -LABEL_FIELD); - - /* Insert both a label and a dispatch table entry for this end-of-msg. */ - label(c, LABEL_ENDMSG); - val = upb_value_uint64(pcofs(c) - method->code_base.ofs); - upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val); - - putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h); - putop(c, OP_RET); - - upb_inttable_compact(&method->dispatch); -} - -/* Populate "methods" with new upb_pbdecodermethod objects reachable from "h". - * Returns the method for these handlers. - * - * Generates a new method for every destination handlers reachable from "h". */ -static void find_methods(compiler *c, const upb_handlers *h) { - upb_value v; - upb_msg_field_iter i; - const upb_msgdef *md; - upb_pbdecodermethod *method; - - if (upb_inttable_lookupptr(&c->group->methods, h, &v)) - return; - - method = newmethod(h, c->group); - upb_inttable_insertptr(&c->group->methods, h, upb_value_ptr(method)); - - /* Find submethods. */ - md = upb_handlers_msgdef(h); - for(upb_msg_field_begin(&i, md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - const upb_handlers *sub_h; - if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE && - (sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) { - /* We only generate a decoder method for submessages with handlers. - * Others will be parsed as unknown fields. */ - find_methods(c, sub_h); - } - } -} - -/* (Re-)compile bytecode for all messages in "msgs." - * Overwrites any existing bytecode in "c". */ -static void compile_methods(compiler *c) { - upb_inttable_iter i; - - /* Start over at the beginning of the bytecode. */ - c->pc = c->group->bytecode; - - upb_inttable_begin(&i, &c->group->methods); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); - compile_method(c, method); - } -} - -static void set_bytecode_handlers(mgroup *g) { - upb_inttable_iter i; - upb_inttable_begin(&i, &g->methods); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i)); - upb_byteshandler *h = &m->input_handler_; - - m->code_base.ptr = g->bytecode + m->code_base.ofs; - - upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr); - upb_byteshandler_setstring(h, upb_pbdecoder_decode, g); - upb_byteshandler_setendstr(h, upb_pbdecoder_end, m); - } -} - - -/* TODO(haberman): allow this to be constructed for an arbitrary set of dest - * handlers and other mgroups (but verify we have a transitive closure). */ -const mgroup *mgroup_new(const upb_handlers *dest, bool lazy) { - mgroup *g; - compiler *c; - - g = newgroup(); - c = newcompiler(g, lazy); - find_methods(c, dest); - - /* We compile in two passes: - * 1. all messages are assigned relative offsets from the beginning of the - * bytecode (saved in method->code_base). - * 2. forwards OP_CALL instructions can be correctly linked since message - * offsets have been previously assigned. - * - * Could avoid the second pass by linking OP_CALL instructions somehow. */ - compile_methods(c); - compile_methods(c); - g->bytecode_end = c->pc; - freecompiler(c); - -#ifdef UPB_DUMP_BYTECODE - { - FILE *f = fopen("/tmp/upb-bytecode", "w"); - UPB_ASSERT(f); - dumpbc(g->bytecode, g->bytecode_end, stderr); - dumpbc(g->bytecode, g->bytecode_end, f); - fclose(f); - - f = fopen("/tmp/upb-bytecode.bin", "wb"); - UPB_ASSERT(f); - fwrite(g->bytecode, 1, g->bytecode_end - g->bytecode, f); - fclose(f); - } -#endif - - set_bytecode_handlers(g); - return g; -} - - -/* upb_pbcodecache ************************************************************/ - -upb_pbcodecache *upb_pbcodecache_new(upb_handlercache *dest) { - upb_pbcodecache *c = upb_gmalloc(sizeof(*c)); - - if (!c) return NULL; - - c->dest = dest; - c->lazy = false; - - c->arena = upb_arena_new(); - if (!upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR)) return NULL; - - return c; -} - -void upb_pbcodecache_free(upb_pbcodecache *c) { - upb_inttable_iter i; - - upb_inttable_begin(&i, &c->groups); - for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - upb_value val = upb_inttable_iter_value(&i); - freegroup((void*)upb_value_getconstptr(val)); - } - - upb_inttable_uninit(&c->groups); - upb_arena_free(c->arena); - upb_gfree(c); -} - -void upb_pbdecodermethodopts_setlazy(upb_pbcodecache *c, bool lazy) { - UPB_ASSERT(upb_inttable_count(&c->groups) == 0); - c->lazy = lazy; -} - -const upb_pbdecodermethod *upb_pbcodecache_get(upb_pbcodecache *c, - const upb_msgdef *md) { - upb_value v; - bool ok; - const upb_handlers *h; - const mgroup *g; - - h = upb_handlercache_get(c->dest, md); - if (upb_inttable_lookupptr(&c->groups, md, &v)) { - g = upb_value_getconstptr(v); - } else { - g = mgroup_new(h, c->lazy); - ok = upb_inttable_insertptr(&c->groups, md, upb_value_constptr(g)); - UPB_ASSUME(ok); - } - - ok = upb_inttable_lookupptr(&g->methods, h, &v); - UPB_ASSUME(ok); - return upb_value_getptr(v); -} -/* -** upb::Decoder (Bytecode Decoder VM) -** -** Bytecode must previously have been generated using the bytecode compiler in -** compile_decoder.c. This decoder then walks through the bytecode op-by-op to -** parse the input. -** -** Decoding is fully resumable; we just keep a pointer to the current bytecode -** instruction and resume from there. A fair amount of the logic here is to -** handle the fact that values can span buffer seams and we have to be able to -** be capable of suspending/resuming from any byte in the stream. This -** sometimes requires keeping a few trailing bytes from the last buffer around -** in the "residual" buffer. -*/ - -#include -#include - -#ifdef UPB_DUMP_BYTECODE -#include -#endif - - -#define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d); - -/* Error messages that are shared between the bytecode and JIT decoders. */ -const char *kPbDecoderStackOverflow = "Nesting too deep."; -const char *kPbDecoderSubmessageTooLong = - "Submessage end extends past enclosing submessage."; - -/* Error messages shared within this file. */ -static const char *kUnterminatedVarint = "Unterminated varint."; - -/* upb_pbdecoder **************************************************************/ - -static opcode halt = OP_HALT; - -/* A dummy character we can point to when the user passes us a NULL buffer. - * We need this because in C (NULL + 0) and (NULL - NULL) are undefined - * behavior, which would invalidate functions like curbufleft(). */ -static const char dummy_char; - -/* Whether an op consumes any of the input buffer. */ -static bool consumes_input(opcode op) { - switch (op) { - case OP_SETDISPATCH: - case OP_STARTMSG: - case OP_ENDMSG: - case OP_STARTSEQ: - case OP_ENDSEQ: - case OP_STARTSUBMSG: - case OP_ENDSUBMSG: - case OP_STARTSTR: - case OP_ENDSTR: - case OP_PUSHTAGDELIM: - case OP_POP: - case OP_SETDELIM: - case OP_SETBIGGROUPNUM: - case OP_CHECKDELIM: - case OP_CALL: - case OP_RET: - case OP_BRANCH: - return false; - default: - return true; - } -} - -static size_t stacksize(upb_pbdecoder *d, size_t entries) { - UPB_UNUSED(d); - return entries * sizeof(upb_pbdecoder_frame); -} - -static size_t callstacksize(upb_pbdecoder *d, size_t entries) { - UPB_UNUSED(d); - - return entries * sizeof(uint32_t*); -} - - -static bool in_residual_buf(const upb_pbdecoder *d, const char *p); - -/* It's unfortunate that we have to micro-manage the compiler with - * UPB_FORCEINLINE and UPB_NOINLINE, especially since this tuning is necessarily - * specific to one hardware configuration. But empirically on a Core i7, - * performance increases 30-50% with these annotations. Every instance where - * these appear, gcc 4.2.1 made the wrong decision and degraded performance in - * benchmarks. */ - -static void seterr(upb_pbdecoder *d, const char *msg) { - upb_status_seterrmsg(d->status, msg); -} - -void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) { - seterr(d, msg); -} - - -/* Buffering ******************************************************************/ - -/* We operate on one buffer at a time, which is either the user's buffer passed - * to our "decode" callback or some residual bytes from the previous buffer. */ - -/* How many bytes can be safely read from d->ptr without reading past end-of-buf - * or past the current delimited end. */ -static size_t curbufleft(const upb_pbdecoder *d) { - UPB_ASSERT(d->data_end >= d->ptr); - return d->data_end - d->ptr; -} - -/* How many bytes are available before end-of-buffer. */ -static size_t bufleft(const upb_pbdecoder *d) { - return d->end - d->ptr; -} - -/* Overall stream offset of d->ptr. */ -uint64_t offset(const upb_pbdecoder *d) { - return d->bufstart_ofs + (d->ptr - d->buf); -} - -/* How many bytes are available before the end of this delimited region. */ -size_t delim_remaining(const upb_pbdecoder *d) { - return d->top->end_ofs - offset(d); -} - -/* Advances d->ptr. */ -static void advance(upb_pbdecoder *d, size_t len) { - UPB_ASSERT(curbufleft(d) >= len); - d->ptr += len; -} - -static bool in_buf(const char *p, const char *buf, const char *end) { - return p >= buf && p <= end; -} - -static bool in_residual_buf(const upb_pbdecoder *d, const char *p) { - return in_buf(p, d->residual, d->residual_end); -} - -/* Calculates the delim_end value, which is affected by both the current buffer - * and the parsing stack, so must be called whenever either is updated. */ -static void set_delim_end(upb_pbdecoder *d) { - size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs; - if (delim_ofs <= (size_t)(d->end - d->buf)) { - d->delim_end = d->buf + delim_ofs; - d->data_end = d->delim_end; - } else { - d->data_end = d->end; - d->delim_end = NULL; - } -} - -static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) { - d->ptr = buf; - d->buf = buf; - d->end = end; - set_delim_end(d); -} - -static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) { - UPB_ASSERT(curbufleft(d) == 0); - d->bufstart_ofs += (d->end - d->buf); - switchtobuf(d, buf, buf + len); -} - -static void checkpoint(upb_pbdecoder *d) { - /* The assertion here is in the interests of efficiency, not correctness. - * We are trying to ensure that we don't checkpoint() more often than - * necessary. */ - UPB_ASSERT(d->checkpoint != d->ptr); - d->checkpoint = d->ptr; -} - -/* Skips "bytes" bytes in the stream, which may be more than available. If we - * skip more bytes than are available, we return a long read count to the caller - * indicating how many bytes can be skipped over before passing actual data - * again. Skipped bytes can pass a NULL buffer and the decoder guarantees they - * won't actually be read. - */ -static int32_t skip(upb_pbdecoder *d, size_t bytes) { - UPB_ASSERT(!in_residual_buf(d, d->ptr) || d->size_param == 0); - UPB_ASSERT(d->skip == 0); - if (bytes > delim_remaining(d)) { - seterr(d, "Skipped value extended beyond enclosing submessage."); - return (int32_t)upb_pbdecoder_suspend(d); - } else if (bufleft(d) >= bytes) { - /* Skipped data is all in current buffer, and more is still available. */ - advance(d, bytes); - d->skip = 0; - return DECODE_OK; - } else { - /* Skipped data extends beyond currently available buffers. */ - d->pc = d->last; - d->skip = bytes - curbufleft(d); - d->bufstart_ofs += (d->end - d->buf); - d->residual_end = d->residual; - switchtobuf(d, d->residual, d->residual_end); - return (int32_t)(d->size_param + d->skip); - } -} - - -/* Resumes the decoder from an initial state or from a previous suspend. */ -int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, - size_t size, const upb_bufhandle *handle) { - UPB_UNUSED(p); /* Useless; just for the benefit of the JIT. */ - - /* d->skip and d->residual_end could probably elegantly be represented - * as a single variable, to more easily represent this invariant. */ - UPB_ASSERT(!(d->skip && d->residual_end > d->residual)); - - /* We need to remember the original size_param, so that the value we return - * is relative to it, even if we do some skipping first. */ - d->size_param = size; - d->handle = handle; - - /* Have to handle this case specially (ie. not with skip()) because the user - * is allowed to pass a NULL buffer here, which won't allow us to safely - * calculate a d->end or use our normal functions like curbufleft(). */ - if (d->skip && d->skip >= size) { - d->skip -= size; - d->bufstart_ofs += size; - buf = &dummy_char; - size = 0; - - /* We can't just return now, because we might need to execute some ops - * like CHECKDELIM, which could call some callbacks and pop the stack. */ - } - - /* We need to pretend that this was the actual buffer param, since some of the - * calculations assume that d->ptr/d->buf is relative to this. */ - d->buf_param = buf; - - if (!buf) { - /* NULL buf is ok if its entire span is covered by the "skip" above, but - * by this point we know that "skip" doesn't cover the buffer. */ - seterr(d, "Passed NULL buffer over non-skippable region."); - return (int32_t)upb_pbdecoder_suspend(d); - } - - if (d->residual_end > d->residual) { - /* We have residual bytes from the last buffer. */ - UPB_ASSERT(d->ptr == d->residual); - } else { - switchtobuf(d, buf, buf + size); - } - - d->checkpoint = d->ptr; - - /* Handle skips that don't cover the whole buffer (as above). */ - if (d->skip) { - size_t skip_bytes = d->skip; - d->skip = 0; - CHECK_RETURN(skip(d, skip_bytes)); - checkpoint(d); - } - - /* If we're inside an unknown group, continue to parse unknown values. */ - if (d->top->groupnum < 0) { - CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0)); - checkpoint(d); - } - - return DECODE_OK; -} - -/* Suspends the decoder at the last checkpoint, without saving any residual - * bytes. If there are any unconsumed bytes, returns a short byte count. */ -size_t upb_pbdecoder_suspend(upb_pbdecoder *d) { - d->pc = d->last; - if (d->checkpoint == d->residual) { - /* Checkpoint was in residual buf; no user bytes were consumed. */ - d->ptr = d->residual; - return 0; - } else { - size_t ret = d->size_param - (d->end - d->checkpoint); - UPB_ASSERT(!in_residual_buf(d, d->checkpoint)); - UPB_ASSERT(d->buf == d->buf_param || d->buf == &dummy_char); - - d->bufstart_ofs += (d->checkpoint - d->buf); - d->residual_end = d->residual; - switchtobuf(d, d->residual, d->residual_end); - return ret; - } -} - -/* Suspends the decoder at the last checkpoint, and saves any unconsumed - * bytes in our residual buffer. This is necessary if we need more user - * bytes to form a complete value, which might not be contiguous in the - * user's buffers. Always consumes all user bytes. */ -static size_t suspend_save(upb_pbdecoder *d) { - /* We hit end-of-buffer before we could parse a full value. - * Save any unconsumed bytes (if any) to the residual buffer. */ - d->pc = d->last; - - if (d->checkpoint == d->residual) { - /* Checkpoint was in residual buf; append user byte(s) to residual buf. */ - UPB_ASSERT((d->residual_end - d->residual) + d->size_param <= - sizeof(d->residual)); - if (!in_residual_buf(d, d->ptr)) { - d->bufstart_ofs -= (d->residual_end - d->residual); - } - memcpy(d->residual_end, d->buf_param, d->size_param); - d->residual_end += d->size_param; - } else { - /* Checkpoint was in user buf; old residual bytes not needed. */ - size_t save; - UPB_ASSERT(!in_residual_buf(d, d->checkpoint)); - - d->ptr = d->checkpoint; - save = curbufleft(d); - UPB_ASSERT(save <= sizeof(d->residual)); - memcpy(d->residual, d->ptr, save); - d->residual_end = d->residual + save; - d->bufstart_ofs = offset(d); - } - - switchtobuf(d, d->residual, d->residual_end); - return d->size_param; -} - -/* Copies the next "bytes" bytes into "buf" and advances the stream. - * Requires that this many bytes are available in the current buffer. */ -UPB_FORCEINLINE static void consumebytes(upb_pbdecoder *d, void *buf, - size_t bytes) { - UPB_ASSERT(bytes <= curbufleft(d)); - memcpy(buf, d->ptr, bytes); - advance(d, bytes); -} - -/* Slow path for getting the next "bytes" bytes, regardless of whether they are - * available in the current buffer or not. Returns a status code as described - * in decoder.int.h. */ -UPB_NOINLINE static int32_t getbytes_slow(upb_pbdecoder *d, void *buf, - size_t bytes) { - const size_t avail = curbufleft(d); - consumebytes(d, buf, avail); - bytes -= avail; - UPB_ASSERT(bytes > 0); - if (in_residual_buf(d, d->ptr)) { - advancetobuf(d, d->buf_param, d->size_param); - } - if (curbufleft(d) >= bytes) { - consumebytes(d, (char *)buf + avail, bytes); - return DECODE_OK; - } else if (d->data_end == d->delim_end) { - seterr(d, "Submessage ended in the middle of a value or group"); - return (int32_t)upb_pbdecoder_suspend(d); - } else { - return (int32_t)suspend_save(d); - } -} - -/* Gets the next "bytes" bytes, regardless of whether they are available in the - * current buffer or not. Returns a status code as described in decoder.int.h. - */ -UPB_FORCEINLINE static int32_t getbytes(upb_pbdecoder *d, void *buf, - size_t bytes) { - if (curbufleft(d) >= bytes) { - /* Buffer has enough data to satisfy. */ - consumebytes(d, buf, bytes); - return DECODE_OK; - } else { - return getbytes_slow(d, buf, bytes); - } -} - -UPB_NOINLINE static size_t peekbytes_slow(upb_pbdecoder *d, void *buf, - size_t bytes) { - size_t ret = curbufleft(d); - memcpy(buf, d->ptr, ret); - if (in_residual_buf(d, d->ptr)) { - size_t copy = UPB_MIN(bytes - ret, d->size_param); - memcpy((char *)buf + ret, d->buf_param, copy); - ret += copy; - } - return ret; -} - -UPB_FORCEINLINE static size_t peekbytes(upb_pbdecoder *d, void *buf, - size_t bytes) { - if (curbufleft(d) >= bytes) { - memcpy(buf, d->ptr, bytes); - return bytes; - } else { - return peekbytes_slow(d, buf, bytes); - } -} - - -/* Decoding of wire types *****************************************************/ - -/* Slow path for decoding a varint from the current buffer position. - * Returns a status code as described in decoder.int.h. */ -UPB_NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, - uint64_t *u64) { - uint8_t byte = 0x80; - int bitpos; - *u64 = 0; - for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) { - CHECK_RETURN(getbytes(d, &byte, 1)); - *u64 |= (uint64_t)(byte & 0x7F) << bitpos; - } - if(bitpos == 70 && (byte & 0x80)) { - seterr(d, kUnterminatedVarint); - return (int32_t)upb_pbdecoder_suspend(d); - } - return DECODE_OK; -} - -/* Decodes a varint from the current buffer position. - * Returns a status code as described in decoder.int.h. */ -UPB_FORCEINLINE static int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) { - if (curbufleft(d) > 0 && !(*d->ptr & 0x80)) { - *u64 = *d->ptr; - advance(d, 1); - return DECODE_OK; - } else if (curbufleft(d) >= 10) { - /* Fast case. */ - upb_decoderet r = upb_vdecode_fast(d->ptr); - if (r.p == NULL) { - seterr(d, kUnterminatedVarint); - return (int32_t)upb_pbdecoder_suspend(d); - } - advance(d, r.p - d->ptr); - *u64 = r.val; - return DECODE_OK; - } else { - /* Slow case -- varint spans buffer seam. */ - return upb_pbdecoder_decode_varint_slow(d, u64); - } -} - -/* Decodes a 32-bit varint from the current buffer position. - * Returns a status code as described in decoder.int.h. */ -UPB_FORCEINLINE static int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) { - uint64_t u64; - int32_t ret = decode_varint(d, &u64); - if (ret >= 0) return ret; - if (u64 > UINT32_MAX) { - seterr(d, "Unterminated 32-bit varint"); - /* TODO(haberman) guarantee that this function return is >= 0 somehow, - * so we know this path will always be treated as error by our caller. - * Right now the size_t -> int32_t can overflow and produce negative values. - */ - *u32 = 0; - return (int32_t)upb_pbdecoder_suspend(d); - } - *u32 = (uint32_t)u64; - return DECODE_OK; -} - -/* Decodes a fixed32 from the current buffer position. - * Returns a status code as described in decoder.int.h. - * TODO: proper byte swapping for big-endian machines. */ -UPB_FORCEINLINE static int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) { - return getbytes(d, u32, 4); -} - -/* Decodes a fixed64 from the current buffer position. - * Returns a status code as described in decoder.int.h. - * TODO: proper byte swapping for big-endian machines. */ -UPB_FORCEINLINE static int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) { - return getbytes(d, u64, 8); -} - -/* Non-static versions of the above functions. - * These are called by the JIT for fallback paths. */ -int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) { - return decode_fixed32(d, u32); -} - -int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) { - return decode_fixed64(d, u64); -} - -static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; } -static float as_float(uint32_t n) { float f; memcpy(&f, &n, 4); return f; } - -/* Pushes a frame onto the decoder stack. */ -static bool decoder_push(upb_pbdecoder *d, uint64_t end) { - upb_pbdecoder_frame *fr = d->top; - - if (end > fr->end_ofs) { - seterr(d, kPbDecoderSubmessageTooLong); - return false; - } else if (fr == d->limit) { - seterr(d, kPbDecoderStackOverflow); - return false; - } - - fr++; - fr->end_ofs = end; - fr->dispatch = NULL; - fr->groupnum = 0; - d->top = fr; - return true; -} - -static bool pushtagdelim(upb_pbdecoder *d, uint32_t arg) { - /* While we expect to see an "end" tag (either ENDGROUP or a non-sequence - * field number) prior to hitting any enclosing submessage end, pushing our - * existing delim end prevents us from continuing to parse values from a - * corrupt proto that doesn't give us an END tag in time. */ - if (!decoder_push(d, d->top->end_ofs)) - return false; - d->top->groupnum = arg; - return true; -} - -/* Pops a frame from the decoder stack. */ -static void decoder_pop(upb_pbdecoder *d) { d->top--; } - -UPB_NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, - uint64_t expected) { - uint64_t data = 0; - size_t bytes = upb_value_size(expected); - size_t read = peekbytes(d, &data, bytes); - if (read == bytes && data == expected) { - /* Advance past matched bytes. */ - int32_t ok = getbytes(d, &data, read); - UPB_ASSERT(ok < 0); - return DECODE_OK; - } else if (read < bytes && memcmp(&data, &expected, read) == 0) { - return (int32_t)suspend_save(d); - } else { - return DECODE_MISMATCH; - } -} - -int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum, - uint8_t wire_type) { - if (fieldnum >= 0) - goto have_tag; - - while (true) { - uint32_t tag; - CHECK_RETURN(decode_v32(d, &tag)); - wire_type = tag & 0x7; - fieldnum = tag >> 3; - -have_tag: - if (fieldnum == 0) { - seterr(d, "Saw invalid field number (0)"); - return (int32_t)upb_pbdecoder_suspend(d); - } - - switch (wire_type) { - case UPB_WIRE_TYPE_32BIT: - CHECK_RETURN(skip(d, 4)); - break; - case UPB_WIRE_TYPE_64BIT: - CHECK_RETURN(skip(d, 8)); - break; - case UPB_WIRE_TYPE_VARINT: { - uint64_t u64; - CHECK_RETURN(decode_varint(d, &u64)); - break; - } - case UPB_WIRE_TYPE_DELIMITED: { - uint32_t len; - CHECK_RETURN(decode_v32(d, &len)); - CHECK_RETURN(skip(d, len)); - break; - } - case UPB_WIRE_TYPE_START_GROUP: - if (!pushtagdelim(d, -fieldnum)) { - return (int32_t)upb_pbdecoder_suspend(d); - } - break; - case UPB_WIRE_TYPE_END_GROUP: - if (fieldnum == -d->top->groupnum) { - decoder_pop(d); - } else if (fieldnum == d->top->groupnum) { - return DECODE_ENDGROUP; - } else { - seterr(d, "Unmatched ENDGROUP tag."); - return (int32_t)upb_pbdecoder_suspend(d); - } - break; - default: - seterr(d, "Invalid wire type"); - return (int32_t)upb_pbdecoder_suspend(d); - } - - if (d->top->groupnum >= 0) { - /* TODO: More code needed for handling unknown groups. */ - upb_sink_putunknown(d->top->sink, d->checkpoint, d->ptr - d->checkpoint); - return DECODE_OK; - } - - /* Unknown group -- continue looping over unknown fields. */ - checkpoint(d); - } -} - -static void goto_endmsg(upb_pbdecoder *d) { - upb_value v; - bool found = upb_inttable_lookup32(d->top->dispatch, DISPATCH_ENDMSG, &v); - UPB_ASSERT(found); - d->pc = d->top->base + upb_value_getuint64(v); -} - -/* Parses a tag and jumps to the corresponding bytecode instruction for this - * field. - * - * If the tag is unknown (or the wire type doesn't match), parses the field as - * unknown. If the tag is a valid ENDGROUP tag, jumps to the bytecode - * instruction for the end of message. */ -static int32_t dispatch(upb_pbdecoder *d) { - upb_inttable *dispatch = d->top->dispatch; - uint32_t tag; - uint8_t wire_type; - uint32_t fieldnum; - upb_value val; - int32_t retval; - - /* Decode tag. */ - CHECK_RETURN(decode_v32(d, &tag)); - wire_type = tag & 0x7; - fieldnum = tag >> 3; - - /* Lookup tag. Because of packed/non-packed compatibility, we have to - * check the wire type against two possibilities. */ - if (fieldnum != DISPATCH_ENDMSG && - upb_inttable_lookup32(dispatch, fieldnum, &val)) { - uint64_t v = upb_value_getuint64(val); - if (wire_type == (v & 0xff)) { - d->pc = d->top->base + (v >> 16); - return DECODE_OK; - } else if (wire_type == ((v >> 8) & 0xff)) { - bool found = - upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val); - UPB_ASSERT(found); - d->pc = d->top->base + upb_value_getuint64(val); - return DECODE_OK; - } - } - - /* We have some unknown fields (or ENDGROUP) to parse. The DISPATCH or TAG - * bytecode that triggered this is preceded by a CHECKDELIM bytecode which - * we need to back up to, so that when we're done skipping unknown data we - * can re-check the delimited end. */ - d->last--; /* Necessary if we get suspended */ - d->pc = d->last; - UPB_ASSERT(getop(*d->last) == OP_CHECKDELIM); - - /* Unknown field or ENDGROUP. */ - retval = upb_pbdecoder_skipunknown(d, fieldnum, wire_type); - - CHECK_RETURN(retval); - - if (retval == DECODE_ENDGROUP) { - goto_endmsg(d); - return DECODE_OK; - } - - return DECODE_OK; -} - -/* Callers know that the stack is more than one deep because the opcodes that - * call this only occur after PUSH operations. */ -upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) { - UPB_ASSERT(d->top != d->stack); - return d->top - 1; -} - - -/* The main decoding loop *****************************************************/ - -/* The main decoder VM function. Uses traditional bytecode dispatch loop with a - * switch() statement. */ -size_t run_decoder_vm(upb_pbdecoder *d, const mgroup *group, - const upb_bufhandle* handle) { - -#define VMCASE(op, code) \ - case op: { code; if (consumes_input(op)) checkpoint(d); break; } -#define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \ - VMCASE(OP_PARSE_ ## type, { \ - ctype val; \ - CHECK_RETURN(decode_ ## wt(d, &val)); \ - upb_sink_put ## name(d->top->sink, arg, (convfunc)(val)); \ - }) - - while(1) { - int32_t instruction; - opcode op; - uint32_t arg; - int32_t longofs; - - d->last = d->pc; - instruction = *d->pc++; - op = getop(instruction); - arg = instruction >> 8; - longofs = arg; - UPB_ASSERT(d->ptr != d->residual_end); - UPB_UNUSED(group); -#ifdef UPB_DUMP_BYTECODE - fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d " - "%x %s (%d)\n", - (int)offset(d), - (int)(d->ptr - d->buf), - (int)(d->data_end - d->ptr), - (int)(d->end - d->ptr), - (int)((d->top->end_ofs - d->bufstart_ofs) - (d->ptr - d->buf)), - (int)(d->pc - 1 - group->bytecode), - upb_pbdecoder_getopname(op), - arg); -#endif - switch (op) { - /* Technically, we are losing data if we see a 32-bit varint that is not - * properly sign-extended. We could detect this and error about the data - * loss, but proto2 does not do this, so we pass. */ - PRIMITIVE_OP(INT32, varint, int32, int32_t, uint64_t) - PRIMITIVE_OP(INT64, varint, int64, int64_t, uint64_t) - PRIMITIVE_OP(UINT32, varint, uint32, uint32_t, uint64_t) - PRIMITIVE_OP(UINT64, varint, uint64, uint64_t, uint64_t) - PRIMITIVE_OP(FIXED32, fixed32, uint32, uint32_t, uint32_t) - PRIMITIVE_OP(FIXED64, fixed64, uint64, uint64_t, uint64_t) - PRIMITIVE_OP(SFIXED32, fixed32, int32, int32_t, uint32_t) - PRIMITIVE_OP(SFIXED64, fixed64, int64, int64_t, uint64_t) - PRIMITIVE_OP(BOOL, varint, bool, bool, uint64_t) - PRIMITIVE_OP(DOUBLE, fixed64, double, as_double, uint64_t) - PRIMITIVE_OP(FLOAT, fixed32, float, as_float, uint32_t) - PRIMITIVE_OP(SINT32, varint, int32, upb_zzdec_32, uint64_t) - PRIMITIVE_OP(SINT64, varint, int64, upb_zzdec_64, uint64_t) - - VMCASE(OP_SETDISPATCH, - d->top->base = d->pc - 1; - memcpy(&d->top->dispatch, d->pc, sizeof(void*)); - d->pc += sizeof(void*) / sizeof(uint32_t); - ) - VMCASE(OP_STARTMSG, - CHECK_SUSPEND(upb_sink_startmsg(d->top->sink)); - ) - VMCASE(OP_ENDMSG, - CHECK_SUSPEND(upb_sink_endmsg(d->top->sink, d->status)); - ) - VMCASE(OP_STARTSEQ, - upb_pbdecoder_frame *outer = outer_frame(d); - CHECK_SUSPEND(upb_sink_startseq(outer->sink, arg, &d->top->sink)); - ) - VMCASE(OP_ENDSEQ, - CHECK_SUSPEND(upb_sink_endseq(d->top->sink, arg)); - ) - VMCASE(OP_STARTSUBMSG, - upb_pbdecoder_frame *outer = outer_frame(d); - CHECK_SUSPEND(upb_sink_startsubmsg(outer->sink, arg, &d->top->sink)); - ) - VMCASE(OP_ENDSUBMSG, - upb_sink subsink = (d->top + 1)->sink; - CHECK_SUSPEND(upb_sink_endsubmsg(d->top->sink, subsink, arg)); - ) - VMCASE(OP_STARTSTR, - uint32_t len = (uint32_t)delim_remaining(d); - upb_pbdecoder_frame *outer = outer_frame(d); - CHECK_SUSPEND(upb_sink_startstr(outer->sink, arg, len, &d->top->sink)); - if (len == 0) { - d->pc++; /* Skip OP_STRING. */ - } - ) - VMCASE(OP_STRING, - uint32_t len = (uint32_t)curbufleft(d); - size_t n = upb_sink_putstring(d->top->sink, arg, d->ptr, len, handle); - if (n > len) { - if (n > delim_remaining(d)) { - seterr(d, "Tried to skip past end of string."); - return upb_pbdecoder_suspend(d); - } else { - int32_t ret = skip(d, n); - /* This shouldn't return DECODE_OK, because n > len. */ - UPB_ASSERT(ret >= 0); - return ret; - } - } - advance(d, n); - if (n < len || d->delim_end == NULL) { - /* We aren't finished with this string yet. */ - d->pc--; /* Repeat OP_STRING. */ - if (n > 0) checkpoint(d); - return upb_pbdecoder_suspend(d); - } - ) - VMCASE(OP_ENDSTR, - CHECK_SUSPEND(upb_sink_endstr(d->top->sink, arg)); - ) - VMCASE(OP_PUSHTAGDELIM, - CHECK_SUSPEND(pushtagdelim(d, arg)); - ) - VMCASE(OP_SETBIGGROUPNUM, - d->top->groupnum = *d->pc++; - ) - VMCASE(OP_POP, - UPB_ASSERT(d->top > d->stack); - decoder_pop(d); - ) - VMCASE(OP_PUSHLENDELIM, - uint32_t len; - CHECK_RETURN(decode_v32(d, &len)); - CHECK_SUSPEND(decoder_push(d, offset(d) + len)); - set_delim_end(d); - ) - VMCASE(OP_SETDELIM, - set_delim_end(d); - ) - VMCASE(OP_CHECKDELIM, - /* We are guaranteed of this assert because we never allow ourselves to - * consume bytes beyond data_end, which covers delim_end when non-NULL. - */ - UPB_ASSERT(!(d->delim_end && d->ptr > d->delim_end)); - if (d->ptr == d->delim_end) - d->pc += longofs; - ) - VMCASE(OP_CALL, - d->callstack[d->call_len++] = d->pc; - d->pc += longofs; - ) - VMCASE(OP_RET, - UPB_ASSERT(d->call_len > 0); - d->pc = d->callstack[--d->call_len]; - ) - VMCASE(OP_BRANCH, - d->pc += longofs; - ) - VMCASE(OP_TAG1, - uint8_t expected; - CHECK_SUSPEND(curbufleft(d) > 0); - expected = (arg >> 8) & 0xff; - if (*d->ptr == expected) { - advance(d, 1); - } else { - int8_t shortofs; - badtag: - shortofs = arg; - if (shortofs == LABEL_DISPATCH) { - CHECK_RETURN(dispatch(d)); - } else { - d->pc += shortofs; - break; /* Avoid checkpoint(). */ - } - } - ) - VMCASE(OP_TAG2, - uint16_t expected; - CHECK_SUSPEND(curbufleft(d) > 0); - expected = (arg >> 8) & 0xffff; - if (curbufleft(d) >= 2) { - uint16_t actual; - memcpy(&actual, d->ptr, 2); - if (expected == actual) { - advance(d, 2); - } else { - goto badtag; - } - } else { - int32_t result = upb_pbdecoder_checktag_slow(d, expected); - if (result == DECODE_MISMATCH) goto badtag; - if (result >= 0) return result; - } - ) - VMCASE(OP_TAGN, { - uint64_t expected; - int32_t result; - memcpy(&expected, d->pc, 8); - d->pc += 2; - result = upb_pbdecoder_checktag_slow(d, expected); - if (result == DECODE_MISMATCH) goto badtag; - if (result >= 0) return result; - }) - VMCASE(OP_DISPATCH, { - CHECK_RETURN(dispatch(d)); - }) - VMCASE(OP_HALT, { - return d->size_param; - }) - } - } -} - - -/* BytesHandler handlers ******************************************************/ - -void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { - upb_pbdecoder *d = closure; - UPB_UNUSED(size_hint); - d->top->end_ofs = UINT64_MAX; - d->bufstart_ofs = 0; - d->call_len = 1; - d->callstack[0] = &halt; - d->pc = pc; - d->skip = 0; - return d; -} - -bool upb_pbdecoder_end(void *closure, const void *handler_data) { - upb_pbdecoder *d = closure; - const upb_pbdecodermethod *method = handler_data; - uint64_t end; - char dummy; - - if (d->residual_end > d->residual) { - seterr(d, "Unexpected EOF: decoder still has buffered unparsed data"); - return false; - } - - if (d->skip) { - seterr(d, "Unexpected EOF inside skipped data"); - return false; - } - - if (d->top->end_ofs != UINT64_MAX) { - seterr(d, "Unexpected EOF inside delimited string"); - return false; - } - - /* The user's end() call indicates that the message ends here. */ - end = offset(d); - d->top->end_ofs = end; - - { - const uint32_t *p = d->pc; - d->stack->end_ofs = end; - /* Check the previous bytecode, but guard against beginning. */ - if (p != method->code_base.ptr) p--; - if (getop(*p) == OP_CHECKDELIM) { - /* Rewind from OP_TAG* to OP_CHECKDELIM. */ - UPB_ASSERT(getop(*d->pc) == OP_TAG1 || - getop(*d->pc) == OP_TAG2 || - getop(*d->pc) == OP_TAGN || - getop(*d->pc) == OP_DISPATCH); - d->pc = p; - } - upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL); - } - - if (d->call_len != 0) { - seterr(d, "Unexpected EOF inside submessage or group"); - return false; - } - - return true; -} - -size_t upb_pbdecoder_decode(void *decoder, const void *group, const char *buf, - size_t size, const upb_bufhandle *handle) { - int32_t result = upb_pbdecoder_resume(decoder, NULL, buf, size, handle); - - if (result == DECODE_ENDGROUP) goto_endmsg(decoder); - CHECK_RETURN(result); - - return run_decoder_vm(decoder, group, handle); -} - - -/* Public API *****************************************************************/ - -void upb_pbdecoder_reset(upb_pbdecoder *d) { - d->top = d->stack; - d->top->groupnum = 0; - d->ptr = d->residual; - d->buf = d->residual; - d->end = d->residual; - d->residual_end = d->residual; -} - -upb_pbdecoder *upb_pbdecoder_create(upb_arena *a, const upb_pbdecodermethod *m, - upb_sink sink, upb_status *status) { - const size_t default_max_nesting = 64; - - upb_pbdecoder *d = upb_arena_malloc(a, sizeof(upb_pbdecoder)); - if (!d) return NULL; - - d->method_ = m; - d->callstack = upb_arena_malloc(a, callstacksize(d, default_max_nesting)); - d->stack = upb_arena_malloc(a, stacksize(d, default_max_nesting)); - if (!d->stack || !d->callstack) { - return NULL; - } - - d->arena = a; - d->limit = d->stack + default_max_nesting - 1; - d->stack_size = default_max_nesting; - d->status = status; - - upb_pbdecoder_reset(d); - upb_bytessink_reset(&d->input_, &m->input_handler_, d); - - if (d->method_->dest_handlers_) { - if (sink.handlers != d->method_->dest_handlers_) - return NULL; - } - d->top->sink = sink; - - return d; -} - -uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d) { - return offset(d); -} - -const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) { - return d->method_; -} - -upb_bytessink upb_pbdecoder_input(upb_pbdecoder *d) { - return d->input_; -} - -size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d) { - return d->stack_size; -} - -bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max) { - UPB_ASSERT(d->top >= d->stack); - - if (max < (size_t)(d->top - d->stack)) { - /* Can't set a limit smaller than what we are currently at. */ - return false; - } - - if (max > d->stack_size) { - /* Need to reallocate stack and callstack to accommodate. */ - size_t old_size = stacksize(d, d->stack_size); - size_t new_size = stacksize(d, max); - void *p = upb_arena_realloc(d->arena, d->stack, old_size, new_size); - if (!p) { - return false; - } - d->stack = p; - - old_size = callstacksize(d, d->stack_size); - new_size = callstacksize(d, max); - p = upb_arena_realloc(d->arena, d->callstack, old_size, new_size); - if (!p) { - return false; - } - d->callstack = p; - - d->stack_size = max; - } - - d->limit = d->stack + max - 1; - return true; -} -/* -** upb::Encoder -** -** Since we are implementing pure handlers (ie. without any out-of-band access -** to pre-computed lengths), we have to buffer all submessages before we can -** emit even their first byte. -** -** Not knowing the size of submessages also means we can't write a perfect -** zero-copy implementation, even with buffering. Lengths are stored as -** varints, which means that we don't know how many bytes to reserve for the -** length until we know what the length is. -** -** This leaves us with three main choices: -** -** 1. buffer all submessage data in a temporary buffer, then copy it exactly -** once into the output buffer. -** -** 2. attempt to buffer data directly into the output buffer, estimating how -** many bytes each length will take. When our guesses are wrong, use -** memmove() to grow or shrink the allotted space. -** -** 3. buffer directly into the output buffer, allocating a max length -** ahead-of-time for each submessage length. If we overallocated, we waste -** space, but no memcpy() or memmove() is required. This approach requires -** defining a maximum size for submessages and rejecting submessages that -** exceed that size. -** -** (2) and (3) have the potential to have better performance, but they are more -** complicated and subtle to implement: -** -** (3) requires making an arbitrary choice of the maximum message size; it -** wastes space when submessages are shorter than this and fails -** completely when they are longer. This makes it more finicky and -** requires configuration based on the input. It also makes it impossible -** to perfectly match the output of reference encoders that always use the -** optimal amount of space for each length. -** -** (2) requires guessing the the size upfront, and if multiple lengths are -** guessed wrong the minimum required number of memmove() operations may -** be complicated to compute correctly. Implemented properly, it may have -** a useful amortized or average cost, but more investigation is required -** to determine this and what the optimal algorithm is to achieve it. -** -** (1) makes you always pay for exactly one copy, but its implementation is -** the simplest and its performance is predictable. -** -** So for now, we implement (1) only. If we wish to optimize later, we should -** be able to do it without affecting users. -** -** The strategy is to buffer the segments of data that do *not* depend on -** unknown lengths in one buffer, and keep a separate buffer of segment pointers -** and lengths. When the top-level submessage ends, we can go beginning to end, -** alternating the writing of lengths with memcpy() of the rest of the data. -** At the top level though, no buffering is required. -*/ - - - -/* The output buffer is divided into segments; a segment is a string of data - * that is "ready to go" -- it does not need any varint lengths inserted into - * the middle. The seams between segments are where varints will be inserted - * once they are known. - * - * We also use the concept of a "run", which is a range of encoded bytes that - * occur at a single submessage level. Every segment contains one or more runs. - * - * A segment can span messages. Consider: - * - * .--Submessage lengths---------. - * | | | - * | V V - * V | |--------------- | |----------------- - * Submessages: | |----------------------------------------------- - * Top-level msg: ------------------------------------------------------------ - * - * Segments: ----- ------------------- ----------------- - * Runs: *---- *--------------*--- *---------------- - * (* marks the start) - * - * Note that the top-level menssage is not in any segment because it does not - * have any length preceding it. - * - * A segment is only interrupted when another length needs to be inserted. So - * observe how the second segment spans both the inner submessage and part of - * the next enclosing message. */ -typedef struct { - uint32_t msglen; /* The length to varint-encode before this segment. */ - uint32_t seglen; /* Length of the segment. */ -} upb_pb_encoder_segment; - -struct upb_pb_encoder { - upb_arena *arena; - - /* Our input and output. */ - upb_sink input_; - upb_bytessink output_; - - /* The "subclosure" -- used as the inner closure as part of the bytessink - * protocol. */ - void *subc; - - /* The output buffer and limit, and our current write position. "buf" - * initially points to "initbuf", but is dynamically allocated if we need to - * grow beyond the initial size. */ - char *buf, *ptr, *limit; - - /* The beginning of the current run, or undefined if we are at the top - * level. */ - char *runbegin; - - /* The list of segments we are accumulating. */ - upb_pb_encoder_segment *segbuf, *segptr, *seglimit; - - /* The stack of enclosing submessages. Each entry in the stack points to the - * segment where this submessage's length is being accumulated. */ - int *stack, *top, *stacklimit; - - /* Depth of startmsg/endmsg calls. */ - int depth; -}; - -/* low-level buffering ********************************************************/ - -/* Low-level functions for interacting with the output buffer. */ - -/* TODO(haberman): handle pushback */ -static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) { - size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL); - UPB_ASSERT(n == len); -} - -static upb_pb_encoder_segment *top(upb_pb_encoder *e) { - return &e->segbuf[*e->top]; -} - -/* Call to ensure that at least "bytes" bytes are available for writing at - * e->ptr. Returns false if the bytes could not be allocated. */ -static bool reserve(upb_pb_encoder *e, size_t bytes) { - if ((size_t)(e->limit - e->ptr) < bytes) { - /* Grow buffer. */ - char *new_buf; - size_t needed = bytes + (e->ptr - e->buf); - size_t old_size = e->limit - e->buf; - - size_t new_size = old_size; - - while (new_size < needed) { - new_size *= 2; - } - - new_buf = upb_arena_realloc(e->arena, e->buf, old_size, new_size); - - if (new_buf == NULL) { - return false; - } - - e->ptr = new_buf + (e->ptr - e->buf); - e->runbegin = new_buf + (e->runbegin - e->buf); - e->limit = new_buf + new_size; - e->buf = new_buf; - } - - return true; -} - -/* Call when "bytes" bytes have been writte at e->ptr. The caller *must* have - * previously called reserve() with at least this many bytes. */ -static void encoder_advance(upb_pb_encoder *e, size_t bytes) { - UPB_ASSERT((size_t)(e->limit - e->ptr) >= bytes); - e->ptr += bytes; -} - -/* Call when all of the bytes for a handler have been written. Flushes the - * bytes if possible and necessary, returning false if this failed. */ -static bool commit(upb_pb_encoder *e) { - if (!e->top) { - /* We aren't inside a delimited region. Flush our accumulated bytes to - * the output. - * - * TODO(haberman): in the future we may want to delay flushing for - * efficiency reasons. */ - putbuf(e, e->buf, e->ptr - e->buf); - e->ptr = e->buf; - } - - return true; -} - -/* Writes the given bytes to the buffer, handling reserve/advance. */ -static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) { - if (!reserve(e, len)) { - return false; - } - - memcpy(e->ptr, data, len); - encoder_advance(e, len); - return true; -} - -/* Finish the current run by adding the run totals to the segment and message - * length. */ -static void accumulate(upb_pb_encoder *e) { - size_t run_len; - UPB_ASSERT(e->ptr >= e->runbegin); - run_len = e->ptr - e->runbegin; - e->segptr->seglen += run_len; - top(e)->msglen += run_len; - e->runbegin = e->ptr; -} - -/* Call to indicate the start of delimited region for which the full length is - * not yet known. All data will be buffered until the length is known. - * Delimited regions may be nested; their lengths will all be tracked properly. */ -static bool start_delim(upb_pb_encoder *e) { - if (e->top) { - /* We are already buffering, advance to the next segment and push it on the - * stack. */ - accumulate(e); - - if (++e->top == e->stacklimit) { - /* TODO(haberman): grow stack? */ - return false; - } - - if (++e->segptr == e->seglimit) { - /* Grow segment buffer. */ - size_t old_size = - (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment); - size_t new_size = old_size * 2; - upb_pb_encoder_segment *new_buf = - upb_arena_realloc(e->arena, e->segbuf, old_size, new_size); - - if (new_buf == NULL) { - return false; - } - - e->segptr = new_buf + (e->segptr - e->segbuf); - e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment)); - e->segbuf = new_buf; - } - } else { - /* We were previously at the top level, start buffering. */ - e->segptr = e->segbuf; - e->top = e->stack; - e->runbegin = e->ptr; - } - - *e->top = (int)(e->segptr - e->segbuf); - e->segptr->seglen = 0; - e->segptr->msglen = 0; - - return true; -} - -/* Call to indicate the end of a delimited region. We now know the length of - * the delimited region. If we are not nested inside any other delimited - * regions, we can now emit all of the buffered data we accumulated. */ -static bool end_delim(upb_pb_encoder *e) { - size_t msglen; - accumulate(e); - msglen = top(e)->msglen; - - if (e->top == e->stack) { - /* All lengths are now available, emit all buffered data. */ - char buf[UPB_PB_VARINT_MAX_LEN]; - upb_pb_encoder_segment *s; - const char *ptr = e->buf; - for (s = e->segbuf; s <= e->segptr; s++) { - size_t lenbytes = upb_vencode64(s->msglen, buf); - putbuf(e, buf, lenbytes); - putbuf(e, ptr, s->seglen); - ptr += s->seglen; - } - - e->ptr = e->buf; - e->top = NULL; - } else { - /* Need to keep buffering; propagate length info into enclosing - * submessages. */ - --e->top; - top(e)->msglen += msglen + upb_varint_size(msglen); - } - - return true; -} - - -/* tag_t **********************************************************************/ - -/* A precomputed (pre-encoded) tag and length. */ - -typedef struct { - uint8_t bytes; - char tag[7]; -} tag_t; - -/* Allocates a new tag for this field, and sets it in these handlerattr. */ -static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt, - upb_handlerattr *attr) { - uint32_t n = upb_fielddef_number(f); - - tag_t *tag = upb_gmalloc(sizeof(tag_t)); - tag->bytes = upb_vencode64((n << 3) | wt, tag->tag); - - attr->handler_data = tag; - upb_handlers_addcleanup(h, tag, upb_gfree); -} - -static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) { - return encode_bytes(e, tag->tag, tag->bytes); -} - - -/* encoding of wire types *****************************************************/ - -static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) { - /* TODO(haberman): byte-swap for big endian. */ - return encode_bytes(e, &val, sizeof(uint64_t)); -} - -static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) { - /* TODO(haberman): byte-swap for big endian. */ - return encode_bytes(e, &val, sizeof(uint32_t)); -} - -static bool encode_varint(upb_pb_encoder *e, uint64_t val) { - if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) { - return false; - } - - encoder_advance(e, upb_vencode64(val, e->ptr)); - return true; -} - -static uint64_t dbl2uint64(double d) { - uint64_t ret; - memcpy(&ret, &d, sizeof(uint64_t)); - return ret; -} - -static uint32_t flt2uint32(float d) { - uint32_t ret; - memcpy(&ret, &d, sizeof(uint32_t)); - return ret; -} - - -/* encoding of proto types ****************************************************/ - -static bool startmsg(void *c, const void *hd) { - upb_pb_encoder *e = c; - UPB_UNUSED(hd); - if (e->depth++ == 0) { - upb_bytessink_start(e->output_, 0, &e->subc); - } - return true; -} - -static bool endmsg(void *c, const void *hd, upb_status *status) { - upb_pb_encoder *e = c; - UPB_UNUSED(hd); - UPB_UNUSED(status); - if (--e->depth == 0) { - upb_bytessink_end(e->output_); - } - return true; -} - -static void *encode_startdelimfield(void *c, const void *hd) { - bool ok = encode_tag(c, hd) && commit(c) && start_delim(c); - return ok ? c : UPB_BREAK; -} - -static bool encode_unknown(void *c, const void *hd, const char *buf, - size_t len) { - UPB_UNUSED(hd); - return encode_bytes(c, buf, len) && commit(c); -} - -static bool encode_enddelimfield(void *c, const void *hd) { - UPB_UNUSED(hd); - return end_delim(c); -} - -static void *encode_startgroup(void *c, const void *hd) { - return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK; -} - -static bool encode_endgroup(void *c, const void *hd) { - return encode_tag(c, hd) && commit(c); -} - -static void *encode_startstr(void *c, const void *hd, size_t size_hint) { - UPB_UNUSED(size_hint); - return encode_startdelimfield(c, hd); -} - -static size_t encode_strbuf(void *c, const void *hd, const char *buf, - size_t len, const upb_bufhandle *h) { - UPB_UNUSED(hd); - UPB_UNUSED(h); - return encode_bytes(c, buf, len) ? len : 0; -} - -#define T(type, ctype, convert, encode) \ - static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \ - return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e); \ - } \ - static bool encode_packed_##type(void *e, const void *hd, ctype val) { \ - UPB_UNUSED(hd); \ - return encode(e, (convert)(val)); \ - } - -T(double, double, dbl2uint64, encode_fixed64) -T(float, float, flt2uint32, encode_fixed32) -T(int64, int64_t, uint64_t, encode_varint) -T(int32, int32_t, int64_t, encode_varint) -T(fixed64, uint64_t, uint64_t, encode_fixed64) -T(fixed32, uint32_t, uint32_t, encode_fixed32) -T(bool, bool, bool, encode_varint) -T(uint32, uint32_t, uint32_t, encode_varint) -T(uint64, uint64_t, uint64_t, encode_varint) -T(enum, int32_t, uint32_t, encode_varint) -T(sfixed32, int32_t, uint32_t, encode_fixed32) -T(sfixed64, int64_t, uint64_t, encode_fixed64) -T(sint32, int32_t, upb_zzenc_32, encode_varint) -T(sint64, int64_t, upb_zzenc_64, encode_varint) - -#undef T - - -/* code to build the handlers *************************************************/ - -#include -static void newhandlers_callback(const void *closure, upb_handlers *h) { - const upb_msgdef *m; - upb_msg_field_iter i; - - UPB_UNUSED(closure); - - upb_handlers_setstartmsg(h, startmsg, NULL); - upb_handlers_setendmsg(h, endmsg, NULL); - upb_handlers_setunknown(h, encode_unknown, NULL); - - m = upb_handlers_msgdef(h); - for(upb_msg_field_begin(&i, m); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) && - upb_fielddef_packed(f); - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - upb_wiretype_t wt = - packed ? UPB_WIRE_TYPE_DELIMITED - : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)]; - - /* Pre-encode the tag for this field. */ - new_tag(h, f, wt, &attr); - - if (packed) { - upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr); - upb_handlers_setendseq(h, f, encode_enddelimfield, &attr); - } - -#define T(upper, lower, upbtype) \ - case UPB_DESCRIPTOR_TYPE_##upper: \ - if (packed) { \ - upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \ - } else { \ - upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \ - } \ - break; - - switch (upb_fielddef_descriptortype(f)) { - T(DOUBLE, double, double); - T(FLOAT, float, float); - T(INT64, int64, int64); - T(INT32, int32, int32); - T(FIXED64, fixed64, uint64); - T(FIXED32, fixed32, uint32); - T(BOOL, bool, bool); - T(UINT32, uint32, uint32); - T(UINT64, uint64, uint64); - T(ENUM, enum, int32); - T(SFIXED32, sfixed32, int32); - T(SFIXED64, sfixed64, int64); - T(SINT32, sint32, int32); - T(SINT64, sint64, int64); - case UPB_DESCRIPTOR_TYPE_STRING: - case UPB_DESCRIPTOR_TYPE_BYTES: - upb_handlers_setstartstr(h, f, encode_startstr, &attr); - upb_handlers_setendstr(h, f, encode_enddelimfield, &attr); - upb_handlers_setstring(h, f, encode_strbuf, &attr); - break; - case UPB_DESCRIPTOR_TYPE_MESSAGE: - upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr); - upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr); - break; - case UPB_DESCRIPTOR_TYPE_GROUP: { - /* Endgroup takes a different tag (wire_type = END_GROUP). */ - upb_handlerattr attr2 = UPB_HANDLERATTR_INIT; - new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2); - - upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr); - upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2); - - break; - } - } - -#undef T - } -} - -void upb_pb_encoder_reset(upb_pb_encoder *e) { - e->segptr = NULL; - e->top = NULL; - e->depth = 0; -} - - -/* public API *****************************************************************/ - -upb_handlercache *upb_pb_encoder_newcache(void) { - return upb_handlercache_new(newhandlers_callback, NULL); -} - -upb_pb_encoder *upb_pb_encoder_create(upb_arena *arena, const upb_handlers *h, - upb_bytessink output) { - const size_t initial_bufsize = 256; - const size_t initial_segbufsize = 16; - /* TODO(haberman): make this configurable. */ - const size_t stack_size = 64; - - upb_pb_encoder *e = upb_arena_malloc(arena, sizeof(upb_pb_encoder)); - if (!e) return NULL; - - e->buf = upb_arena_malloc(arena, initial_bufsize); - e->segbuf = upb_arena_malloc(arena, initial_segbufsize * sizeof(*e->segbuf)); - e->stack = upb_arena_malloc(arena, stack_size * sizeof(*e->stack)); - - if (!e->buf || !e->segbuf || !e->stack) { - return NULL; - } - - e->limit = e->buf + initial_bufsize; - e->seglimit = e->segbuf + initial_segbufsize; - e->stacklimit = e->stack + stack_size; - - upb_pb_encoder_reset(e); - upb_sink_reset(&e->input_, h, e); - - e->arena = arena; - e->output_ = output; - e->subc = output.closure; - e->ptr = e->buf; - - return e; -} - -upb_sink upb_pb_encoder_input(upb_pb_encoder *e) { return e->input_; } -/* - * upb::pb::TextPrinter - * - * OPT: This is not optimized at all. It uses printf() which parses the format - * string every time, and it allocates memory for every put. - */ - - -#include -#include -#include -#include -#include -#include - - - -struct upb_textprinter { - upb_sink input_; - upb_bytessink output_; - int indent_depth_; - bool single_line_; - void *subc; -}; - -#define CHECK(x) if ((x) < 0) goto err; - -static const char *shortname(const char *longname) { - const char *last = strrchr(longname, '.'); - return last ? last + 1 : longname; -} - -static int indent(upb_textprinter *p) { - int i; - if (!p->single_line_) - for (i = 0; i < p->indent_depth_; i++) - upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL); - return 0; -} - -static int endfield(upb_textprinter *p) { - const char ch = (p->single_line_ ? ' ' : '\n'); - upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL); - return 0; -} - -static int putescaped(upb_textprinter *p, const char *buf, size_t len, - bool preserve_utf8) { - /* Based on CEscapeInternal() from Google's protobuf release. */ - char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); - const char *end = buf + len; - - /* I think hex is prettier and more useful, but proto2 uses octal; should - * investigate whether it can parse hex also. */ - const bool use_hex = false; - bool last_hex_escape = false; /* true if last output char was \xNN */ - - for (; buf < end; buf++) { - bool is_hex_escape; - - if (dstend - dst < 4) { - upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); - dst = dstbuf; - } - - is_hex_escape = false; - switch (*buf) { - case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break; - case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break; - case '\t': *(dst++) = '\\'; *(dst++) = 't'; break; - case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break; - case '\'': *(dst++) = '\\'; *(dst++) = '\''; break; - case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break; - default: - /* Note that if we emit \xNN and the buf character after that is a hex - * digit then that digit must be escaped too to prevent it being - * interpreted as part of the character code by C. */ - if ((!preserve_utf8 || (uint8_t)*buf < 0x80) && - (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) { - sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf); - is_hex_escape = use_hex; - dst += 4; - } else { - *(dst++) = *buf; break; - } - } - last_hex_escape = is_hex_escape; - } - /* Flush remaining data. */ - upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); - return 0; -} - -bool putf(upb_textprinter *p, const char *fmt, ...) { - va_list args; - va_list args_copy; - char *str; - int written; - int len; - bool ok; - - va_start(args, fmt); - - /* Run once to get the length of the string. */ - _upb_va_copy(args_copy, args); - len = _upb_vsnprintf(NULL, 0, fmt, args_copy); - va_end(args_copy); - - /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */ - str = upb_gmalloc(len + 1); - if (!str) return false; - written = vsprintf(str, fmt, args); - va_end(args); - UPB_ASSERT(written == len); - - ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL); - upb_gfree(str); - return ok; -} - - -/* handlers *******************************************************************/ - -static bool textprinter_startmsg(void *c, const void *hd) { - upb_textprinter *p = c; - UPB_UNUSED(hd); - if (p->indent_depth_ == 0) { - upb_bytessink_start(p->output_, 0, &p->subc); - } - return true; -} - -static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) { - upb_textprinter *p = c; - UPB_UNUSED(hd); - UPB_UNUSED(s); - if (p->indent_depth_ == 0) { - upb_bytessink_end(p->output_); - } - return true; -} - -#define TYPE(name, ctype, fmt) \ - static bool textprinter_put ## name(void *closure, const void *handler_data, \ - ctype val) { \ - upb_textprinter *p = closure; \ - const upb_fielddef *f = handler_data; \ - CHECK(indent(p)); \ - putf(p, "%s: " fmt, upb_fielddef_name(f), val); \ - CHECK(endfield(p)); \ - return true; \ - err: \ - return false; \ -} - -static bool textprinter_putbool(void *closure, const void *handler_data, - bool val) { - upb_textprinter *p = closure; - const upb_fielddef *f = handler_data; - CHECK(indent(p)); - putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false"); - CHECK(endfield(p)); - return true; -err: - return false; -} - -#define STRINGIFY_HELPER(x) #x -#define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x) - -TYPE(int32, int32_t, "%" PRId32) -TYPE(int64, int64_t, "%" PRId64) -TYPE(uint32, uint32_t, "%" PRIu32) -TYPE(uint64, uint64_t, "%" PRIu64) -TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g") -TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") - -#undef TYPE - -/* Output a symbolic value from the enum if found, else just print as int32. */ -static bool textprinter_putenum(void *closure, const void *handler_data, - int32_t val) { - upb_textprinter *p = closure; - const upb_fielddef *f = handler_data; - const upb_enumdef *enum_def = upb_fielddef_enumsubdef(f); - const char *label = upb_enumdef_iton(enum_def, val); - if (label) { - indent(p); - putf(p, "%s: %s", upb_fielddef_name(f), label); - endfield(p); - } else { - if (!textprinter_putint32(closure, handler_data, val)) - return false; - } - return true; -} - -static void *textprinter_startstr(void *closure, const void *handler_data, - size_t size_hint) { - upb_textprinter *p = closure; - const upb_fielddef *f = handler_data; - UPB_UNUSED(size_hint); - indent(p); - putf(p, "%s: \"", upb_fielddef_name(f)); - return p; -} - -static bool textprinter_endstr(void *closure, const void *handler_data) { - upb_textprinter *p = closure; - UPB_UNUSED(handler_data); - putf(p, "\""); - endfield(p); - return true; -} - -static size_t textprinter_putstr(void *closure, const void *hd, const char *buf, - size_t len, const upb_bufhandle *handle) { - upb_textprinter *p = closure; - const upb_fielddef *f = hd; - UPB_UNUSED(handle); - CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING)); - return len; -err: - return 0; -} - -static void *textprinter_startsubmsg(void *closure, const void *handler_data) { - upb_textprinter *p = closure; - const char *name = handler_data; - CHECK(indent(p)); - putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n'); - p->indent_depth_++; - return p; -err: - return UPB_BREAK; -} - -static bool textprinter_endsubmsg(void *closure, const void *handler_data) { - upb_textprinter *p = closure; - UPB_UNUSED(handler_data); - p->indent_depth_--; - CHECK(indent(p)); - upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL); - CHECK(endfield(p)); - return true; -err: - return false; -} - -static void onmreg(const void *c, upb_handlers *h) { - const upb_msgdef *m = upb_handlers_msgdef(h); - upb_msg_field_iter i; - UPB_UNUSED(c); - - upb_handlers_setstartmsg(h, textprinter_startmsg, NULL); - upb_handlers_setendmsg(h, textprinter_endmsg, NULL); - - for(upb_msg_field_begin(&i, m); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - upb_handlerattr attr = UPB_HANDLERATTR_INIT; - attr.handler_data = f; - switch (upb_fielddef_type(f)) { - case UPB_TYPE_INT32: - upb_handlers_setint32(h, f, textprinter_putint32, &attr); - break; - case UPB_TYPE_INT64: - upb_handlers_setint64(h, f, textprinter_putint64, &attr); - break; - case UPB_TYPE_UINT32: - upb_handlers_setuint32(h, f, textprinter_putuint32, &attr); - break; - case UPB_TYPE_UINT64: - upb_handlers_setuint64(h, f, textprinter_putuint64, &attr); - break; - case UPB_TYPE_FLOAT: - upb_handlers_setfloat(h, f, textprinter_putfloat, &attr); - break; - case UPB_TYPE_DOUBLE: - upb_handlers_setdouble(h, f, textprinter_putdouble, &attr); - break; - case UPB_TYPE_BOOL: - upb_handlers_setbool(h, f, textprinter_putbool, &attr); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - upb_handlers_setstartstr(h, f, textprinter_startstr, &attr); - upb_handlers_setstring(h, f, textprinter_putstr, &attr); - upb_handlers_setendstr(h, f, textprinter_endstr, &attr); - break; - case UPB_TYPE_MESSAGE: { - const char *name = - upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_GROUP - ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f))) - : upb_fielddef_name(f); - attr.handler_data = name; - upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr); - upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr); - break; - } - case UPB_TYPE_ENUM: - upb_handlers_setint32(h, f, textprinter_putenum, &attr); - break; - } - } -} - -static void textprinter_reset(upb_textprinter *p, bool single_line) { - p->single_line_ = single_line; - p->indent_depth_ = 0; -} - - -/* Public API *****************************************************************/ - -upb_textprinter *upb_textprinter_create(upb_arena *arena, const upb_handlers *h, - upb_bytessink output) { - upb_textprinter *p = upb_arena_malloc(arena, sizeof(upb_textprinter)); - if (!p) return NULL; - - p->output_ = output; - upb_sink_reset(&p->input_, h, p); - textprinter_reset(p, false); - - return p; -} - -upb_handlercache *upb_textprinter_newcache(void) { - return upb_handlercache_new(&onmreg, NULL); -} - -upb_sink upb_textprinter_input(upb_textprinter *p) { return p->input_; } - -void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) { - p->single_line_ = single_line; -} - - -/* Index is descriptor type. */ -const uint8_t upb_pb_native_wire_types[] = { - UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */ - UPB_WIRE_TYPE_64BIT, /* DOUBLE */ - UPB_WIRE_TYPE_32BIT, /* FLOAT */ - UPB_WIRE_TYPE_VARINT, /* INT64 */ - UPB_WIRE_TYPE_VARINT, /* UINT64 */ - UPB_WIRE_TYPE_VARINT, /* INT32 */ - UPB_WIRE_TYPE_64BIT, /* FIXED64 */ - UPB_WIRE_TYPE_32BIT, /* FIXED32 */ - UPB_WIRE_TYPE_VARINT, /* BOOL */ - UPB_WIRE_TYPE_DELIMITED, /* STRING */ - UPB_WIRE_TYPE_START_GROUP, /* GROUP */ - UPB_WIRE_TYPE_DELIMITED, /* MESSAGE */ - UPB_WIRE_TYPE_DELIMITED, /* BYTES */ - UPB_WIRE_TYPE_VARINT, /* UINT32 */ - UPB_WIRE_TYPE_VARINT, /* ENUM */ - UPB_WIRE_TYPE_32BIT, /* SFIXED32 */ - UPB_WIRE_TYPE_64BIT, /* SFIXED64 */ - UPB_WIRE_TYPE_VARINT, /* SINT32 */ - UPB_WIRE_TYPE_VARINT, /* SINT64 */ -}; - -/* A basic branch-based decoder, uses 32-bit values to get good performance - * on 32-bit architectures (but performs well on 64-bits also). - * This scheme comes from the original Google Protobuf implementation - * (proto2). */ -upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) { - upb_decoderet err = {NULL, 0}; - const char *p = r.p; - uint32_t low = (uint32_t)r.val; - uint32_t high = 0; - uint32_t b; - b = *(p++); low |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done; - b = *(p++); low |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done; - b = *(p++); low |= (b & 0x7fU) << 28; - high = (b & 0x7fU) >> 4; if (!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7fU) << 3; if (!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done; - b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done; - return err; - -done: - r.val = ((uint64_t)high << 32) | low; - r.p = p; - return r; -} - -/* Like the previous, but uses 64-bit values. */ -upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) { - const char *p = r.p; - uint64_t val = r.val; - uint64_t b; - upb_decoderet err = {NULL, 0}; - b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done; - b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done; - b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done; - b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done; - b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done; - b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done; - b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done; - b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done; - return err; - -done: - r.val = val; - r.p = p; - return r; -} - -#line 1 "upb/json/parser.rl" -/* -** upb::json::Parser (upb_json_parser) -** -** A parser that uses the Ragel State Machine Compiler to generate -** the finite automata. -** -** Ragel only natively handles regular languages, but we can manually -** program it a bit to handle context-free languages like JSON, by using -** the "fcall" and "fret" constructs. -** -** This parser can handle the basics, but needs several things to be fleshed -** out: -** -** - handling of unicode escape sequences (including high surrogate pairs). -** - properly check and report errors for unknown fields, stack overflow, -** improper array nesting (or lack of nesting). -** - handling of base64 sequences with padding characters. -** - handling of push-back (non-success returns from sink functions). -** - handling of keys/escape-sequences/etc that span input buffers. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - - -#define UPB_JSON_MAX_DEPTH 64 - -/* Type of value message */ -enum { - VALUE_NULLVALUE = 0, - VALUE_NUMBERVALUE = 1, - VALUE_STRINGVALUE = 2, - VALUE_BOOLVALUE = 3, - VALUE_STRUCTVALUE = 4, - VALUE_LISTVALUE = 5 -}; - -/* Forward declare */ -static bool is_top_level(upb_json_parser *p); -static bool is_wellknown_msg(upb_json_parser *p, upb_wellknowntype_t type); -static bool is_wellknown_field(upb_json_parser *p, upb_wellknowntype_t type); - -static bool is_number_wrapper_object(upb_json_parser *p); -static bool does_number_wrapper_start(upb_json_parser *p); -static bool does_number_wrapper_end(upb_json_parser *p); - -static bool is_string_wrapper_object(upb_json_parser *p); -static bool does_string_wrapper_start(upb_json_parser *p); -static bool does_string_wrapper_end(upb_json_parser *p); - -static bool does_fieldmask_start(upb_json_parser *p); -static bool does_fieldmask_end(upb_json_parser *p); -static void start_fieldmask_object(upb_json_parser *p); -static void end_fieldmask_object(upb_json_parser *p); - -static void start_wrapper_object(upb_json_parser *p); -static void end_wrapper_object(upb_json_parser *p); - -static void start_value_object(upb_json_parser *p, int value_type); -static void end_value_object(upb_json_parser *p); - -static void start_listvalue_object(upb_json_parser *p); -static void end_listvalue_object(upb_json_parser *p); - -static void start_structvalue_object(upb_json_parser *p); -static void end_structvalue_object(upb_json_parser *p); - -static void start_object(upb_json_parser *p); -static void end_object(upb_json_parser *p); - -static void start_any_object(upb_json_parser *p, const char *ptr); -static bool end_any_object(upb_json_parser *p, const char *ptr); - -static bool start_subobject(upb_json_parser *p); -static void end_subobject(upb_json_parser *p); - -static void start_member(upb_json_parser *p); -static void end_member(upb_json_parser *p); -static bool end_membername(upb_json_parser *p); - -static void start_any_member(upb_json_parser *p, const char *ptr); -static void end_any_member(upb_json_parser *p, const char *ptr); -static bool end_any_membername(upb_json_parser *p); - -size_t parse(void *closure, const void *hd, const char *buf, size_t size, - const upb_bufhandle *handle); -static bool end(void *closure, const void *hd); - -static const char eof_ch = 'e'; - -/* stringsink */ -typedef struct { - upb_byteshandler handler; - upb_bytessink sink; - char *ptr; - size_t len, size; -} upb_stringsink; - - -static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { - upb_stringsink *sink = _sink; - sink->len = 0; - UPB_UNUSED(hd); - UPB_UNUSED(size_hint); - return sink; -} - -static size_t stringsink_string(void *_sink, const void *hd, const char *ptr, - size_t len, const upb_bufhandle *handle) { - upb_stringsink *sink = _sink; - size_t new_size = sink->size; - - UPB_UNUSED(hd); - UPB_UNUSED(handle); - - while (sink->len + len > new_size) { - new_size *= 2; - } - - if (new_size != sink->size) { - sink->ptr = realloc(sink->ptr, new_size); - sink->size = new_size; - } - - memcpy(sink->ptr + sink->len, ptr, len); - sink->len += len; - - return len; -} - -void upb_stringsink_init(upb_stringsink *sink) { - upb_byteshandler_init(&sink->handler); - upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); - upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); - - upb_bytessink_reset(&sink->sink, &sink->handler, sink); - - sink->size = 32; - sink->ptr = malloc(sink->size); - sink->len = 0; -} - -void upb_stringsink_uninit(upb_stringsink *sink) { free(sink->ptr); } - -typedef struct { - /* For encoding Any value field in binary format. */ - upb_handlercache *encoder_handlercache; - upb_stringsink stringsink; - - /* For decoding Any value field in json format. */ - upb_json_codecache *parser_codecache; - upb_sink sink; - upb_json_parser *parser; - - /* Mark the range of uninterpreted values in json input before type url. */ - const char *before_type_url_start; - const char *before_type_url_end; - - /* Mark the range of uninterpreted values in json input after type url. */ - const char *after_type_url_start; -} upb_jsonparser_any_frame; - -typedef struct { - upb_sink sink; - - /* The current message in which we're parsing, and the field whose value we're - * expecting next. */ - const upb_msgdef *m; - const upb_fielddef *f; - - /* The table mapping json name to fielddef for this message. */ - const upb_strtable *name_table; - - /* We are in a repeated-field context. We need this flag to decide whether to - * handle the array as a normal repeated field or a - * google.protobuf.ListValue/google.protobuf.Value. */ - bool is_repeated; - - /* We are in a repeated-field context, ready to emit mapentries as - * submessages. This flag alters the start-of-object (open-brace) behavior to - * begin a sequence of mapentry messages rather than a single submessage. */ - bool is_map; - - /* We are in a map-entry message context. This flag is set when parsing the - * value field of a single map entry and indicates to all value-field parsers - * (subobjects, strings, numbers, and bools) that the map-entry submessage - * should end as soon as the value is parsed. */ - bool is_mapentry; - - /* If |is_map| or |is_mapentry| is true, |mapfield| refers to the parent - * message's map field that we're currently parsing. This differs from |f| - * because |f| is the field in the *current* message (i.e., the map-entry - * message itself), not the parent's field that leads to this map. */ - const upb_fielddef *mapfield; - - /* We are in an Any message context. This flag is set when parsing the Any - * message and indicates to all field parsers (subobjects, strings, numbers, - * and bools) that the parsed field should be serialized as binary data or - * cached (type url not found yet). */ - bool is_any; - - /* The type of packed message in Any. */ - upb_jsonparser_any_frame *any_frame; - - /* True if the field to be parsed is unknown. */ - bool is_unknown_field; -} upb_jsonparser_frame; - -static void init_frame(upb_jsonparser_frame* frame) { - frame->m = NULL; - frame->f = NULL; - frame->name_table = NULL; - frame->is_repeated = false; - frame->is_map = false; - frame->is_mapentry = false; - frame->mapfield = NULL; - frame->is_any = false; - frame->any_frame = NULL; - frame->is_unknown_field = false; -} - -struct upb_json_parser { - upb_arena *arena; - const upb_json_parsermethod *method; - upb_bytessink input_; - - /* Stack to track the JSON scopes we are in. */ - upb_jsonparser_frame stack[UPB_JSON_MAX_DEPTH]; - upb_jsonparser_frame *top; - upb_jsonparser_frame *limit; - - upb_status *status; - - /* Ragel's internal parsing stack for the parsing state machine. */ - int current_state; - int parser_stack[UPB_JSON_MAX_DEPTH]; - int parser_top; - - /* The handle for the current buffer. */ - const upb_bufhandle *handle; - - /* Accumulate buffer. See details in parser.rl. */ - const char *accumulated; - size_t accumulated_len; - char *accumulate_buf; - size_t accumulate_buf_size; - - /* Multi-part text data. See details in parser.rl. */ - int multipart_state; - upb_selector_t string_selector; - - /* Input capture. See details in parser.rl. */ - const char *capture; - - /* Intermediate result of parsing a unicode escape sequence. */ - uint32_t digit; - - /* For resolve type url in Any. */ - const upb_symtab *symtab; - - /* Whether to proceed if unknown field is met. */ - bool ignore_json_unknown; - - /* Cache for parsing timestamp due to base and zone are handled in different - * handlers. */ - struct tm tm; -}; - -static upb_jsonparser_frame* start_jsonparser_frame(upb_json_parser *p) { - upb_jsonparser_frame *inner; - inner = p->top + 1; - init_frame(inner); - return inner; -} - -struct upb_json_codecache { - upb_arena *arena; - upb_inttable methods; /* upb_msgdef* -> upb_json_parsermethod* */ -}; - -struct upb_json_parsermethod { - const upb_json_codecache *cache; - upb_byteshandler input_handler_; - - /* Maps json_name -> fielddef */ - upb_strtable name_table; -}; - -#define PARSER_CHECK_RETURN(x) if (!(x)) return false - -static upb_jsonparser_any_frame *json_parser_any_frame_new( - upb_json_parser *p) { - upb_jsonparser_any_frame *frame; - - frame = upb_arena_malloc(p->arena, sizeof(upb_jsonparser_any_frame)); - - frame->encoder_handlercache = upb_pb_encoder_newcache(); - frame->parser_codecache = upb_json_codecache_new(); - frame->parser = NULL; - frame->before_type_url_start = NULL; - frame->before_type_url_end = NULL; - frame->after_type_url_start = NULL; - - upb_stringsink_init(&frame->stringsink); - - return frame; -} - -static void json_parser_any_frame_set_payload_type( - upb_json_parser *p, - upb_jsonparser_any_frame *frame, - const upb_msgdef *payload_type) { - const upb_handlers *h; - const upb_json_parsermethod *parser_method; - upb_pb_encoder *encoder; - - /* Initialize encoder. */ - h = upb_handlercache_get(frame->encoder_handlercache, payload_type); - encoder = upb_pb_encoder_create(p->arena, h, frame->stringsink.sink); - - /* Initialize parser. */ - parser_method = upb_json_codecache_get(frame->parser_codecache, payload_type); - upb_sink_reset(&frame->sink, h, encoder); - frame->parser = - upb_json_parser_create(p->arena, parser_method, p->symtab, frame->sink, - p->status, p->ignore_json_unknown); -} - -static void json_parser_any_frame_free(upb_jsonparser_any_frame *frame) { - upb_handlercache_free(frame->encoder_handlercache); - upb_json_codecache_free(frame->parser_codecache); - upb_stringsink_uninit(&frame->stringsink); -} - -static bool json_parser_any_frame_has_type_url( - upb_jsonparser_any_frame *frame) { - return frame->parser != NULL; -} - -static bool json_parser_any_frame_has_value_before_type_url( - upb_jsonparser_any_frame *frame) { - return frame->before_type_url_start != frame->before_type_url_end; -} - -static bool json_parser_any_frame_has_value_after_type_url( - upb_jsonparser_any_frame *frame) { - return frame->after_type_url_start != NULL; -} - -static bool json_parser_any_frame_has_value( - upb_jsonparser_any_frame *frame) { - return json_parser_any_frame_has_value_before_type_url(frame) || - json_parser_any_frame_has_value_after_type_url(frame); -} - -static void json_parser_any_frame_set_before_type_url_end( - upb_jsonparser_any_frame *frame, - const char *ptr) { - if (frame->parser == NULL) { - frame->before_type_url_end = ptr; - } -} - -static void json_parser_any_frame_set_after_type_url_start_once( - upb_jsonparser_any_frame *frame, - const char *ptr) { - if (json_parser_any_frame_has_type_url(frame) && - frame->after_type_url_start == NULL) { - frame->after_type_url_start = ptr; - } -} - -/* Used to signal that a capture has been suspended. */ -static char suspend_capture; - -static upb_selector_t getsel_for_handlertype(upb_json_parser *p, - upb_handlertype_t type) { - upb_selector_t sel; - bool ok = upb_handlers_getselector(p->top->f, type, &sel); - UPB_ASSUME(ok); - return sel; -} - -static upb_selector_t parser_getsel(upb_json_parser *p) { - return getsel_for_handlertype( - p, upb_handlers_getprimitivehandlertype(p->top->f)); -} - -static bool check_stack(upb_json_parser *p) { - if ((p->top + 1) == p->limit) { - upb_status_seterrmsg(p->status, "Nesting too deep"); - return false; - } - - return true; -} - -static void set_name_table(upb_json_parser *p, upb_jsonparser_frame *frame) { - upb_value v; - const upb_json_codecache *cache = p->method->cache; - bool ok; - const upb_json_parsermethod *method; - - ok = upb_inttable_lookupptr(&cache->methods, frame->m, &v); - UPB_ASSUME(ok); - method = upb_value_getconstptr(v); - - frame->name_table = &method->name_table; -} - -/* There are GCC/Clang built-ins for overflow checking which we could start - * using if there was any performance benefit to it. */ - -static bool checked_add(size_t a, size_t b, size_t *c) { - if (SIZE_MAX - a < b) return false; - *c = a + b; - return true; -} - -static size_t saturating_multiply(size_t a, size_t b) { - /* size_t is unsigned, so this is defined behavior even on overflow. */ - size_t ret = a * b; - if (b != 0 && ret / b != a) { - ret = SIZE_MAX; - } - return ret; -} - - -/* Base64 decoding ************************************************************/ - -/* TODO(haberman): make this streaming. */ - -static const signed char b64table[] = { - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, - 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, - 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, - -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, - 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, - 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, - 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, - -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, - 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, - 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, - 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 -}; - -/* Returns the table value sign-extended to 32 bits. Knowing that the upper - * bits will be 1 for unrecognized characters makes it easier to check for - * this error condition later (see below). */ -int32_t b64lookup(unsigned char ch) { return b64table[ch]; } - -/* Returns true if the given character is not a valid base64 character or - * padding. */ -bool nonbase64(unsigned char ch) { return b64lookup(ch) == -1 && ch != '='; } - -static bool base64_push(upb_json_parser *p, upb_selector_t sel, const char *ptr, - size_t len) { - const char *limit = ptr + len; - for (; ptr < limit; ptr += 4) { - uint32_t val; - char output[3]; - - if (limit - ptr < 4) { - upb_status_seterrf(p->status, - "Base64 input for bytes field not a multiple of 4: %s", - upb_fielddef_name(p->top->f)); - return false; - } - - val = b64lookup(ptr[0]) << 18 | - b64lookup(ptr[1]) << 12 | - b64lookup(ptr[2]) << 6 | - b64lookup(ptr[3]); - - /* Test the upper bit; returns true if any of the characters returned -1. */ - if (val & 0x80000000) { - goto otherchar; - } - - output[0] = val >> 16; - output[1] = (val >> 8) & 0xff; - output[2] = val & 0xff; - upb_sink_putstring(p->top->sink, sel, output, 3, NULL); - } - return true; - -otherchar: - if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) || - nonbase64(ptr[3]) ) { - upb_status_seterrf(p->status, - "Non-base64 characters in bytes field: %s", - upb_fielddef_name(p->top->f)); - return false; - } if (ptr[2] == '=') { - uint32_t val; - char output; - - /* Last group contains only two input bytes, one output byte. */ - if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') { - goto badpadding; - } - - val = b64lookup(ptr[0]) << 18 | - b64lookup(ptr[1]) << 12; - - UPB_ASSERT(!(val & 0x80000000)); - output = val >> 16; - upb_sink_putstring(p->top->sink, sel, &output, 1, NULL); - return true; - } else { - uint32_t val; - char output[2]; - - /* Last group contains only three input bytes, two output bytes. */ - if (ptr[0] == '=' || ptr[1] == '=' || ptr[2] == '=') { - goto badpadding; - } - - val = b64lookup(ptr[0]) << 18 | - b64lookup(ptr[1]) << 12 | - b64lookup(ptr[2]) << 6; - - output[0] = val >> 16; - output[1] = (val >> 8) & 0xff; - upb_sink_putstring(p->top->sink, sel, output, 2, NULL); - return true; - } - -badpadding: - upb_status_seterrf(p->status, - "Incorrect base64 padding for field: %s (%.*s)", - upb_fielddef_name(p->top->f), - 4, ptr); - return false; -} - - -/* Accumulate buffer **********************************************************/ - -/* Functionality for accumulating a buffer. - * - * Some parts of the parser need an entire value as a contiguous string. For - * example, to look up a member name in a hash table, or to turn a string into - * a number, the relevant library routines need the input string to be in - * contiguous memory, even if the value spanned two or more buffers in the - * input. These routines handle that. - * - * In the common case we can just point to the input buffer to get this - * contiguous string and avoid any actual copy. So we optimistically begin - * this way. But there are a few cases where we must instead copy into a - * separate buffer: - * - * 1. The string was not contiguous in the input (it spanned buffers). - * - * 2. The string included escape sequences that need to be interpreted to get - * the true value in a contiguous buffer. */ - -static void assert_accumulate_empty(upb_json_parser *p) { - UPB_ASSERT(p->accumulated == NULL); - UPB_ASSERT(p->accumulated_len == 0); -} - -static void accumulate_clear(upb_json_parser *p) { - p->accumulated = NULL; - p->accumulated_len = 0; -} - -/* Used internally by accumulate_append(). */ -static bool accumulate_realloc(upb_json_parser *p, size_t need) { - void *mem; - size_t old_size = p->accumulate_buf_size; - size_t new_size = UPB_MAX(old_size, 128); - while (new_size < need) { - new_size = saturating_multiply(new_size, 2); - } - - mem = upb_arena_realloc(p->arena, p->accumulate_buf, old_size, new_size); - if (!mem) { - upb_status_seterrmsg(p->status, "Out of memory allocating buffer."); - return false; - } - - p->accumulate_buf = mem; - p->accumulate_buf_size = new_size; - return true; -} - -/* Logically appends the given data to the append buffer. - * If "can_alias" is true, we will try to avoid actually copying, but the buffer - * must be valid until the next accumulate_append() call (if any). */ -static bool accumulate_append(upb_json_parser *p, const char *buf, size_t len, - bool can_alias) { - size_t need; - - if (!p->accumulated && can_alias) { - p->accumulated = buf; - p->accumulated_len = len; - return true; - } - - if (!checked_add(p->accumulated_len, len, &need)) { - upb_status_seterrmsg(p->status, "Integer overflow."); - return false; - } - - if (need > p->accumulate_buf_size && !accumulate_realloc(p, need)) { - return false; - } - - if (p->accumulated != p->accumulate_buf) { - memcpy(p->accumulate_buf, p->accumulated, p->accumulated_len); - p->accumulated = p->accumulate_buf; - } - - memcpy(p->accumulate_buf + p->accumulated_len, buf, len); - p->accumulated_len += len; - return true; -} - -/* Returns a pointer to the data accumulated since the last accumulate_clear() - * call, and writes the length to *len. This with point either to the input - * buffer or a temporary accumulate buffer. */ -static const char *accumulate_getptr(upb_json_parser *p, size_t *len) { - UPB_ASSERT(p->accumulated); - *len = p->accumulated_len; - return p->accumulated; -} - - -/* Mult-part text data ********************************************************/ - -/* When we have text data in the input, it can often come in multiple segments. - * For example, there may be some raw string data followed by an escape - * sequence. The two segments are processed with different logic. Also buffer - * seams in the input can cause multiple segments. - * - * As we see segments, there are two main cases for how we want to process them: - * - * 1. we want to push the captured input directly to string handlers. - * - * 2. we need to accumulate all the parts into a contiguous buffer for further - * processing (field name lookup, string->number conversion, etc). */ - -/* This is the set of states for p->multipart_state. */ -enum { - /* We are not currently processing multipart data. */ - MULTIPART_INACTIVE = 0, - - /* We are processing multipart data by accumulating it into a contiguous - * buffer. */ - MULTIPART_ACCUMULATE = 1, - - /* We are processing multipart data by pushing each part directly to the - * current string handlers. */ - MULTIPART_PUSHEAGERLY = 2 -}; - -/* Start a multi-part text value where we accumulate the data for processing at - * the end. */ -static void multipart_startaccum(upb_json_parser *p) { - assert_accumulate_empty(p); - UPB_ASSERT(p->multipart_state == MULTIPART_INACTIVE); - p->multipart_state = MULTIPART_ACCUMULATE; -} - -/* Start a multi-part text value where we immediately push text data to a string - * value with the given selector. */ -static void multipart_start(upb_json_parser *p, upb_selector_t sel) { - assert_accumulate_empty(p); - UPB_ASSERT(p->multipart_state == MULTIPART_INACTIVE); - p->multipart_state = MULTIPART_PUSHEAGERLY; - p->string_selector = sel; -} - -static bool multipart_text(upb_json_parser *p, const char *buf, size_t len, - bool can_alias) { - switch (p->multipart_state) { - case MULTIPART_INACTIVE: - upb_status_seterrmsg( - p->status, "Internal error: unexpected state MULTIPART_INACTIVE"); - return false; - - case MULTIPART_ACCUMULATE: - if (!accumulate_append(p, buf, len, can_alias)) { - return false; - } - break; - - case MULTIPART_PUSHEAGERLY: { - const upb_bufhandle *handle = can_alias ? p->handle : NULL; - upb_sink_putstring(p->top->sink, p->string_selector, buf, len, handle); - break; - } - } - - return true; -} - -/* Note: this invalidates the accumulate buffer! Call only after reading its - * contents. */ -static void multipart_end(upb_json_parser *p) { - /* This is false sometimes. Probably a bug of some sort, but this code is - * intended for deletion soon. */ - /* UPB_ASSERT(p->multipart_state != MULTIPART_INACTIVE); */ - p->multipart_state = MULTIPART_INACTIVE; - accumulate_clear(p); -} - - -/* Input capture **************************************************************/ - -/* Functionality for capturing a region of the input as text. Gracefully - * handles the case where a buffer seam occurs in the middle of the captured - * region. */ - -static void capture_begin(upb_json_parser *p, const char *ptr) { - UPB_ASSERT(p->multipart_state != MULTIPART_INACTIVE); - UPB_ASSERT(p->capture == NULL); - p->capture = ptr; -} - -static bool capture_end(upb_json_parser *p, const char *ptr) { - UPB_ASSERT(p->capture); - if (multipart_text(p, p->capture, ptr - p->capture, true)) { - p->capture = NULL; - return true; - } else { - return false; - } -} - -/* This is called at the end of each input buffer (ie. when we have hit a - * buffer seam). If we are in the middle of capturing the input, this - * processes the unprocessed capture region. */ -static void capture_suspend(upb_json_parser *p, const char **ptr) { - if (!p->capture) return; - - if (multipart_text(p, p->capture, *ptr - p->capture, false)) { - /* We use this as a signal that we were in the middle of capturing, and - * that capturing should resume at the beginning of the next buffer. - * - * We can't use *ptr here, because we have no guarantee that this pointer - * will be valid when we resume (if the underlying memory is freed, then - * using the pointer at all, even to compare to NULL, is likely undefined - * behavior). */ - p->capture = &suspend_capture; - } else { - /* Need to back up the pointer to the beginning of the capture, since - * we were not able to actually preserve it. */ - *ptr = p->capture; - } -} - -static void capture_resume(upb_json_parser *p, const char *ptr) { - if (p->capture) { - UPB_ASSERT(p->capture == &suspend_capture); - p->capture = ptr; - } -} - - -/* Callbacks from the parser **************************************************/ - -/* These are the functions called directly from the parser itself. - * We define these in the same order as their declarations in the parser. */ - -static char escape_char(char in) { - switch (in) { - case 'r': return '\r'; - case 't': return '\t'; - case 'n': return '\n'; - case 'f': return '\f'; - case 'b': return '\b'; - case '/': return '/'; - case '"': return '"'; - case '\\': return '\\'; - default: - UPB_ASSERT(0); - return 'x'; - } -} - -static bool escape(upb_json_parser *p, const char *ptr) { - char ch = escape_char(*ptr); - return multipart_text(p, &ch, 1, false); -} - -static void start_hex(upb_json_parser *p) { - p->digit = 0; -} - -static void hexdigit(upb_json_parser *p, const char *ptr) { - char ch = *ptr; - - p->digit <<= 4; - - if (ch >= '0' && ch <= '9') { - p->digit += (ch - '0'); - } else if (ch >= 'a' && ch <= 'f') { - p->digit += ((ch - 'a') + 10); - } else { - UPB_ASSERT(ch >= 'A' && ch <= 'F'); - p->digit += ((ch - 'A') + 10); - } -} - -static bool end_hex(upb_json_parser *p) { - uint32_t codepoint = p->digit; - - /* emit the codepoint as UTF-8. */ - char utf8[3]; /* support \u0000 -- \uFFFF -- need only three bytes. */ - int length = 0; - if (codepoint <= 0x7F) { - utf8[0] = codepoint; - length = 1; - } else if (codepoint <= 0x07FF) { - utf8[1] = (codepoint & 0x3F) | 0x80; - codepoint >>= 6; - utf8[0] = (codepoint & 0x1F) | 0xC0; - length = 2; - } else /* codepoint <= 0xFFFF */ { - utf8[2] = (codepoint & 0x3F) | 0x80; - codepoint >>= 6; - utf8[1] = (codepoint & 0x3F) | 0x80; - codepoint >>= 6; - utf8[0] = (codepoint & 0x0F) | 0xE0; - length = 3; - } - /* TODO(haberman): Handle high surrogates: if codepoint is a high surrogate - * we have to wait for the next escape to get the full code point). */ - - return multipart_text(p, utf8, length, false); -} - -static void start_text(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_text(upb_json_parser *p, const char *ptr) { - return capture_end(p, ptr); -} - -static bool start_number(upb_json_parser *p, const char *ptr) { - if (is_top_level(p)) { - if (is_number_wrapper_object(p)) { - start_wrapper_object(p); - } else if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - start_value_object(p, VALUE_NUMBERVALUE); - } else { - return false; - } - } else if (does_number_wrapper_start(p)) { - if (!start_subobject(p)) { - return false; - } - start_wrapper_object(p); - } else if (is_wellknown_field(p, UPB_WELLKNOWN_VALUE)) { - if (!start_subobject(p)) { - return false; - } - start_value_object(p, VALUE_NUMBERVALUE); - } - - multipart_startaccum(p); - capture_begin(p, ptr); - return true; -} - -static bool parse_number(upb_json_parser *p, bool is_quoted); - -static bool end_number_nontop(upb_json_parser *p, const char *ptr) { - if (!capture_end(p, ptr)) { - return false; - } - - if (p->top->f == NULL) { - multipart_end(p); - return true; - } - - return parse_number(p, false); -} - -static bool end_number(upb_json_parser *p, const char *ptr) { - if (!end_number_nontop(p, ptr)) { - return false; - } - - if (does_number_wrapper_end(p)) { - end_wrapper_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - end_value_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - return true; -} - -/* |buf| is NULL-terminated. |buf| itself will never include quotes; - * |is_quoted| tells us whether this text originally appeared inside quotes. */ -static bool parse_number_from_buffer(upb_json_parser *p, const char *buf, - bool is_quoted) { - size_t len = strlen(buf); - const char *bufend = buf + len; - char *end; - upb_fieldtype_t type = upb_fielddef_type(p->top->f); - double val; - double dummy; - double inf = UPB_INFINITY; - - errno = 0; - - if (len == 0 || buf[0] == ' ') { - return false; - } - - /* For integer types, first try parsing with integer-specific routines. - * If these succeed, they will be more accurate for int64/uint64 than - * strtod(). - */ - switch (type) { - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: { - long val = strtol(buf, &end, 0); - if (errno == ERANGE || end != bufend) { - break; - } else if (val > INT32_MAX || val < INT32_MIN) { - return false; - } else { - upb_sink_putint32(p->top->sink, parser_getsel(p), (int32_t)val); - return true; - } - } - case UPB_TYPE_UINT32: { - unsigned long val = strtoul(buf, &end, 0); - if (end != bufend) { - break; - } else if (val > UINT32_MAX || errno == ERANGE) { - return false; - } else { - upb_sink_putuint32(p->top->sink, parser_getsel(p), (uint32_t)val); - return true; - } - } - /* XXX: We can't handle [u]int64 properly on 32-bit machines because - * strto[u]ll isn't in C89. */ - case UPB_TYPE_INT64: { - long val = strtol(buf, &end, 0); - if (errno == ERANGE || end != bufend) { - break; - } else { - upb_sink_putint64(p->top->sink, parser_getsel(p), val); - return true; - } - } - case UPB_TYPE_UINT64: { - unsigned long val = strtoul(p->accumulated, &end, 0); - if (end != bufend) { - break; - } else if (errno == ERANGE) { - return false; - } else { - upb_sink_putuint64(p->top->sink, parser_getsel(p), val); - return true; - } - } - default: - break; - } - - if (type != UPB_TYPE_DOUBLE && type != UPB_TYPE_FLOAT && is_quoted) { - /* Quoted numbers for integer types are not allowed to be in double form. */ - return false; - } - - if (len == strlen("Infinity") && strcmp(buf, "Infinity") == 0) { - /* C89 does not have an INFINITY macro. */ - val = inf; - } else if (len == strlen("-Infinity") && strcmp(buf, "-Infinity") == 0) { - val = -inf; - } else { - val = strtod(buf, &end); - if (errno == ERANGE || end != bufend) { - return false; - } - } - - switch (type) { -#define CASE(capitaltype, smalltype, ctype, min, max) \ - case UPB_TYPE_ ## capitaltype: { \ - if (modf(val, &dummy) != 0 || val > max || val < min) { \ - return false; \ - } else { \ - upb_sink_put ## smalltype(p->top->sink, parser_getsel(p), \ - (ctype)val); \ - return true; \ - } \ - break; \ - } - case UPB_TYPE_ENUM: - CASE(INT32, int32, int32_t, INT32_MIN, INT32_MAX); - CASE(INT64, int64, int64_t, INT64_MIN, INT64_MAX); - CASE(UINT32, uint32, uint32_t, 0, UINT32_MAX); - CASE(UINT64, uint64, uint64_t, 0, UINT64_MAX); -#undef CASE - - case UPB_TYPE_DOUBLE: - upb_sink_putdouble(p->top->sink, parser_getsel(p), val); - return true; - case UPB_TYPE_FLOAT: - if ((val > FLT_MAX || val < -FLT_MAX) && val != inf && val != -inf) { - return false; - } else { - upb_sink_putfloat(p->top->sink, parser_getsel(p), val); - return true; - } - default: - return false; - } -} - -static bool parse_number(upb_json_parser *p, bool is_quoted) { - size_t len; - const char *buf; - - /* strtol() and friends unfortunately do not support specifying the length of - * the input string, so we need to force a copy into a NULL-terminated buffer. */ - if (!multipart_text(p, "\0", 1, false)) { - return false; - } - - buf = accumulate_getptr(p, &len); - - if (parse_number_from_buffer(p, buf, is_quoted)) { - multipart_end(p); - return true; - } else { - upb_status_seterrf(p->status, "error parsing number: %s", buf); - multipart_end(p); - return false; - } -} - -static bool parser_putbool(upb_json_parser *p, bool val) { - bool ok; - - if (p->top->f == NULL) { - return true; - } - - if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) { - upb_status_seterrf(p->status, - "Boolean value specified for non-bool field: %s", - upb_fielddef_name(p->top->f)); - return false; - } - - ok = upb_sink_putbool(p->top->sink, parser_getsel(p), val); - UPB_ASSERT(ok); - - return true; -} - -static bool end_bool(upb_json_parser *p, bool val) { - if (is_top_level(p)) { - if (is_wellknown_msg(p, UPB_WELLKNOWN_BOOLVALUE)) { - start_wrapper_object(p); - } else if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - start_value_object(p, VALUE_BOOLVALUE); - } else { - return false; - } - } else if (is_wellknown_field(p, UPB_WELLKNOWN_BOOLVALUE)) { - if (!start_subobject(p)) { - return false; - } - start_wrapper_object(p); - } else if (is_wellknown_field(p, UPB_WELLKNOWN_VALUE)) { - if (!start_subobject(p)) { - return false; - } - start_value_object(p, VALUE_BOOLVALUE); - } - - if (p->top->is_unknown_field) { - return true; - } - - if (!parser_putbool(p, val)) { - return false; - } - - if (is_wellknown_msg(p, UPB_WELLKNOWN_BOOLVALUE)) { - end_wrapper_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - end_value_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - return true; -} - -static bool end_null(upb_json_parser *p) { - const char *zero_ptr = "0"; - - if (is_top_level(p)) { - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - start_value_object(p, VALUE_NULLVALUE); - } else { - return true; - } - } else if (is_wellknown_field(p, UPB_WELLKNOWN_VALUE)) { - if (!start_subobject(p)) { - return false; - } - start_value_object(p, VALUE_NULLVALUE); - } else { - return true; - } - - /* Fill null_value field. */ - multipart_startaccum(p); - capture_begin(p, zero_ptr); - capture_end(p, zero_ptr + 1); - parse_number(p, false); - - end_value_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - - return true; -} - -static bool start_any_stringval(upb_json_parser *p) { - multipart_startaccum(p); - return true; -} - -static bool start_stringval(upb_json_parser *p) { - if (is_top_level(p)) { - if (is_string_wrapper_object(p) || - is_number_wrapper_object(p)) { - start_wrapper_object(p); - } else if (is_wellknown_msg(p, UPB_WELLKNOWN_FIELDMASK)) { - start_fieldmask_object(p); - return true; - } else if (is_wellknown_msg(p, UPB_WELLKNOWN_TIMESTAMP) || - is_wellknown_msg(p, UPB_WELLKNOWN_DURATION)) { - start_object(p); - } else if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - start_value_object(p, VALUE_STRINGVALUE); - } else { - return false; - } - } else if (does_string_wrapper_start(p) || - does_number_wrapper_start(p)) { - if (!start_subobject(p)) { - return false; - } - start_wrapper_object(p); - } else if (does_fieldmask_start(p)) { - if (!start_subobject(p)) { - return false; - } - start_fieldmask_object(p); - return true; - } else if (is_wellknown_field(p, UPB_WELLKNOWN_TIMESTAMP) || - is_wellknown_field(p, UPB_WELLKNOWN_DURATION)) { - if (!start_subobject(p)) { - return false; - } - start_object(p); - } else if (is_wellknown_field(p, UPB_WELLKNOWN_VALUE)) { - if (!start_subobject(p)) { - return false; - } - start_value_object(p, VALUE_STRINGVALUE); - } - - if (p->top->f == NULL) { - multipart_startaccum(p); - return true; - } - - if (p->top->is_any) { - return start_any_stringval(p); - } - - if (upb_fielddef_isstring(p->top->f)) { - upb_jsonparser_frame *inner; - upb_selector_t sel; - - if (!check_stack(p)) return false; - - /* Start a new parser frame: parser frames correspond one-to-one with - * handler frames, and string events occur in a sub-frame. */ - inner = start_jsonparser_frame(p); - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); - upb_sink_startstr(p->top->sink, sel, 0, &inner->sink); - inner->m = p->top->m; - inner->f = p->top->f; - p->top = inner; - - if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) { - /* For STRING fields we push data directly to the handlers as it is - * parsed. We don't do this yet for BYTES fields, because our base64 - * decoder is not streaming. - * - * TODO(haberman): make base64 decoding streaming also. */ - multipart_start(p, getsel_for_handlertype(p, UPB_HANDLER_STRING)); - return true; - } else { - multipart_startaccum(p); - return true; - } - } else if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL && - upb_fielddef_type(p->top->f) != UPB_TYPE_MESSAGE) { - /* No need to push a frame -- numeric values in quotes remain in the - * current parser frame. These values must accmulate so we can convert - * them all at once at the end. */ - multipart_startaccum(p); - return true; - } else { - upb_status_seterrf(p->status, - "String specified for bool or submessage field: %s", - upb_fielddef_name(p->top->f)); - return false; - } -} - -static bool end_any_stringval(upb_json_parser *p) { - size_t len; - const char *buf = accumulate_getptr(p, &len); - - /* Set type_url */ - upb_selector_t sel; - upb_jsonparser_frame *inner; - if (!check_stack(p)) return false; - inner = p->top + 1; - - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); - upb_sink_startstr(p->top->sink, sel, 0, &inner->sink); - sel = getsel_for_handlertype(p, UPB_HANDLER_STRING); - upb_sink_putstring(inner->sink, sel, buf, len, NULL); - sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); - upb_sink_endstr(inner->sink, sel); - - multipart_end(p); - - /* Resolve type url */ - if (strncmp(buf, "type.googleapis.com/", 20) == 0 && len > 20) { - const upb_msgdef *payload_type = NULL; - buf += 20; - len -= 20; - - payload_type = upb_symtab_lookupmsg2(p->symtab, buf, len); - if (payload_type == NULL) { - upb_status_seterrf( - p->status, "Cannot find packed type: %.*s\n", (int)len, buf); - return false; - } - - json_parser_any_frame_set_payload_type(p, p->top->any_frame, payload_type); - - return true; - } else { - upb_status_seterrf( - p->status, "Invalid type url: %.*s\n", (int)len, buf); - return false; - } -} - -static bool end_stringval_nontop(upb_json_parser *p) { - bool ok = true; - - if (is_wellknown_msg(p, UPB_WELLKNOWN_TIMESTAMP) || - is_wellknown_msg(p, UPB_WELLKNOWN_DURATION)) { - multipart_end(p); - return true; - } - - if (p->top->f == NULL) { - multipart_end(p); - return true; - } - - if (p->top->is_any) { - return end_any_stringval(p); - } - - switch (upb_fielddef_type(p->top->f)) { - case UPB_TYPE_BYTES: - if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING), - p->accumulated, p->accumulated_len)) { - return false; - } - /* Fall through. */ - - case UPB_TYPE_STRING: { - upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); - upb_sink_endstr(p->top->sink, sel); - p->top--; - break; - } - - case UPB_TYPE_ENUM: { - /* Resolve enum symbolic name to integer value. */ - const upb_enumdef *enumdef = upb_fielddef_enumsubdef(p->top->f); - - size_t len; - const char *buf = accumulate_getptr(p, &len); - - int32_t int_val = 0; - ok = upb_enumdef_ntoi(enumdef, buf, len, &int_val); - - if (ok) { - upb_selector_t sel = parser_getsel(p); - upb_sink_putint32(p->top->sink, sel, int_val); - } else { - if (p->ignore_json_unknown) { - ok = true; - /* TODO(teboring): Should also clean this field. */ - } else { - upb_status_seterrf(p->status, "Enum value unknown: '%.*s'", len, buf); - } - } - - break; - } - - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - case UPB_TYPE_DOUBLE: - case UPB_TYPE_FLOAT: - ok = parse_number(p, true); - break; - - default: - UPB_ASSERT(false); - upb_status_seterrmsg(p->status, "Internal error in JSON decoder"); - ok = false; - break; - } - - multipart_end(p); - - return ok; -} - -static bool end_stringval(upb_json_parser *p) { - /* FieldMask's stringvals have been ended when handling them. Only need to - * close FieldMask here.*/ - if (does_fieldmask_end(p)) { - end_fieldmask_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - if (!end_stringval_nontop(p)) { - return false; - } - - if (does_string_wrapper_end(p) || - does_number_wrapper_end(p)) { - end_wrapper_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - end_value_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - if (is_wellknown_msg(p, UPB_WELLKNOWN_TIMESTAMP) || - is_wellknown_msg(p, UPB_WELLKNOWN_DURATION) || - is_wellknown_msg(p, UPB_WELLKNOWN_FIELDMASK)) { - end_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - return true; - } - - return true; -} - -static void start_duration_base(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_duration_base(upb_json_parser *p, const char *ptr) { - size_t len; - const char *buf; - char seconds_buf[14]; - char nanos_buf[12]; - char *end; - int64_t seconds = 0; - int32_t nanos = 0; - double val = 0.0; - const char *seconds_membername = "seconds"; - const char *nanos_membername = "nanos"; - size_t fraction_start; - - if (!capture_end(p, ptr)) { - return false; - } - - buf = accumulate_getptr(p, &len); - - memset(seconds_buf, 0, 14); - memset(nanos_buf, 0, 12); - - /* Find out base end. The maximus duration is 315576000000, which cannot be - * represented by double without losing precision. Thus, we need to handle - * fraction and base separately. */ - for (fraction_start = 0; fraction_start < len && buf[fraction_start] != '.'; - fraction_start++); - - /* Parse base */ - memcpy(seconds_buf, buf, fraction_start); - seconds = strtol(seconds_buf, &end, 10); - if (errno == ERANGE || end != seconds_buf + fraction_start) { - upb_status_seterrf(p->status, "error parsing duration: %s", - seconds_buf); - return false; - } - - if (seconds > 315576000000) { - upb_status_seterrf(p->status, "error parsing duration: " - "maximum acceptable value is " - "315576000000"); - return false; - } - - if (seconds < -315576000000) { - upb_status_seterrf(p->status, "error parsing duration: " - "minimum acceptable value is " - "-315576000000"); - return false; - } - - /* Parse fraction */ - nanos_buf[0] = '0'; - memcpy(nanos_buf + 1, buf + fraction_start, len - fraction_start); - val = strtod(nanos_buf, &end); - if (errno == ERANGE || end != nanos_buf + len - fraction_start + 1) { - upb_status_seterrf(p->status, "error parsing duration: %s", - nanos_buf); - return false; - } - - nanos = val * 1000000000; - if (seconds < 0) nanos = -nanos; - - /* Clean up buffer */ - multipart_end(p); - - /* Set seconds */ - start_member(p); - capture_begin(p, seconds_membername); - capture_end(p, seconds_membername + 7); - end_membername(p); - upb_sink_putint64(p->top->sink, parser_getsel(p), seconds); - end_member(p); - - /* Set nanos */ - start_member(p); - capture_begin(p, nanos_membername); - capture_end(p, nanos_membername + 5); - end_membername(p); - upb_sink_putint32(p->top->sink, parser_getsel(p), nanos); - end_member(p); - - /* Continue previous arena */ - multipart_startaccum(p); - - return true; -} - -static int parse_timestamp_number(upb_json_parser *p) { - size_t len; - const char *buf; - int val; - - /* atoi() and friends unfortunately do not support specifying the length of - * the input string, so we need to force a copy into a NULL-terminated buffer. */ - multipart_text(p, "\0", 1, false); - - buf = accumulate_getptr(p, &len); - val = atoi(buf); - multipart_end(p); - multipart_startaccum(p); - - return val; -} - -static void start_year(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_year(upb_json_parser *p, const char *ptr) { - if (!capture_end(p, ptr)) { - return false; - } - p->tm.tm_year = parse_timestamp_number(p) - 1900; - return true; -} - -static void start_month(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_month(upb_json_parser *p, const char *ptr) { - if (!capture_end(p, ptr)) { - return false; - } - p->tm.tm_mon = parse_timestamp_number(p) - 1; - return true; -} - -static void start_day(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_day(upb_json_parser *p, const char *ptr) { - if (!capture_end(p, ptr)) { - return false; - } - p->tm.tm_mday = parse_timestamp_number(p); - return true; -} - -static void start_hour(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_hour(upb_json_parser *p, const char *ptr) { - if (!capture_end(p, ptr)) { - return false; - } - p->tm.tm_hour = parse_timestamp_number(p); - return true; -} - -static void start_minute(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_minute(upb_json_parser *p, const char *ptr) { - if (!capture_end(p, ptr)) { - return false; - } - p->tm.tm_min = parse_timestamp_number(p); - return true; -} - -static void start_second(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_second(upb_json_parser *p, const char *ptr) { - if (!capture_end(p, ptr)) { - return false; - } - p->tm.tm_sec = parse_timestamp_number(p); - return true; -} - -static void start_timestamp_base(upb_json_parser *p) { - memset(&p->tm, 0, sizeof(struct tm)); -} - -static void start_timestamp_fraction(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_timestamp_fraction(upb_json_parser *p, const char *ptr) { - size_t len; - const char *buf; - char nanos_buf[12]; - char *end; - double val = 0.0; - int32_t nanos; - const char *nanos_membername = "nanos"; - - memset(nanos_buf, 0, 12); - - if (!capture_end(p, ptr)) { - return false; - } - - buf = accumulate_getptr(p, &len); - - if (len > 10) { - upb_status_seterrf(p->status, - "error parsing timestamp: at most 9-digit fraction."); - return false; - } - - /* Parse nanos */ - nanos_buf[0] = '0'; - memcpy(nanos_buf + 1, buf, len); - val = strtod(nanos_buf, &end); - - if (errno == ERANGE || end != nanos_buf + len + 1) { - upb_status_seterrf(p->status, "error parsing timestamp nanos: %s", - nanos_buf); - return false; - } - - nanos = val * 1000000000; - - /* Clean up previous environment */ - multipart_end(p); - - /* Set nanos */ - start_member(p); - capture_begin(p, nanos_membername); - capture_end(p, nanos_membername + 5); - end_membername(p); - upb_sink_putint32(p->top->sink, parser_getsel(p), nanos); - end_member(p); - - /* Continue previous environment */ - multipart_startaccum(p); - - return true; -} - -static void start_timestamp_zone(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static int div_round_up2(int n, int d) { - return (n + d - 1) / d; -} - -/* epoch_days(1970, 1, 1) == 1970-01-01 == 0. */ -static int epoch_days(int year, int month, int day) { - static const uint16_t month_yday[12] = {0, 31, 59, 90, 120, 151, - 181, 212, 243, 273, 304, 334}; - int febs_since_0 = month > 2 ? year + 1 : year; - int leap_days_since_0 = div_round_up2(febs_since_0, 4) - - div_round_up2(febs_since_0, 100) + - div_round_up2(febs_since_0, 400); - int days_since_0 = - 365 * year + month_yday[month - 1] + (day - 1) + leap_days_since_0; - - /* Convert from 0-epoch (0001-01-01 BC) to Unix Epoch (1970-01-01 AD). - * Since the "BC" system does not have a year zero, 1 BC == year zero. */ - return days_since_0 - 719528; -} - -static int64_t upb_timegm(const struct tm *tp) { - int64_t ret = epoch_days(tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday); - ret = (ret * 24) + tp->tm_hour; - ret = (ret * 60) + tp->tm_min; - ret = (ret * 60) + tp->tm_sec; - return ret; -} - -static bool end_timestamp_zone(upb_json_parser *p, const char *ptr) { - size_t len; - const char *buf; - int hours; - int64_t seconds; - const char *seconds_membername = "seconds"; - - if (!capture_end(p, ptr)) { - return false; - } - - buf = accumulate_getptr(p, &len); - - if (buf[0] != 'Z') { - if (sscanf(buf + 1, "%2d:00", &hours) != 1) { - upb_status_seterrf(p->status, "error parsing timestamp offset"); - return false; - } - - if (buf[0] == '+') { - hours = -hours; - } - - p->tm.tm_hour += hours; - } - - /* Normalize tm */ - seconds = upb_timegm(&p->tm); - - /* Check timestamp boundary */ - if (seconds < -62135596800) { - upb_status_seterrf(p->status, "error parsing timestamp: " - "minimum acceptable value is " - "0001-01-01T00:00:00Z"); - return false; - } - - /* Clean up previous environment */ - multipart_end(p); - - /* Set seconds */ - start_member(p); - capture_begin(p, seconds_membername); - capture_end(p, seconds_membername + 7); - end_membername(p); - upb_sink_putint64(p->top->sink, parser_getsel(p), seconds); - end_member(p); - - /* Continue previous environment */ - multipart_startaccum(p); - - return true; -} - -static void start_fieldmask_path_text(upb_json_parser *p, const char *ptr) { - capture_begin(p, ptr); -} - -static bool end_fieldmask_path_text(upb_json_parser *p, const char *ptr) { - return capture_end(p, ptr); -} - -static bool start_fieldmask_path(upb_json_parser *p) { - upb_jsonparser_frame *inner; - upb_selector_t sel; - - if (!check_stack(p)) return false; - - /* Start a new parser frame: parser frames correspond one-to-one with - * handler frames, and string events occur in a sub-frame. */ - inner = start_jsonparser_frame(p); - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); - upb_sink_startstr(p->top->sink, sel, 0, &inner->sink); - inner->m = p->top->m; - inner->f = p->top->f; - p->top = inner; - - multipart_startaccum(p); - return true; -} - -static bool lower_camel_push( - upb_json_parser *p, upb_selector_t sel, const char *ptr, size_t len) { - const char *limit = ptr + len; - bool first = true; - for (;ptr < limit; ptr++) { - if (*ptr >= 'A' && *ptr <= 'Z' && !first) { - char lower = tolower(*ptr); - upb_sink_putstring(p->top->sink, sel, "_", 1, NULL); - upb_sink_putstring(p->top->sink, sel, &lower, 1, NULL); - } else { - upb_sink_putstring(p->top->sink, sel, ptr, 1, NULL); - } - first = false; - } - return true; -} - -static bool end_fieldmask_path(upb_json_parser *p) { - upb_selector_t sel; - - if (!lower_camel_push( - p, getsel_for_handlertype(p, UPB_HANDLER_STRING), - p->accumulated, p->accumulated_len)) { - return false; - } - - sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); - upb_sink_endstr(p->top->sink, sel); - p->top--; - - multipart_end(p); - return true; -} - -static void start_member(upb_json_parser *p) { - UPB_ASSERT(!p->top->f); - multipart_startaccum(p); -} - -/* Helper: invoked during parse_mapentry() to emit the mapentry message's key - * field based on the current contents of the accumulate buffer. */ -static bool parse_mapentry_key(upb_json_parser *p) { - - size_t len; - const char *buf = accumulate_getptr(p, &len); - - /* Emit the key field. We do a bit of ad-hoc parsing here because the - * parser state machine has already decided that this is a string field - * name, and we are reinterpreting it as some arbitrary key type. In - * particular, integer and bool keys are quoted, so we need to parse the - * quoted string contents here. */ - - p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_KEY); - if (p->top->f == NULL) { - upb_status_seterrmsg(p->status, "mapentry message has no key"); - return false; - } - switch (upb_fielddef_type(p->top->f)) { - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - /* Invoke end_number. The accum buffer has the number's text already. */ - if (!parse_number(p, true)) { - return false; - } - break; - case UPB_TYPE_BOOL: - if (len == 4 && !strncmp(buf, "true", 4)) { - if (!parser_putbool(p, true)) { - return false; - } - } else if (len == 5 && !strncmp(buf, "false", 5)) { - if (!parser_putbool(p, false)) { - return false; - } - } else { - upb_status_seterrmsg(p->status, - "Map bool key not 'true' or 'false'"); - return false; - } - multipart_end(p); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - upb_sink subsink; - upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); - upb_sink_startstr(p->top->sink, sel, len, &subsink); - sel = getsel_for_handlertype(p, UPB_HANDLER_STRING); - upb_sink_putstring(subsink, sel, buf, len, NULL); - sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); - upb_sink_endstr(subsink, sel); - multipart_end(p); - break; - } - default: - upb_status_seterrmsg(p->status, "Invalid field type for map key"); - return false; - } - - return true; -} - -/* Helper: emit one map entry (as a submessage in the map field sequence). This - * is invoked from end_membername(), at the end of the map entry's key string, - * with the map key in the accumulate buffer. It parses the key from that - * buffer, emits the handler calls to start the mapentry submessage (setting up - * its subframe in the process), and sets up state in the subframe so that the - * value parser (invoked next) will emit the mapentry's value field and then - * end the mapentry message. */ - -static bool handle_mapentry(upb_json_parser *p) { - const upb_fielddef *mapfield; - const upb_msgdef *mapentrymsg; - upb_jsonparser_frame *inner; - upb_selector_t sel; - - /* Map entry: p->top->sink is the seq frame, so we need to start a frame - * for the mapentry itself, and then set |f| in that frame so that the map - * value field is parsed, and also set a flag to end the frame after the - * map-entry value is parsed. */ - if (!check_stack(p)) return false; - - mapfield = p->top->mapfield; - mapentrymsg = upb_fielddef_msgsubdef(mapfield); - - inner = start_jsonparser_frame(p); - p->top->f = mapfield; - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG); - upb_sink_startsubmsg(p->top->sink, sel, &inner->sink); - inner->m = mapentrymsg; - inner->mapfield = mapfield; - - /* Don't set this to true *yet* -- we reuse parsing handlers below to push - * the key field value to the sink, and these handlers will pop the frame - * if they see is_mapentry (when invoked by the parser state machine, they - * would have just seen the map-entry value, not key). */ - inner->is_mapentry = false; - p->top = inner; - - /* send STARTMSG in submsg frame. */ - upb_sink_startmsg(p->top->sink); - - parse_mapentry_key(p); - - /* Set up the value field to receive the map-entry value. */ - p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_VALUE); - p->top->is_mapentry = true; /* set up to pop frame after value is parsed. */ - p->top->mapfield = mapfield; - if (p->top->f == NULL) { - upb_status_seterrmsg(p->status, "mapentry message has no value"); - return false; - } - - return true; -} - -static bool end_membername(upb_json_parser *p) { - UPB_ASSERT(!p->top->f); - - if (!p->top->m) { - p->top->is_unknown_field = true; - multipart_end(p); - return true; - } - - if (p->top->is_any) { - return end_any_membername(p); - } else if (p->top->is_map) { - return handle_mapentry(p); - } else { - size_t len; - const char *buf = accumulate_getptr(p, &len); - upb_value v; - - if (upb_strtable_lookup2(p->top->name_table, buf, len, &v)) { - p->top->f = upb_value_getconstptr(v); - multipart_end(p); - - return true; - } else if (p->ignore_json_unknown) { - p->top->is_unknown_field = true; - multipart_end(p); - return true; - } else { - upb_status_seterrf(p->status, "No such field: %.*s\n", (int)len, buf); - return false; - } - } -} - -static bool end_any_membername(upb_json_parser *p) { - size_t len; - const char *buf = accumulate_getptr(p, &len); - upb_value v; - - if (len == 5 && strncmp(buf, "@type", len) == 0) { - upb_strtable_lookup2(p->top->name_table, "type_url", 8, &v); - p->top->f = upb_value_getconstptr(v); - multipart_end(p); - return true; - } else { - p->top->is_unknown_field = true; - multipart_end(p); - return true; - } -} - -static void end_member(upb_json_parser *p) { - /* If we just parsed a map-entry value, end that frame too. */ - if (p->top->is_mapentry) { - upb_selector_t sel; - bool ok; - const upb_fielddef *mapfield; - - UPB_ASSERT(p->top > p->stack); - /* send ENDMSG on submsg. */ - upb_sink_endmsg(p->top->sink, p->status); - mapfield = p->top->mapfield; - - /* send ENDSUBMSG in repeated-field-of-mapentries frame. */ - p->top--; - ok = upb_handlers_getselector(mapfield, UPB_HANDLER_ENDSUBMSG, &sel); - UPB_ASSUME(ok); - upb_sink_endsubmsg(p->top->sink, (p->top + 1)->sink, sel); - } - - p->top->f = NULL; - p->top->is_unknown_field = false; -} - -static void start_any_member(upb_json_parser *p, const char *ptr) { - start_member(p); - json_parser_any_frame_set_after_type_url_start_once(p->top->any_frame, ptr); -} - -static void end_any_member(upb_json_parser *p, const char *ptr) { - json_parser_any_frame_set_before_type_url_end(p->top->any_frame, ptr); - end_member(p); -} - -static bool start_subobject(upb_json_parser *p) { - if (p->top->is_unknown_field) { - if (!check_stack(p)) return false; - - p->top = start_jsonparser_frame(p); - return true; - } - - if (upb_fielddef_ismap(p->top->f)) { - upb_jsonparser_frame *inner; - upb_selector_t sel; - - /* Beginning of a map. Start a new parser frame in a repeated-field - * context. */ - if (!check_stack(p)) return false; - - inner = start_jsonparser_frame(p); - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ); - upb_sink_startseq(p->top->sink, sel, &inner->sink); - inner->m = upb_fielddef_msgsubdef(p->top->f); - inner->mapfield = p->top->f; - inner->is_map = true; - p->top = inner; - - return true; - } else if (upb_fielddef_issubmsg(p->top->f)) { - upb_jsonparser_frame *inner; - upb_selector_t sel; - - /* Beginning of a subobject. Start a new parser frame in the submsg - * context. */ - if (!check_stack(p)) return false; - - inner = start_jsonparser_frame(p); - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG); - upb_sink_startsubmsg(p->top->sink, sel, &inner->sink); - inner->m = upb_fielddef_msgsubdef(p->top->f); - set_name_table(p, inner); - p->top = inner; - - if (is_wellknown_msg(p, UPB_WELLKNOWN_ANY)) { - p->top->is_any = true; - p->top->any_frame = json_parser_any_frame_new(p); - } else { - p->top->is_any = false; - p->top->any_frame = NULL; - } - - return true; - } else { - upb_status_seterrf(p->status, - "Object specified for non-message/group field: %s", - upb_fielddef_name(p->top->f)); - return false; - } -} - -static bool start_subobject_full(upb_json_parser *p) { - if (is_top_level(p)) { - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - start_value_object(p, VALUE_STRUCTVALUE); - if (!start_subobject(p)) return false; - start_structvalue_object(p); - } else if (is_wellknown_msg(p, UPB_WELLKNOWN_STRUCT)) { - start_structvalue_object(p); - } else { - return true; - } - } else if (is_wellknown_field(p, UPB_WELLKNOWN_STRUCT)) { - if (!start_subobject(p)) return false; - start_structvalue_object(p); - } else if (is_wellknown_field(p, UPB_WELLKNOWN_VALUE)) { - if (!start_subobject(p)) return false; - start_value_object(p, VALUE_STRUCTVALUE); - if (!start_subobject(p)) return false; - start_structvalue_object(p); - } - - return start_subobject(p); -} - -static void end_subobject(upb_json_parser *p) { - if (is_top_level(p)) { - return; - } - - if (p->top->is_map) { - upb_selector_t sel; - p->top--; - sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ); - upb_sink_endseq(p->top->sink, sel); - } else { - upb_selector_t sel; - bool is_unknown = p->top->m == NULL; - p->top--; - if (!is_unknown) { - sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG); - upb_sink_endsubmsg(p->top->sink, (p->top + 1)->sink, sel); - } - } -} - -static void end_subobject_full(upb_json_parser *p) { - end_subobject(p); - - if (is_wellknown_msg(p, UPB_WELLKNOWN_STRUCT)) { - end_structvalue_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - } - - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - end_value_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - } -} - -static bool start_array(upb_json_parser *p) { - upb_jsonparser_frame *inner; - upb_selector_t sel; - - if (is_top_level(p)) { - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - start_value_object(p, VALUE_LISTVALUE); - if (!start_subobject(p)) return false; - start_listvalue_object(p); - } else if (is_wellknown_msg(p, UPB_WELLKNOWN_LISTVALUE)) { - start_listvalue_object(p); - } else { - return false; - } - } else if (is_wellknown_field(p, UPB_WELLKNOWN_LISTVALUE) && - (!upb_fielddef_isseq(p->top->f) || - p->top->is_repeated)) { - if (!start_subobject(p)) return false; - start_listvalue_object(p); - } else if (is_wellknown_field(p, UPB_WELLKNOWN_VALUE) && - (!upb_fielddef_isseq(p->top->f) || - p->top->is_repeated)) { - if (!start_subobject(p)) return false; - start_value_object(p, VALUE_LISTVALUE); - if (!start_subobject(p)) return false; - start_listvalue_object(p); - } - - if (p->top->is_unknown_field) { - inner = start_jsonparser_frame(p); - inner->is_unknown_field = true; - p->top = inner; - - return true; - } - - if (!upb_fielddef_isseq(p->top->f)) { - upb_status_seterrf(p->status, - "Array specified for non-repeated field: %s", - upb_fielddef_name(p->top->f)); - return false; - } - - if (!check_stack(p)) return false; - - inner = start_jsonparser_frame(p); - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ); - upb_sink_startseq(p->top->sink, sel, &inner->sink); - inner->m = p->top->m; - inner->f = p->top->f; - inner->is_repeated = true; - p->top = inner; - - return true; -} - -static void end_array(upb_json_parser *p) { - upb_selector_t sel; - - UPB_ASSERT(p->top > p->stack); - - p->top--; - - if (p->top->is_unknown_field) { - return; - } - - sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ); - upb_sink_endseq(p->top->sink, sel); - - if (is_wellknown_msg(p, UPB_WELLKNOWN_LISTVALUE)) { - end_listvalue_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - } - - if (is_wellknown_msg(p, UPB_WELLKNOWN_VALUE)) { - end_value_object(p); - if (!is_top_level(p)) { - end_subobject(p); - } - } -} - -static void start_object(upb_json_parser *p) { - if (!p->top->is_map && p->top->m != NULL) { - upb_sink_startmsg(p->top->sink); - } -} - -static void end_object(upb_json_parser *p) { - if (!p->top->is_map && p->top->m != NULL) { - upb_sink_endmsg(p->top->sink, p->status); - } -} - -static void start_any_object(upb_json_parser *p, const char *ptr) { - start_object(p); - p->top->any_frame->before_type_url_start = ptr; - p->top->any_frame->before_type_url_end = ptr; -} - -static bool end_any_object(upb_json_parser *p, const char *ptr) { - const char *value_membername = "value"; - bool is_well_known_packed = false; - const char *packed_end = ptr + 1; - upb_selector_t sel; - upb_jsonparser_frame *inner; - - if (json_parser_any_frame_has_value(p->top->any_frame) && - !json_parser_any_frame_has_type_url(p->top->any_frame)) { - upb_status_seterrmsg(p->status, "No valid type url"); - return false; - } - - /* Well known types data is represented as value field. */ - if (upb_msgdef_wellknowntype(p->top->any_frame->parser->top->m) != - UPB_WELLKNOWN_UNSPECIFIED) { - is_well_known_packed = true; - - if (json_parser_any_frame_has_value_before_type_url(p->top->any_frame)) { - p->top->any_frame->before_type_url_start = - memchr(p->top->any_frame->before_type_url_start, ':', - p->top->any_frame->before_type_url_end - - p->top->any_frame->before_type_url_start); - if (p->top->any_frame->before_type_url_start == NULL) { - upb_status_seterrmsg(p->status, "invalid data for well known type."); - return false; - } - p->top->any_frame->before_type_url_start++; - } - - if (json_parser_any_frame_has_value_after_type_url(p->top->any_frame)) { - p->top->any_frame->after_type_url_start = - memchr(p->top->any_frame->after_type_url_start, ':', - (ptr + 1) - - p->top->any_frame->after_type_url_start); - if (p->top->any_frame->after_type_url_start == NULL) { - upb_status_seterrmsg(p->status, "Invalid data for well known type."); - return false; - } - p->top->any_frame->after_type_url_start++; - packed_end = ptr; - } - } - - if (json_parser_any_frame_has_value_before_type_url(p->top->any_frame)) { - if (!parse(p->top->any_frame->parser, NULL, - p->top->any_frame->before_type_url_start, - p->top->any_frame->before_type_url_end - - p->top->any_frame->before_type_url_start, NULL)) { - return false; - } - } else { - if (!is_well_known_packed) { - if (!parse(p->top->any_frame->parser, NULL, "{", 1, NULL)) { - return false; - } - } - } - - if (json_parser_any_frame_has_value_before_type_url(p->top->any_frame) && - json_parser_any_frame_has_value_after_type_url(p->top->any_frame)) { - if (!parse(p->top->any_frame->parser, NULL, ",", 1, NULL)) { - return false; - } - } - - if (json_parser_any_frame_has_value_after_type_url(p->top->any_frame)) { - if (!parse(p->top->any_frame->parser, NULL, - p->top->any_frame->after_type_url_start, - packed_end - p->top->any_frame->after_type_url_start, NULL)) { - return false; - } - } else { - if (!is_well_known_packed) { - if (!parse(p->top->any_frame->parser, NULL, "}", 1, NULL)) { - return false; - } - } - } - - if (!end(p->top->any_frame->parser, NULL)) { - return false; - } - - p->top->is_any = false; - - /* Set value */ - start_member(p); - capture_begin(p, value_membername); - capture_end(p, value_membername + 5); - end_membername(p); - - if (!check_stack(p)) return false; - inner = p->top + 1; - - sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); - upb_sink_startstr(p->top->sink, sel, 0, &inner->sink); - sel = getsel_for_handlertype(p, UPB_HANDLER_STRING); - upb_sink_putstring(inner->sink, sel, p->top->any_frame->stringsink.ptr, - p->top->any_frame->stringsink.len, NULL); - sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); - upb_sink_endstr(inner->sink, sel); - - end_member(p); - - end_object(p); - - /* Deallocate any parse frame. */ - json_parser_any_frame_free(p->top->any_frame); - - return true; -} - -static bool is_string_wrapper(const upb_msgdef *m) { - upb_wellknowntype_t type = upb_msgdef_wellknowntype(m); - return type == UPB_WELLKNOWN_STRINGVALUE || - type == UPB_WELLKNOWN_BYTESVALUE; -} - -static bool is_fieldmask(const upb_msgdef *m) { - upb_wellknowntype_t type = upb_msgdef_wellknowntype(m); - return type == UPB_WELLKNOWN_FIELDMASK; -} - -static void start_fieldmask_object(upb_json_parser *p) { - const char *membername = "paths"; - - start_object(p); - - /* Set up context for parsing value */ - start_member(p); - capture_begin(p, membername); - capture_end(p, membername + 5); - end_membername(p); - - start_array(p); -} - -static void end_fieldmask_object(upb_json_parser *p) { - end_array(p); - end_member(p); - end_object(p); -} - -static void start_wrapper_object(upb_json_parser *p) { - const char *membername = "value"; - - start_object(p); - - /* Set up context for parsing value */ - start_member(p); - capture_begin(p, membername); - capture_end(p, membername + 5); - end_membername(p); -} - -static void end_wrapper_object(upb_json_parser *p) { - end_member(p); - end_object(p); -} - -static void start_value_object(upb_json_parser *p, int value_type) { - const char *nullmember = "null_value"; - const char *numbermember = "number_value"; - const char *stringmember = "string_value"; - const char *boolmember = "bool_value"; - const char *structmember = "struct_value"; - const char *listmember = "list_value"; - const char *membername = ""; - - switch (value_type) { - case VALUE_NULLVALUE: - membername = nullmember; - break; - case VALUE_NUMBERVALUE: - membername = numbermember; - break; - case VALUE_STRINGVALUE: - membername = stringmember; - break; - case VALUE_BOOLVALUE: - membername = boolmember; - break; - case VALUE_STRUCTVALUE: - membername = structmember; - break; - case VALUE_LISTVALUE: - membername = listmember; - break; - } - - start_object(p); - - /* Set up context for parsing value */ - start_member(p); - capture_begin(p, membername); - capture_end(p, membername + strlen(membername)); - end_membername(p); -} - -static void end_value_object(upb_json_parser *p) { - end_member(p); - end_object(p); -} - -static void start_listvalue_object(upb_json_parser *p) { - const char *membername = "values"; - - start_object(p); - - /* Set up context for parsing value */ - start_member(p); - capture_begin(p, membername); - capture_end(p, membername + strlen(membername)); - end_membername(p); -} - -static void end_listvalue_object(upb_json_parser *p) { - end_member(p); - end_object(p); -} - -static void start_structvalue_object(upb_json_parser *p) { - const char *membername = "fields"; - - start_object(p); - - /* Set up context for parsing value */ - start_member(p); - capture_begin(p, membername); - capture_end(p, membername + strlen(membername)); - end_membername(p); -} - -static void end_structvalue_object(upb_json_parser *p) { - end_member(p); - end_object(p); -} - -static bool is_top_level(upb_json_parser *p) { - return p->top == p->stack && p->top->f == NULL && !p->top->is_unknown_field; -} - -static bool is_wellknown_msg(upb_json_parser *p, upb_wellknowntype_t type) { - return p->top->m != NULL && upb_msgdef_wellknowntype(p->top->m) == type; -} - -static bool is_wellknown_field(upb_json_parser *p, upb_wellknowntype_t type) { - return p->top->f != NULL && - upb_fielddef_issubmsg(p->top->f) && - (upb_msgdef_wellknowntype(upb_fielddef_msgsubdef(p->top->f)) - == type); -} - -static bool does_number_wrapper_start(upb_json_parser *p) { - return p->top->f != NULL && - upb_fielddef_issubmsg(p->top->f) && - upb_msgdef_isnumberwrapper(upb_fielddef_msgsubdef(p->top->f)); -} - -static bool does_number_wrapper_end(upb_json_parser *p) { - return p->top->m != NULL && upb_msgdef_isnumberwrapper(p->top->m); -} - -static bool is_number_wrapper_object(upb_json_parser *p) { - return p->top->m != NULL && upb_msgdef_isnumberwrapper(p->top->m); -} - -static bool does_string_wrapper_start(upb_json_parser *p) { - return p->top->f != NULL && - upb_fielddef_issubmsg(p->top->f) && - is_string_wrapper(upb_fielddef_msgsubdef(p->top->f)); -} - -static bool does_string_wrapper_end(upb_json_parser *p) { - return p->top->m != NULL && is_string_wrapper(p->top->m); -} - -static bool is_string_wrapper_object(upb_json_parser *p) { - return p->top->m != NULL && is_string_wrapper(p->top->m); -} - -static bool does_fieldmask_start(upb_json_parser *p) { - return p->top->f != NULL && - upb_fielddef_issubmsg(p->top->f) && - is_fieldmask(upb_fielddef_msgsubdef(p->top->f)); -} - -static bool does_fieldmask_end(upb_json_parser *p) { - return p->top->m != NULL && is_fieldmask(p->top->m); -} - -#define CHECK_RETURN_TOP(x) if (!(x)) goto error - - -/* The actual parser **********************************************************/ - -/* What follows is the Ragel parser itself. The language is specified in Ragel - * and the actions call our C functions above. - * - * Ragel has an extensive set of functionality, and we use only a small part of - * it. There are many action types but we only use a few: - * - * ">" -- transition into a machine - * "%" -- transition out of a machine - * "@" -- transition into a final state of a machine. - * - * "@" transitions are tricky because a machine can transition into a final - * state repeatedly. But in some cases we know this can't happen, for example - * a string which is delimited by a final '"' can only transition into its - * final state once, when the closing '"' is seen. */ - - -#line 2787 "upb/json/parser.rl" - - - -#line 2590 "upb/json/parser.c" -static const char _json_actions[] = { - 0, 1, 0, 1, 1, 1, 3, 1, - 4, 1, 6, 1, 7, 1, 8, 1, - 9, 1, 11, 1, 12, 1, 13, 1, - 14, 1, 15, 1, 16, 1, 17, 1, - 18, 1, 19, 1, 20, 1, 22, 1, - 23, 1, 24, 1, 35, 1, 37, 1, - 39, 1, 40, 1, 42, 1, 43, 1, - 44, 1, 46, 1, 48, 1, 49, 1, - 50, 1, 51, 1, 53, 1, 54, 2, - 4, 9, 2, 5, 6, 2, 7, 3, - 2, 7, 9, 2, 21, 26, 2, 25, - 10, 2, 27, 28, 2, 29, 30, 2, - 32, 34, 2, 33, 31, 2, 38, 36, - 2, 40, 42, 2, 45, 2, 2, 46, - 54, 2, 47, 36, 2, 49, 54, 2, - 50, 54, 2, 51, 54, 2, 52, 41, - 2, 53, 54, 3, 32, 34, 35, 4, - 21, 26, 27, 28 -}; - -static const short _json_key_offsets[] = { - 0, 0, 12, 13, 18, 23, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, - 38, 43, 44, 48, 53, 58, 63, 67, - 71, 74, 77, 79, 83, 87, 89, 91, - 96, 98, 100, 109, 115, 121, 127, 133, - 135, 139, 142, 144, 146, 149, 150, 154, - 156, 158, 160, 162, 163, 165, 167, 168, - 170, 172, 173, 175, 177, 178, 180, 182, - 183, 185, 187, 191, 193, 195, 196, 197, - 198, 199, 201, 206, 208, 210, 212, 221, - 222, 222, 222, 227, 232, 237, 238, 239, - 240, 241, 241, 242, 243, 244, 244, 245, - 246, 247, 247, 252, 253, 257, 262, 267, - 272, 276, 276, 279, 282, 285, 288, 291, - 294, 294, 294, 294, 294, 294 -}; - -static const char _json_trans_keys[] = { - 32, 34, 45, 91, 102, 110, 116, 123, - 9, 13, 48, 57, 34, 32, 93, 125, - 9, 13, 32, 44, 93, 9, 13, 32, - 93, 125, 9, 13, 97, 108, 115, 101, - 117, 108, 108, 114, 117, 101, 32, 34, - 125, 9, 13, 34, 32, 58, 9, 13, - 32, 93, 125, 9, 13, 32, 44, 125, - 9, 13, 32, 44, 125, 9, 13, 32, - 34, 9, 13, 45, 48, 49, 57, 48, - 49, 57, 46, 69, 101, 48, 57, 69, - 101, 48, 57, 43, 45, 48, 57, 48, - 57, 48, 57, 46, 69, 101, 48, 57, - 34, 92, 34, 92, 34, 47, 92, 98, - 102, 110, 114, 116, 117, 48, 57, 65, - 70, 97, 102, 48, 57, 65, 70, 97, - 102, 48, 57, 65, 70, 97, 102, 48, - 57, 65, 70, 97, 102, 34, 92, 45, - 48, 49, 57, 48, 49, 57, 46, 115, - 48, 57, 115, 48, 57, 34, 46, 115, - 48, 57, 48, 57, 48, 57, 48, 57, - 48, 57, 45, 48, 57, 48, 57, 45, - 48, 57, 48, 57, 84, 48, 57, 48, - 57, 58, 48, 57, 48, 57, 58, 48, - 57, 48, 57, 43, 45, 46, 90, 48, - 57, 48, 57, 58, 48, 48, 34, 48, - 57, 43, 45, 90, 48, 57, 34, 44, - 34, 44, 34, 44, 34, 45, 91, 102, - 110, 116, 123, 48, 57, 34, 32, 93, - 125, 9, 13, 32, 44, 93, 9, 13, - 32, 93, 125, 9, 13, 97, 108, 115, - 101, 117, 108, 108, 114, 117, 101, 32, - 34, 125, 9, 13, 34, 32, 58, 9, - 13, 32, 93, 125, 9, 13, 32, 44, - 125, 9, 13, 32, 44, 125, 9, 13, - 32, 34, 9, 13, 32, 9, 13, 32, - 9, 13, 32, 9, 13, 32, 9, 13, - 32, 9, 13, 32, 9, 13, 0 -}; - -static const char _json_single_lengths[] = { - 0, 8, 1, 3, 3, 3, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 3, 1, 2, 3, 3, 3, 2, 2, - 1, 3, 0, 2, 2, 0, 0, 3, - 2, 2, 9, 0, 0, 0, 0, 2, - 2, 1, 2, 0, 1, 1, 2, 0, - 0, 0, 0, 1, 0, 0, 1, 0, - 0, 1, 0, 0, 1, 0, 0, 1, - 0, 0, 4, 0, 0, 1, 1, 1, - 1, 0, 3, 2, 2, 2, 7, 1, - 0, 0, 3, 3, 3, 1, 1, 1, - 1, 0, 1, 1, 1, 0, 1, 1, - 1, 0, 3, 1, 2, 3, 3, 3, - 2, 0, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0 -}; - -static const char _json_range_lengths[] = { - 0, 2, 0, 1, 1, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 3, 3, 3, 3, 0, - 1, 1, 0, 1, 1, 0, 1, 1, - 1, 1, 1, 0, 1, 1, 0, 1, - 1, 0, 1, 1, 0, 1, 1, 0, - 1, 1, 0, 1, 1, 0, 0, 0, - 0, 1, 1, 0, 0, 0, 1, 0, - 0, 0, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 1, 1, 1, 1, - 1, 0, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0 -}; - -static const short _json_index_offsets[] = { - 0, 0, 11, 13, 18, 23, 28, 30, - 32, 34, 36, 38, 40, 42, 44, 46, - 48, 53, 55, 59, 64, 69, 74, 78, - 82, 85, 89, 91, 95, 99, 101, 103, - 108, 111, 114, 124, 128, 132, 136, 140, - 143, 147, 150, 153, 155, 158, 160, 164, - 166, 168, 170, 172, 174, 176, 178, 180, - 182, 184, 186, 188, 190, 192, 194, 196, - 198, 200, 202, 207, 209, 211, 213, 215, - 217, 219, 221, 226, 229, 232, 235, 244, - 246, 247, 248, 253, 258, 263, 265, 267, - 269, 271, 272, 274, 276, 278, 279, 281, - 283, 285, 286, 291, 293, 297, 302, 307, - 312, 316, 317, 320, 323, 326, 329, 332, - 335, 336, 337, 338, 339, 340 -}; - -static const unsigned char _json_indicies[] = { - 0, 2, 3, 4, 5, 6, 7, 8, - 0, 3, 1, 9, 1, 11, 12, 1, - 11, 10, 13, 14, 12, 13, 1, 14, - 1, 1, 14, 10, 15, 1, 16, 1, - 17, 1, 18, 1, 19, 1, 20, 1, - 21, 1, 22, 1, 23, 1, 24, 1, - 25, 26, 27, 25, 1, 28, 1, 29, - 30, 29, 1, 30, 1, 1, 30, 31, - 32, 33, 34, 32, 1, 35, 36, 27, - 35, 1, 36, 26, 36, 1, 37, 38, - 39, 1, 38, 39, 1, 41, 42, 42, - 40, 43, 1, 42, 42, 43, 40, 44, - 44, 45, 1, 45, 1, 45, 40, 41, - 42, 42, 39, 40, 47, 48, 46, 50, - 51, 49, 52, 52, 52, 52, 52, 52, - 52, 52, 53, 1, 54, 54, 54, 1, - 55, 55, 55, 1, 56, 56, 56, 1, - 57, 57, 57, 1, 59, 60, 58, 61, - 62, 63, 1, 64, 65, 1, 66, 67, - 1, 68, 1, 67, 68, 1, 69, 1, - 66, 67, 65, 1, 70, 1, 71, 1, - 72, 1, 73, 1, 74, 1, 75, 1, - 76, 1, 77, 1, 78, 1, 79, 1, - 80, 1, 81, 1, 82, 1, 83, 1, - 84, 1, 85, 1, 86, 1, 87, 1, - 88, 1, 89, 89, 90, 91, 1, 92, - 1, 93, 1, 94, 1, 95, 1, 96, - 1, 97, 1, 98, 1, 99, 99, 100, - 98, 1, 102, 1, 101, 104, 105, 103, - 1, 1, 101, 106, 107, 108, 109, 110, - 111, 112, 107, 1, 113, 1, 114, 115, - 117, 118, 1, 117, 116, 119, 120, 118, - 119, 1, 120, 1, 1, 120, 116, 121, - 1, 122, 1, 123, 1, 124, 1, 125, - 126, 1, 127, 1, 128, 1, 129, 130, - 1, 131, 1, 132, 1, 133, 134, 135, - 136, 134, 1, 137, 1, 138, 139, 138, - 1, 139, 1, 1, 139, 140, 141, 142, - 143, 141, 1, 144, 145, 136, 144, 1, - 145, 135, 145, 1, 146, 147, 147, 1, - 148, 148, 1, 149, 149, 1, 150, 150, - 1, 151, 151, 1, 152, 152, 1, 1, - 1, 1, 1, 1, 1, 0 -}; - -static const char _json_trans_targs[] = { - 1, 0, 2, 107, 3, 6, 10, 13, - 16, 106, 4, 3, 106, 4, 5, 7, - 8, 9, 108, 11, 12, 109, 14, 15, - 110, 16, 17, 111, 18, 18, 19, 20, - 21, 22, 111, 21, 22, 24, 25, 31, - 112, 26, 28, 27, 29, 30, 33, 113, - 34, 33, 113, 34, 32, 35, 36, 37, - 38, 39, 33, 113, 34, 41, 42, 46, - 42, 46, 43, 45, 44, 114, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, - 66, 67, 73, 72, 68, 69, 70, 71, - 72, 115, 74, 67, 72, 76, 116, 76, - 116, 77, 79, 81, 82, 85, 90, 94, - 98, 80, 117, 117, 83, 82, 80, 83, - 84, 86, 87, 88, 89, 117, 91, 92, - 93, 117, 95, 96, 97, 117, 98, 99, - 105, 100, 100, 101, 102, 103, 104, 105, - 103, 104, 117, 106, 106, 106, 106, 106, - 106 -}; - -static const unsigned char _json_trans_actions[] = { - 0, 0, 113, 107, 53, 0, 0, 0, - 125, 59, 45, 0, 55, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 101, 51, 47, 0, 0, 45, - 49, 49, 104, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, 5, 15, - 0, 0, 71, 7, 13, 0, 74, 9, - 9, 9, 77, 80, 11, 37, 37, 37, - 0, 0, 0, 39, 0, 41, 86, 0, - 0, 0, 17, 19, 0, 21, 23, 0, - 25, 27, 0, 29, 31, 0, 33, 35, - 0, 135, 83, 135, 0, 0, 0, 0, - 0, 92, 0, 89, 89, 98, 43, 0, - 131, 95, 113, 107, 53, 0, 0, 0, - 125, 59, 69, 110, 45, 0, 55, 0, - 0, 0, 0, 0, 0, 119, 0, 0, - 0, 122, 0, 0, 0, 116, 0, 101, - 51, 47, 0, 0, 45, 49, 49, 104, - 0, 0, 128, 0, 57, 63, 65, 61, - 67 -}; - -static const unsigned char _json_eof_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 57, 63, 65, 61, 67, - 0, 0, 0, 0, 0, 0 -}; - -static const int json_start = 1; - -static const int json_en_number_machine = 23; -static const int json_en_string_machine = 32; -static const int json_en_duration_machine = 40; -static const int json_en_timestamp_machine = 47; -static const int json_en_fieldmask_machine = 75; -static const int json_en_value_machine = 78; -static const int json_en_main = 1; - - -#line 2790 "upb/json/parser.rl" - -size_t parse(void *closure, const void *hd, const char *buf, size_t size, - const upb_bufhandle *handle) { - upb_json_parser *parser = closure; - - /* Variables used by Ragel's generated code. */ - int cs = parser->current_state; - int *stack = parser->parser_stack; - int top = parser->parser_top; - - const char *p = buf; - const char *pe = buf + size; - const char *eof = &eof_ch; - - parser->handle = handle; - - UPB_UNUSED(hd); - UPB_UNUSED(handle); - - capture_resume(parser, buf); - - -#line 2868 "upb/json/parser.c" - { - int _klen; - unsigned int _trans; - const char *_acts; - unsigned int _nacts; - const char *_keys; - - if ( p == pe ) - goto _test_eof; - if ( cs == 0 ) - goto _out; -_resume: - _keys = _json_trans_keys + _json_key_offsets[cs]; - _trans = _json_index_offsets[cs]; - - _klen = _json_single_lengths[cs]; - if ( _klen > 0 ) { - const char *_lower = _keys; - const char *_mid; - const char *_upper = _keys + _klen - 1; - while (1) { - if ( _upper < _lower ) - break; - - _mid = _lower + ((_upper-_lower) >> 1); - if ( (*p) < *_mid ) - _upper = _mid - 1; - else if ( (*p) > *_mid ) - _lower = _mid + 1; - else { - _trans += (unsigned int)(_mid - _keys); - goto _match; - } - } - _keys += _klen; - _trans += _klen; - } - - _klen = _json_range_lengths[cs]; - if ( _klen > 0 ) { - const char *_lower = _keys; - const char *_mid; - const char *_upper = _keys + (_klen<<1) - 2; - while (1) { - if ( _upper < _lower ) - break; - - _mid = _lower + (((_upper-_lower) >> 1) & ~1); - if ( (*p) < _mid[0] ) - _upper = _mid - 2; - else if ( (*p) > _mid[1] ) - _lower = _mid + 2; - else { - _trans += (unsigned int)((_mid - _keys)>>1); - goto _match; - } - } - _trans += _klen; - } - -_match: - _trans = _json_indicies[_trans]; - cs = _json_trans_targs[_trans]; - - if ( _json_trans_actions[_trans] == 0 ) - goto _again; - - _acts = _json_actions + _json_trans_actions[_trans]; - _nacts = (unsigned int) *_acts++; - while ( _nacts-- > 0 ) - { - switch ( *_acts++ ) - { - case 1: -#line 2595 "upb/json/parser.rl" - { p--; {cs = stack[--top]; goto _again;} } - break; - case 2: -#line 2597 "upb/json/parser.rl" - { p--; {stack[top++] = cs; cs = 23;goto _again;} } - break; - case 3: -#line 2601 "upb/json/parser.rl" - { start_text(parser, p); } - break; - case 4: -#line 2602 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_text(parser, p)); } - break; - case 5: -#line 2608 "upb/json/parser.rl" - { start_hex(parser); } - break; - case 6: -#line 2609 "upb/json/parser.rl" - { hexdigit(parser, p); } - break; - case 7: -#line 2610 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_hex(parser)); } - break; - case 8: -#line 2616 "upb/json/parser.rl" - { CHECK_RETURN_TOP(escape(parser, p)); } - break; - case 9: -#line 2622 "upb/json/parser.rl" - { p--; {cs = stack[--top]; goto _again;} } - break; - case 10: -#line 2627 "upb/json/parser.rl" - { start_year(parser, p); } - break; - case 11: -#line 2628 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_year(parser, p)); } - break; - case 12: -#line 2632 "upb/json/parser.rl" - { start_month(parser, p); } - break; - case 13: -#line 2633 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_month(parser, p)); } - break; - case 14: -#line 2637 "upb/json/parser.rl" - { start_day(parser, p); } - break; - case 15: -#line 2638 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_day(parser, p)); } - break; - case 16: -#line 2642 "upb/json/parser.rl" - { start_hour(parser, p); } - break; - case 17: -#line 2643 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_hour(parser, p)); } - break; - case 18: -#line 2647 "upb/json/parser.rl" - { start_minute(parser, p); } - break; - case 19: -#line 2648 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_minute(parser, p)); } - break; - case 20: -#line 2652 "upb/json/parser.rl" - { start_second(parser, p); } - break; - case 21: -#line 2653 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_second(parser, p)); } - break; - case 22: -#line 2658 "upb/json/parser.rl" - { start_duration_base(parser, p); } - break; - case 23: -#line 2659 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_duration_base(parser, p)); } - break; - case 24: -#line 2661 "upb/json/parser.rl" - { p--; {cs = stack[--top]; goto _again;} } - break; - case 25: -#line 2666 "upb/json/parser.rl" - { start_timestamp_base(parser); } - break; - case 26: -#line 2668 "upb/json/parser.rl" - { start_timestamp_fraction(parser, p); } - break; - case 27: -#line 2669 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_timestamp_fraction(parser, p)); } - break; - case 28: -#line 2671 "upb/json/parser.rl" - { start_timestamp_zone(parser, p); } - break; - case 29: -#line 2672 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_timestamp_zone(parser, p)); } - break; - case 30: -#line 2674 "upb/json/parser.rl" - { p--; {cs = stack[--top]; goto _again;} } - break; - case 31: -#line 2679 "upb/json/parser.rl" - { start_fieldmask_path_text(parser, p); } - break; - case 32: -#line 2680 "upb/json/parser.rl" - { end_fieldmask_path_text(parser, p); } - break; - case 33: -#line 2685 "upb/json/parser.rl" - { start_fieldmask_path(parser); } - break; - case 34: -#line 2686 "upb/json/parser.rl" - { end_fieldmask_path(parser); } - break; - case 35: -#line 2692 "upb/json/parser.rl" - { p--; {cs = stack[--top]; goto _again;} } - break; - case 36: -#line 2697 "upb/json/parser.rl" - { - if (is_wellknown_msg(parser, UPB_WELLKNOWN_TIMESTAMP)) { - {stack[top++] = cs; cs = 47;goto _again;} - } else if (is_wellknown_msg(parser, UPB_WELLKNOWN_DURATION)) { - {stack[top++] = cs; cs = 40;goto _again;} - } else if (is_wellknown_msg(parser, UPB_WELLKNOWN_FIELDMASK)) { - {stack[top++] = cs; cs = 75;goto _again;} - } else { - {stack[top++] = cs; cs = 32;goto _again;} - } - } - break; - case 37: -#line 2710 "upb/json/parser.rl" - { p--; {stack[top++] = cs; cs = 78;goto _again;} } - break; - case 38: -#line 2715 "upb/json/parser.rl" - { - if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { - start_any_member(parser, p); - } else { - start_member(parser); - } - } - break; - case 39: -#line 2722 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_membername(parser)); } - break; - case 40: -#line 2725 "upb/json/parser.rl" - { - if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { - end_any_member(parser, p); - } else { - end_member(parser); - } - } - break; - case 41: -#line 2736 "upb/json/parser.rl" - { - if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { - start_any_object(parser, p); - } else { - start_object(parser); - } - } - break; - case 42: -#line 2745 "upb/json/parser.rl" - { - if (is_wellknown_msg(parser, UPB_WELLKNOWN_ANY)) { - CHECK_RETURN_TOP(end_any_object(parser, p)); - } else { - end_object(parser); - } - } - break; - case 43: -#line 2757 "upb/json/parser.rl" - { CHECK_RETURN_TOP(start_array(parser)); } - break; - case 44: -#line 2761 "upb/json/parser.rl" - { end_array(parser); } - break; - case 45: -#line 2766 "upb/json/parser.rl" - { CHECK_RETURN_TOP(start_number(parser, p)); } - break; - case 46: -#line 2767 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_number(parser, p)); } - break; - case 47: -#line 2769 "upb/json/parser.rl" - { CHECK_RETURN_TOP(start_stringval(parser)); } - break; - case 48: -#line 2770 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_stringval(parser)); } - break; - case 49: -#line 2772 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_bool(parser, true)); } - break; - case 50: -#line 2774 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_bool(parser, false)); } - break; - case 51: -#line 2776 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_null(parser)); } - break; - case 52: -#line 2778 "upb/json/parser.rl" - { CHECK_RETURN_TOP(start_subobject_full(parser)); } - break; - case 53: -#line 2779 "upb/json/parser.rl" - { end_subobject_full(parser); } - break; - case 54: -#line 2784 "upb/json/parser.rl" - { p--; {cs = stack[--top]; goto _again;} } - break; -#line 3192 "upb/json/parser.c" - } - } - -_again: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - const char *__acts = _json_actions + _json_eof_actions[cs]; - unsigned int __nacts = (unsigned int) *__acts++; - while ( __nacts-- > 0 ) { - switch ( *__acts++ ) { - case 0: -#line 2593 "upb/json/parser.rl" - { p--; {cs = stack[--top]; if ( p == pe ) - goto _test_eof; -goto _again;} } - break; - case 46: -#line 2767 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_number(parser, p)); } - break; - case 49: -#line 2772 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_bool(parser, true)); } - break; - case 50: -#line 2774 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_bool(parser, false)); } - break; - case 51: -#line 2776 "upb/json/parser.rl" - { CHECK_RETURN_TOP(end_null(parser)); } - break; - case 53: -#line 2779 "upb/json/parser.rl" - { end_subobject_full(parser); } - break; -#line 3234 "upb/json/parser.c" - } - } - } - - _out: {} - } - -#line 2812 "upb/json/parser.rl" - - if (p != pe) { - upb_status_seterrf(parser->status, "Parse error at '%.*s'\n", pe - p, p); - } else { - capture_suspend(parser, &p); - } - -error: - /* Save parsing state back to parser. */ - parser->current_state = cs; - parser->parser_top = top; - - return p - buf; -} - -static bool end(void *closure, const void *hd) { - upb_json_parser *parser = closure; - - /* Prevent compile warning on unused static constants. */ - UPB_UNUSED(json_start); - UPB_UNUSED(json_en_duration_machine); - UPB_UNUSED(json_en_fieldmask_machine); - UPB_UNUSED(json_en_number_machine); - UPB_UNUSED(json_en_string_machine); - UPB_UNUSED(json_en_timestamp_machine); - UPB_UNUSED(json_en_value_machine); - UPB_UNUSED(json_en_main); - - parse(parser, hd, &eof_ch, 0, NULL); - - return parser->current_state >= 106; -} - -static void json_parser_reset(upb_json_parser *p) { - int cs; - int top; - - p->top = p->stack; - init_frame(p->top); - - /* Emit Ragel initialization of the parser. */ - -#line 3285 "upb/json/parser.c" - { - cs = json_start; - top = 0; - } - -#line 2854 "upb/json/parser.rl" - p->current_state = cs; - p->parser_top = top; - accumulate_clear(p); - p->multipart_state = MULTIPART_INACTIVE; - p->capture = NULL; - p->accumulated = NULL; -} - -static upb_json_parsermethod *parsermethod_new(upb_json_codecache *c, - const upb_msgdef *md) { - upb_msg_field_iter i; - upb_alloc *alloc = upb_arena_alloc(c->arena); - - upb_json_parsermethod *m = upb_malloc(alloc, sizeof(*m)); - - m->cache = c; - - upb_byteshandler_init(&m->input_handler_); - upb_byteshandler_setstring(&m->input_handler_, parse, m); - upb_byteshandler_setendstr(&m->input_handler_, end, m); - - upb_strtable_init2(&m->name_table, UPB_CTYPE_CONSTPTR, alloc); - - /* Build name_table */ - - for(upb_msg_field_begin(&i, md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - upb_value v = upb_value_constptr(f); - const char *name; - - /* Add an entry for the JSON name. */ - name = upb_fielddef_jsonname(f); - upb_strtable_insert3(&m->name_table, name, strlen(name), v, alloc); - - if (strcmp(name, upb_fielddef_name(f)) != 0) { - /* Since the JSON name is different from the regular field name, add an - * entry for the raw name (compliant proto3 JSON parsers must accept - * both). */ - const char *name = upb_fielddef_name(f); - upb_strtable_insert3(&m->name_table, name, strlen(name), v, alloc); - } - } - - return m; -} - -/* Public API *****************************************************************/ - -upb_json_parser *upb_json_parser_create(upb_arena *arena, - const upb_json_parsermethod *method, - const upb_symtab* symtab, - upb_sink output, - upb_status *status, - bool ignore_json_unknown) { - upb_json_parser *p = upb_arena_malloc(arena, sizeof(upb_json_parser)); - if (!p) return false; - - p->arena = arena; - p->method = method; - p->status = status; - p->limit = p->stack + UPB_JSON_MAX_DEPTH; - p->accumulate_buf = NULL; - p->accumulate_buf_size = 0; - upb_bytessink_reset(&p->input_, &method->input_handler_, p); - - json_parser_reset(p); - p->top->sink = output; - p->top->m = upb_handlers_msgdef(output.handlers); - if (is_wellknown_msg(p, UPB_WELLKNOWN_ANY)) { - p->top->is_any = true; - p->top->any_frame = json_parser_any_frame_new(p); - } else { - p->top->is_any = false; - p->top->any_frame = NULL; - } - set_name_table(p, p->top); - p->symtab = symtab; - - p->ignore_json_unknown = ignore_json_unknown; - - return p; -} - -upb_bytessink upb_json_parser_input(upb_json_parser *p) { - return p->input_; -} - -const upb_byteshandler *upb_json_parsermethod_inputhandler( - const upb_json_parsermethod *m) { - return &m->input_handler_; -} - -upb_json_codecache *upb_json_codecache_new(void) { - upb_alloc *alloc; - upb_json_codecache *c; - - c = upb_gmalloc(sizeof(*c)); - - c->arena = upb_arena_new(); - alloc = upb_arena_alloc(c->arena); - - upb_inttable_init2(&c->methods, UPB_CTYPE_CONSTPTR, alloc); - - return c; -} - -void upb_json_codecache_free(upb_json_codecache *c) { - upb_arena_free(c->arena); - upb_gfree(c); -} - -const upb_json_parsermethod *upb_json_codecache_get(upb_json_codecache *c, - const upb_msgdef *md) { - upb_json_parsermethod *m; - upb_value v; - upb_msg_field_iter i; - upb_alloc *alloc = upb_arena_alloc(c->arena); - - if (upb_inttable_lookupptr(&c->methods, md, &v)) { - return upb_value_getconstptr(v); - } - - m = parsermethod_new(c, md); - v = upb_value_constptr(m); - - if (!m) return NULL; - if (!upb_inttable_insertptr2(&c->methods, md, v, alloc)) return NULL; - - /* Populate parser methods for all submessages, so the name tables will - * be available during parsing. */ - for(upb_msg_field_begin(&i, md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - - if (upb_fielddef_issubmsg(f)) { - const upb_msgdef *subdef = upb_fielddef_msgsubdef(f); - const upb_json_parsermethod *sub_method = - upb_json_codecache_get(c, subdef); - - if (!sub_method) return NULL; - } - } - - return m; -} -/* -** This currently uses snprintf() to format primitives, and could be optimized -** further. -*/ - - -#include -#include -#include -#include -#include - - -struct upb_json_printer { - upb_sink input_; - /* BytesSink closure. */ - void *subc_; - upb_bytessink output_; - - /* We track the depth so that we know when to emit startstr/endstr on the - * output. */ - int depth_; - - /* Have we emitted the first element? This state is necessary to emit commas - * without leaving a trailing comma in arrays/maps. We keep this state per - * frame depth. - * - * Why max_depth * 2? UPB_MAX_HANDLER_DEPTH counts depth as nested messages. - * We count frames (contexts in which we separate elements by commas) as both - * repeated fields and messages (maps), and the worst case is a - * message->repeated field->submessage->repeated field->... nesting. */ - bool first_elem_[UPB_MAX_HANDLER_DEPTH * 2]; - - /* To print timestamp, printer needs to cache its seconds and nanos values - * and convert them when ending timestamp message. See comments of - * printer_sethandlers_timestamp for more detail. */ - int64_t seconds; - int32_t nanos; -}; - -/* StringPiece; a pointer plus a length. */ -typedef struct { - char *ptr; - size_t len; -} strpc; - -void freestrpc(void *ptr) { - strpc *pc = ptr; - upb_gfree(pc->ptr); - upb_gfree(pc); -} - -typedef struct { - bool preserve_fieldnames; -} upb_json_printercache; - -/* Convert fielddef name to JSON name and return as a string piece. */ -strpc *newstrpc(upb_handlers *h, const upb_fielddef *f, - bool preserve_fieldnames) { - /* TODO(haberman): handle malloc failure. */ - strpc *ret = upb_gmalloc(sizeof(*ret)); - if (preserve_fieldnames) { - ret->ptr = upb_gstrdup(upb_fielddef_name(f)); - ret->len = strlen(ret->ptr); - } else { - ret->ptr = upb_gstrdup(upb_fielddef_jsonname(f)); - ret->len = strlen(ret->ptr); - } - - upb_handlers_addcleanup(h, ret, freestrpc); - return ret; -} - -/* Convert a null-terminated const char* to a string piece. */ -strpc *newstrpc_str(upb_handlers *h, const char * str) { - strpc * ret = upb_gmalloc(sizeof(*ret)); - ret->ptr = upb_gstrdup(str); - ret->len = strlen(str); - upb_handlers_addcleanup(h, ret, freestrpc); - return ret; -} - -/* ------------ JSON string printing: values, maps, arrays ------------------ */ - -static void print_data( - upb_json_printer *p, const char *buf, size_t len) { - /* TODO: Will need to change if we support pushback from the sink. */ - size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL); - UPB_ASSERT(n == len); -} - -static void print_comma(upb_json_printer *p) { - if (!p->first_elem_[p->depth_]) { - print_data(p, ",", 1); - } - p->first_elem_[p->depth_] = false; -} - -/* Helpers that print properly formatted elements to the JSON output stream. */ - -/* Used for escaping control chars in strings. */ -static const char kControlCharLimit = 0x20; - -UPB_INLINE bool is_json_escaped(char c) { - /* See RFC 4627. */ - unsigned char uc = (unsigned char)c; - return uc < kControlCharLimit || uc == '"' || uc == '\\'; -} - -UPB_INLINE const char* json_nice_escape(char c) { - switch (c) { - case '"': return "\\\""; - case '\\': return "\\\\"; - case '\b': return "\\b"; - case '\f': return "\\f"; - case '\n': return "\\n"; - case '\r': return "\\r"; - case '\t': return "\\t"; - default: return NULL; - } -} - -/* Write a properly escaped string chunk. The surrounding quotes are *not* - * printed; this is so that the caller has the option of emitting the string - * content in chunks. */ -static void putstring(upb_json_printer *p, const char *buf, size_t len) { - const char* unescaped_run = NULL; - unsigned int i; - for (i = 0; i < len; i++) { - char c = buf[i]; - /* Handle escaping. */ - if (is_json_escaped(c)) { - /* Use a "nice" escape, like \n, if one exists for this character. */ - const char* escape = json_nice_escape(c); - /* If we don't have a specific 'nice' escape code, use a \uXXXX-style - * escape. */ - char escape_buf[8]; - if (!escape) { - unsigned char byte = (unsigned char)c; - _upb_snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte); - escape = escape_buf; - } - - /* N.B. that we assume that the input encoding is equal to the output - * encoding (both UTF-8 for now), so for chars >= 0x20 and != \, ", we - * can simply pass the bytes through. */ - - /* If there's a current run of unescaped chars, print that run first. */ - if (unescaped_run) { - print_data(p, unescaped_run, &buf[i] - unescaped_run); - unescaped_run = NULL; - } - /* Then print the escape code. */ - print_data(p, escape, strlen(escape)); - } else { - /* Add to the current unescaped run of characters. */ - if (unescaped_run == NULL) { - unescaped_run = &buf[i]; - } - } - } - - /* If the string ended in a run of unescaped characters, print that last run. */ - if (unescaped_run) { - print_data(p, unescaped_run, &buf[len] - unescaped_run); - } -} - -#define CHKLENGTH(x) if (!(x)) return -1; - -/* Helpers that format floating point values according to our custom formats. - * Right now we use %.8g and %.17g for float/double, respectively, to match - * proto2::util::JsonFormat's defaults. May want to change this later. */ - -const char neginf[] = "\"-Infinity\""; -const char inf[] = "\"Infinity\""; - -static size_t fmt_double(double val, char* buf, size_t length) { - if (val == UPB_INFINITY) { - CHKLENGTH(length >= strlen(inf)); - strcpy(buf, inf); - return strlen(inf); - } else if (val == -UPB_INFINITY) { - CHKLENGTH(length >= strlen(neginf)); - strcpy(buf, neginf); - return strlen(neginf); - } else { - size_t n = _upb_snprintf(buf, length, "%.17g", val); - CHKLENGTH(n > 0 && n < length); - return n; - } -} - -static size_t fmt_float(float val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "%.8g", val); - CHKLENGTH(n > 0 && n < length); - return n; -} - -static size_t fmt_bool(bool val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "%s", (val ? "true" : "false")); - CHKLENGTH(n > 0 && n < length); - return n; -} - -static size_t fmt_int64_as_number(int64_t val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "%" PRId64, val); - CHKLENGTH(n > 0 && n < length); - return n; -} - -static size_t fmt_uint64_as_number(uint64_t val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "%" PRIu64, val); - CHKLENGTH(n > 0 && n < length); - return n; -} - -static size_t fmt_int64_as_string(int64_t val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "\"%" PRId64 "\"", val); - CHKLENGTH(n > 0 && n < length); - return n; -} - -static size_t fmt_uint64_as_string(uint64_t val, char* buf, size_t length) { - size_t n = _upb_snprintf(buf, length, "\"%" PRIu64 "\"", val); - CHKLENGTH(n > 0 && n < length); - return n; -} - -/* Print a map key given a field name. Called by scalar field handlers and by - * startseq for repeated fields. */ -static bool putkey(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - const strpc *key = handler_data; - print_comma(p); - print_data(p, "\"", 1); - putstring(p, key->ptr, key->len); - print_data(p, "\":", 2); - return true; -} - -#define CHKFMT(val) if ((val) == (size_t)-1) return false; -#define CHK(val) if (!(val)) return false; - -#define TYPE_HANDLERS(type, fmt_func) \ - static bool put##type(void *closure, const void *handler_data, type val) { \ - upb_json_printer *p = closure; \ - char data[64]; \ - size_t length = fmt_func(val, data, sizeof(data)); \ - UPB_UNUSED(handler_data); \ - CHKFMT(length); \ - print_data(p, data, length); \ - return true; \ - } \ - static bool scalar_##type(void *closure, const void *handler_data, \ - type val) { \ - CHK(putkey(closure, handler_data)); \ - CHK(put##type(closure, handler_data, val)); \ - return true; \ - } \ - static bool repeated_##type(void *closure, const void *handler_data, \ - type val) { \ - upb_json_printer *p = closure; \ - print_comma(p); \ - CHK(put##type(closure, handler_data, val)); \ - return true; \ - } - -#define TYPE_HANDLERS_MAPKEY(type, fmt_func) \ - static bool putmapkey_##type(void *closure, const void *handler_data, \ - type val) { \ - upb_json_printer *p = closure; \ - char data[64]; \ - size_t length = fmt_func(val, data, sizeof(data)); \ - UPB_UNUSED(handler_data); \ - print_data(p, "\"", 1); \ - print_data(p, data, length); \ - print_data(p, "\":", 2); \ - return true; \ - } - -TYPE_HANDLERS(double, fmt_double) -TYPE_HANDLERS(float, fmt_float) -TYPE_HANDLERS(bool, fmt_bool) -TYPE_HANDLERS(int32_t, fmt_int64_as_number) -TYPE_HANDLERS(uint32_t, fmt_int64_as_number) -TYPE_HANDLERS(int64_t, fmt_int64_as_string) -TYPE_HANDLERS(uint64_t, fmt_uint64_as_string) - -/* double and float are not allowed to be map keys. */ -TYPE_HANDLERS_MAPKEY(bool, fmt_bool) -TYPE_HANDLERS_MAPKEY(int32_t, fmt_int64_as_number) -TYPE_HANDLERS_MAPKEY(uint32_t, fmt_int64_as_number) -TYPE_HANDLERS_MAPKEY(int64_t, fmt_int64_as_number) -TYPE_HANDLERS_MAPKEY(uint64_t, fmt_uint64_as_number) - -#undef TYPE_HANDLERS -#undef TYPE_HANDLERS_MAPKEY - -typedef struct { - void *keyname; - const upb_enumdef *enumdef; -} EnumHandlerData; - -static bool scalar_enum(void *closure, const void *handler_data, - int32_t val) { - const EnumHandlerData *hd = handler_data; - upb_json_printer *p = closure; - const char *symbolic_name; - - CHK(putkey(closure, hd->keyname)); - - symbolic_name = upb_enumdef_iton(hd->enumdef, val); - if (symbolic_name) { - print_data(p, "\"", 1); - putstring(p, symbolic_name, strlen(symbolic_name)); - print_data(p, "\"", 1); - } else { - putint32_t(closure, NULL, val); - } - - return true; -} - -static void print_enum_symbolic_name(upb_json_printer *p, - const upb_enumdef *def, - int32_t val) { - const char *symbolic_name = upb_enumdef_iton(def, val); - if (symbolic_name) { - print_data(p, "\"", 1); - putstring(p, symbolic_name, strlen(symbolic_name)); - print_data(p, "\"", 1); - } else { - putint32_t(p, NULL, val); - } -} - -static bool repeated_enum(void *closure, const void *handler_data, - int32_t val) { - const EnumHandlerData *hd = handler_data; - upb_json_printer *p = closure; - print_comma(p); - - print_enum_symbolic_name(p, hd->enumdef, val); - - return true; -} - -static bool mapvalue_enum(void *closure, const void *handler_data, - int32_t val) { - const EnumHandlerData *hd = handler_data; - upb_json_printer *p = closure; - - print_enum_symbolic_name(p, hd->enumdef, val); - - return true; -} - -static void *scalar_startsubmsg(void *closure, const void *handler_data) { - return putkey(closure, handler_data) ? closure : UPB_BREAK; -} - -static void *repeated_startsubmsg(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - print_comma(p); - return closure; -} - -static void start_frame(upb_json_printer *p) { - p->depth_++; - p->first_elem_[p->depth_] = true; - print_data(p, "{", 1); -} - -static void end_frame(upb_json_printer *p) { - print_data(p, "}", 1); - p->depth_--; -} - -static bool printer_startmsg(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - if (p->depth_ == 0) { - upb_bytessink_start(p->output_, 0, &p->subc_); - } - start_frame(p); - return true; -} - -static bool printer_endmsg(void *closure, const void *handler_data, upb_status *s) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(s); - end_frame(p); - if (p->depth_ == 0) { - upb_bytessink_end(p->output_); - } - return true; -} - -static void *startseq(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - CHK(putkey(closure, handler_data)); - p->depth_++; - p->first_elem_[p->depth_] = true; - print_data(p, "[", 1); - return closure; -} - -static bool endseq(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - print_data(p, "]", 1); - p->depth_--; - return true; -} - -static void *startmap(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - CHK(putkey(closure, handler_data)); - p->depth_++; - p->first_elem_[p->depth_] = true; - print_data(p, "{", 1); - return closure; -} - -static bool endmap(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - print_data(p, "}", 1); - p->depth_--; - return true; -} - -static size_t putstr(void *closure, const void *handler_data, const char *str, - size_t len, const upb_bufhandle *handle) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(handle); - putstring(p, str, len); - return len; -} - -/* This has to Base64 encode the bytes, because JSON has no "bytes" type. */ -static size_t putbytes(void *closure, const void *handler_data, const char *str, - size_t len, const upb_bufhandle *handle) { - upb_json_printer *p = closure; - - /* This is the regular base64, not the "web-safe" version. */ - static const char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - /* Base64-encode. */ - char data[16000]; - const char *limit = data + sizeof(data); - const unsigned char *from = (const unsigned char*)str; - char *to = data; - size_t remaining = len; - size_t bytes; - - UPB_UNUSED(handler_data); - UPB_UNUSED(handle); - - print_data(p, "\"", 1); - - while (remaining > 2) { - if (limit - to < 4) { - bytes = to - data; - putstring(p, data, bytes); - to = data; - } - - to[0] = base64[from[0] >> 2]; - to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)]; - to[2] = base64[((from[1] & 0xf) << 2) | (from[2] >> 6)]; - to[3] = base64[from[2] & 0x3f]; - - remaining -= 3; - to += 4; - from += 3; - } - - switch (remaining) { - case 2: - to[0] = base64[from[0] >> 2]; - to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)]; - to[2] = base64[(from[1] & 0xf) << 2]; - to[3] = '='; - to += 4; - from += 2; - break; - case 1: - to[0] = base64[from[0] >> 2]; - to[1] = base64[((from[0] & 0x3) << 4)]; - to[2] = '='; - to[3] = '='; - to += 4; - from += 1; - break; - } - - bytes = to - data; - putstring(p, data, bytes); - print_data(p, "\"", 1); - return len; -} - -static void *scalar_startstr(void *closure, const void *handler_data, - size_t size_hint) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(size_hint); - CHK(putkey(closure, handler_data)); - print_data(p, "\"", 1); - return p; -} - -static size_t scalar_str(void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - CHK(putstr(closure, handler_data, str, len, handle)); - return len; -} - -static bool scalar_endstr(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - print_data(p, "\"", 1); - return true; -} - -static void *repeated_startstr(void *closure, const void *handler_data, - size_t size_hint) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(size_hint); - print_comma(p); - print_data(p, "\"", 1); - return p; -} - -static size_t repeated_str(void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - CHK(putstr(closure, handler_data, str, len, handle)); - return len; -} - -static bool repeated_endstr(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - print_data(p, "\"", 1); - return true; -} - -static void *mapkeyval_startstr(void *closure, const void *handler_data, - size_t size_hint) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(size_hint); - print_data(p, "\"", 1); - return p; -} - -static size_t mapkey_str(void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - CHK(putstr(closure, handler_data, str, len, handle)); - return len; -} - -static bool mapkey_endstr(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - print_data(p, "\":", 2); - return true; -} - -static bool mapvalue_endstr(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - print_data(p, "\"", 1); - return true; -} - -static size_t scalar_bytes(void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - CHK(putkey(closure, handler_data)); - CHK(putbytes(closure, handler_data, str, len, handle)); - return len; -} - -static size_t repeated_bytes(void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - upb_json_printer *p = closure; - print_comma(p); - CHK(putbytes(closure, handler_data, str, len, handle)); - return len; -} - -static size_t mapkey_bytes(void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - upb_json_printer *p = closure; - CHK(putbytes(closure, handler_data, str, len, handle)); - print_data(p, ":", 1); - return len; -} - -static void set_enum_hd(upb_handlers *h, - const upb_fielddef *f, - bool preserve_fieldnames, - upb_handlerattr *attr) { - EnumHandlerData *hd = upb_gmalloc(sizeof(EnumHandlerData)); - hd->enumdef = upb_fielddef_enumsubdef(f); - hd->keyname = newstrpc(h, f, preserve_fieldnames); - upb_handlers_addcleanup(h, hd, upb_gfree); - attr->handler_data = hd; -} - -/* Set up handlers for a mapentry submessage (i.e., an individual key/value pair - * in a map). - * - * TODO: Handle missing key, missing value, out-of-order key/value, or repeated - * key or value cases properly. The right way to do this is to allocate a - * temporary structure at the start of a mapentry submessage, store key and - * value data in it as key and value handlers are called, and then print the - * key/value pair once at the end of the submessage. If we don't do this, we - * should at least detect the case and throw an error. However, so far all of - * our sources that emit mapentry messages do so canonically (with one key - * field, and then one value field), so this is not a pressing concern at the - * moment. */ -void printer_sethandlers_mapentry(const void *closure, bool preserve_fieldnames, - upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - - /* A mapentry message is printed simply as '"key": value'. Rather than - * special-case key and value for every type below, we just handle both - * fields explicitly here. */ - const upb_fielddef* key_field = upb_msgdef_itof(md, UPB_MAPENTRY_KEY); - const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_MAPENTRY_VALUE); - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - UPB_UNUSED(closure); - - switch (upb_fielddef_type(key_field)) { - case UPB_TYPE_INT32: - upb_handlers_setint32(h, key_field, putmapkey_int32_t, &empty_attr); - break; - case UPB_TYPE_INT64: - upb_handlers_setint64(h, key_field, putmapkey_int64_t, &empty_attr); - break; - case UPB_TYPE_UINT32: - upb_handlers_setuint32(h, key_field, putmapkey_uint32_t, &empty_attr); - break; - case UPB_TYPE_UINT64: - upb_handlers_setuint64(h, key_field, putmapkey_uint64_t, &empty_attr); - break; - case UPB_TYPE_BOOL: - upb_handlers_setbool(h, key_field, putmapkey_bool, &empty_attr); - break; - case UPB_TYPE_STRING: - upb_handlers_setstartstr(h, key_field, mapkeyval_startstr, &empty_attr); - upb_handlers_setstring(h, key_field, mapkey_str, &empty_attr); - upb_handlers_setendstr(h, key_field, mapkey_endstr, &empty_attr); - break; - case UPB_TYPE_BYTES: - upb_handlers_setstring(h, key_field, mapkey_bytes, &empty_attr); - break; - default: - UPB_ASSERT(false); - break; - } - - switch (upb_fielddef_type(value_field)) { - case UPB_TYPE_INT32: - upb_handlers_setint32(h, value_field, putint32_t, &empty_attr); - break; - case UPB_TYPE_INT64: - upb_handlers_setint64(h, value_field, putint64_t, &empty_attr); - break; - case UPB_TYPE_UINT32: - upb_handlers_setuint32(h, value_field, putuint32_t, &empty_attr); - break; - case UPB_TYPE_UINT64: - upb_handlers_setuint64(h, value_field, putuint64_t, &empty_attr); - break; - case UPB_TYPE_BOOL: - upb_handlers_setbool(h, value_field, putbool, &empty_attr); - break; - case UPB_TYPE_FLOAT: - upb_handlers_setfloat(h, value_field, putfloat, &empty_attr); - break; - case UPB_TYPE_DOUBLE: - upb_handlers_setdouble(h, value_field, putdouble, &empty_attr); - break; - case UPB_TYPE_STRING: - upb_handlers_setstartstr(h, value_field, mapkeyval_startstr, &empty_attr); - upb_handlers_setstring(h, value_field, putstr, &empty_attr); - upb_handlers_setendstr(h, value_field, mapvalue_endstr, &empty_attr); - break; - case UPB_TYPE_BYTES: - upb_handlers_setstring(h, value_field, putbytes, &empty_attr); - break; - case UPB_TYPE_ENUM: { - upb_handlerattr enum_attr = UPB_HANDLERATTR_INIT; - set_enum_hd(h, value_field, preserve_fieldnames, &enum_attr); - upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr); - break; - } - case UPB_TYPE_MESSAGE: - /* No handler necessary -- the submsg handlers will print the message - * as appropriate. */ - break; - } -} - -static bool putseconds(void *closure, const void *handler_data, - int64_t seconds) { - upb_json_printer *p = closure; - p->seconds = seconds; - UPB_UNUSED(handler_data); - return true; -} - -static bool putnanos(void *closure, const void *handler_data, - int32_t nanos) { - upb_json_printer *p = closure; - p->nanos = nanos; - UPB_UNUSED(handler_data); - return true; -} - -static void *scalar_startstr_nokey(void *closure, const void *handler_data, - size_t size_hint) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(size_hint); - print_data(p, "\"", 1); - return p; -} - -static size_t putstr_nokey(void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(handle); - print_data(p, "\"", 1); - putstring(p, str, len); - print_data(p, "\"", 1); - return len + 2; -} - -static void *startseq_nokey(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - p->depth_++; - p->first_elem_[p->depth_] = true; - print_data(p, "[", 1); - return closure; -} - -static void *startseq_fieldmask(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - p->depth_++; - p->first_elem_[p->depth_] = true; - return closure; -} - -static bool endseq_fieldmask(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - p->depth_--; - return true; -} - -static void *repeated_startstr_fieldmask( - void *closure, const void *handler_data, - size_t size_hint) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(size_hint); - print_comma(p); - return p; -} - -static size_t repeated_str_fieldmask( - void *closure, const void *handler_data, - const char *str, size_t len, - const upb_bufhandle *handle) { - const char* limit = str + len; - bool upper = false; - size_t result_len = 0; - for (; str < limit; str++) { - if (*str == '_') { - upper = true; - continue; - } - if (upper && *str >= 'a' && *str <= 'z') { - char upper_char = toupper(*str); - CHK(putstr(closure, handler_data, &upper_char, 1, handle)); - } else { - CHK(putstr(closure, handler_data, str, 1, handle)); - } - upper = false; - result_len++; - } - return result_len; -} - -static void *startmap_nokey(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - p->depth_++; - p->first_elem_[p->depth_] = true; - print_data(p, "{", 1); - return closure; -} - -static bool putnull(void *closure, const void *handler_data, - int32_t null) { - upb_json_printer *p = closure; - print_data(p, "null", 4); - UPB_UNUSED(handler_data); - UPB_UNUSED(null); - return true; -} - -static bool printer_startdurationmsg(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - if (p->depth_ == 0) { - upb_bytessink_start(p->output_, 0, &p->subc_); - } - return true; -} - -#define UPB_DURATION_MAX_JSON_LEN 23 -#define UPB_DURATION_MAX_NANO_LEN 9 - -static bool printer_enddurationmsg(void *closure, const void *handler_data, - upb_status *s) { - upb_json_printer *p = closure; - char buffer[UPB_DURATION_MAX_JSON_LEN]; - size_t base_len; - size_t curr; - size_t i; - - memset(buffer, 0, UPB_DURATION_MAX_JSON_LEN); - - if (p->seconds < -315576000000) { - upb_status_seterrf(s, "error parsing duration: " - "minimum acceptable value is " - "-315576000000"); - return false; - } - - if (p->seconds > 315576000000) { - upb_status_seterrf(s, "error serializing duration: " - "maximum acceptable value is " - "315576000000"); - return false; - } - - _upb_snprintf(buffer, sizeof(buffer), "%ld", (long)p->seconds); - base_len = strlen(buffer); - - if (p->nanos != 0) { - char nanos_buffer[UPB_DURATION_MAX_NANO_LEN + 3]; - _upb_snprintf(nanos_buffer, sizeof(nanos_buffer), "%.9f", - p->nanos / 1000000000.0); - /* Remove trailing 0. */ - for (i = UPB_DURATION_MAX_NANO_LEN + 2; - nanos_buffer[i] == '0'; i--) { - nanos_buffer[i] = 0; - } - strcpy(buffer + base_len, nanos_buffer + 1); - } - - curr = strlen(buffer); - strcpy(buffer + curr, "s"); - - p->seconds = 0; - p->nanos = 0; - - print_data(p, "\"", 1); - print_data(p, buffer, strlen(buffer)); - print_data(p, "\"", 1); - - if (p->depth_ == 0) { - upb_bytessink_end(p->output_); - } - - UPB_UNUSED(handler_data); - return true; -} - -static bool printer_starttimestampmsg(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - if (p->depth_ == 0) { - upb_bytessink_start(p->output_, 0, &p->subc_); - } - return true; -} - -#define UPB_TIMESTAMP_MAX_JSON_LEN 31 -#define UPB_TIMESTAMP_BEFORE_NANO_LEN 19 -#define UPB_TIMESTAMP_MAX_NANO_LEN 9 - -static bool printer_endtimestampmsg(void *closure, const void *handler_data, - upb_status *s) { - upb_json_printer *p = closure; - char buffer[UPB_TIMESTAMP_MAX_JSON_LEN]; - time_t time = p->seconds; - size_t curr; - size_t i; - size_t year_length = - strftime(buffer, UPB_TIMESTAMP_MAX_JSON_LEN, "%Y", gmtime(&time)); - - if (p->seconds < -62135596800) { - upb_status_seterrf(s, "error parsing timestamp: " - "minimum acceptable value is " - "0001-01-01T00:00:00Z"); - return false; - } - - if (p->seconds > 253402300799) { - upb_status_seterrf(s, "error parsing timestamp: " - "maximum acceptable value is " - "9999-12-31T23:59:59Z"); - return false; - } - - /* strftime doesn't guarantee 4 digits for year. Prepend 0 by ourselves. */ - for (i = 0; i < 4 - year_length; i++) { - buffer[i] = '0'; - } - - strftime(buffer + (4 - year_length), UPB_TIMESTAMP_MAX_JSON_LEN, - "%Y-%m-%dT%H:%M:%S", gmtime(&time)); - if (p->nanos != 0) { - char nanos_buffer[UPB_TIMESTAMP_MAX_NANO_LEN + 3]; - _upb_snprintf(nanos_buffer, sizeof(nanos_buffer), "%.9f", - p->nanos / 1000000000.0); - /* Remove trailing 0. */ - for (i = UPB_TIMESTAMP_MAX_NANO_LEN + 2; - nanos_buffer[i] == '0'; i--) { - nanos_buffer[i] = 0; - } - strcpy(buffer + UPB_TIMESTAMP_BEFORE_NANO_LEN, nanos_buffer + 1); - } - - curr = strlen(buffer); - strcpy(buffer + curr, "Z"); - - p->seconds = 0; - p->nanos = 0; - - print_data(p, "\"", 1); - print_data(p, buffer, strlen(buffer)); - print_data(p, "\"", 1); - - if (p->depth_ == 0) { - upb_bytessink_end(p->output_); - } - - UPB_UNUSED(handler_data); - UPB_UNUSED(s); - return true; -} - -static bool printer_startmsg_noframe(void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - if (p->depth_ == 0) { - upb_bytessink_start(p->output_, 0, &p->subc_); - } - return true; -} - -static bool printer_endmsg_noframe( - void *closure, const void *handler_data, upb_status *s) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(s); - if (p->depth_ == 0) { - upb_bytessink_end(p->output_); - } - return true; -} - -static bool printer_startmsg_fieldmask( - void *closure, const void *handler_data) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - if (p->depth_ == 0) { - upb_bytessink_start(p->output_, 0, &p->subc_); - } - print_data(p, "\"", 1); - return true; -} - -static bool printer_endmsg_fieldmask( - void *closure, const void *handler_data, upb_status *s) { - upb_json_printer *p = closure; - UPB_UNUSED(handler_data); - UPB_UNUSED(s); - print_data(p, "\"", 1); - if (p->depth_ == 0) { - upb_bytessink_end(p->output_); - } - return true; -} - -static void *scalar_startstr_onlykey( - void *closure, const void *handler_data, size_t size_hint) { - upb_json_printer *p = closure; - UPB_UNUSED(size_hint); - CHK(putkey(closure, handler_data)); - return p; -} - -/* Set up handlers for an Any submessage. */ -void printer_sethandlers_any(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - - const upb_fielddef* type_field = upb_msgdef_itof(md, UPB_ANY_TYPE); - const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_ANY_VALUE); - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - /* type_url's json name is "@type" */ - upb_handlerattr type_name_attr = UPB_HANDLERATTR_INIT; - upb_handlerattr value_name_attr = UPB_HANDLERATTR_INIT; - strpc *type_url_json_name = newstrpc_str(h, "@type"); - strpc *value_json_name = newstrpc_str(h, "value"); - - type_name_attr.handler_data = type_url_json_name; - value_name_attr.handler_data = value_json_name; - - /* Set up handlers. */ - upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr); - upb_handlers_setendmsg(h, printer_endmsg, &empty_attr); - - upb_handlers_setstartstr(h, type_field, scalar_startstr, &type_name_attr); - upb_handlers_setstring(h, type_field, scalar_str, &empty_attr); - upb_handlers_setendstr(h, type_field, scalar_endstr, &empty_attr); - - /* This is not the full and correct JSON encoding for the Any value field. It - * requires further processing by the wrapper code based on the type URL. - */ - upb_handlers_setstartstr(h, value_field, scalar_startstr_onlykey, - &value_name_attr); - - UPB_UNUSED(closure); -} - -/* Set up handlers for a fieldmask submessage. */ -void printer_sethandlers_fieldmask(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - const upb_fielddef* f = upb_msgdef_itof(md, 1); - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - upb_handlers_setstartseq(h, f, startseq_fieldmask, &empty_attr); - upb_handlers_setendseq(h, f, endseq_fieldmask, &empty_attr); - - upb_handlers_setstartmsg(h, printer_startmsg_fieldmask, &empty_attr); - upb_handlers_setendmsg(h, printer_endmsg_fieldmask, &empty_attr); - - upb_handlers_setstartstr(h, f, repeated_startstr_fieldmask, &empty_attr); - upb_handlers_setstring(h, f, repeated_str_fieldmask, &empty_attr); - - UPB_UNUSED(closure); -} - -/* Set up handlers for a duration submessage. */ -void printer_sethandlers_duration(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - - const upb_fielddef* seconds_field = - upb_msgdef_itof(md, UPB_DURATION_SECONDS); - const upb_fielddef* nanos_field = - upb_msgdef_itof(md, UPB_DURATION_NANOS); - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - upb_handlers_setstartmsg(h, printer_startdurationmsg, &empty_attr); - upb_handlers_setint64(h, seconds_field, putseconds, &empty_attr); - upb_handlers_setint32(h, nanos_field, putnanos, &empty_attr); - upb_handlers_setendmsg(h, printer_enddurationmsg, &empty_attr); - - UPB_UNUSED(closure); -} - -/* Set up handlers for a timestamp submessage. Instead of printing fields - * separately, the json representation of timestamp follows RFC 3339 */ -void printer_sethandlers_timestamp(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - - const upb_fielddef* seconds_field = - upb_msgdef_itof(md, UPB_TIMESTAMP_SECONDS); - const upb_fielddef* nanos_field = - upb_msgdef_itof(md, UPB_TIMESTAMP_NANOS); - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - upb_handlers_setstartmsg(h, printer_starttimestampmsg, &empty_attr); - upb_handlers_setint64(h, seconds_field, putseconds, &empty_attr); - upb_handlers_setint32(h, nanos_field, putnanos, &empty_attr); - upb_handlers_setendmsg(h, printer_endtimestampmsg, &empty_attr); - - UPB_UNUSED(closure); -} - -void printer_sethandlers_value(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - upb_msg_field_iter i; - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - upb_handlers_setstartmsg(h, printer_startmsg_noframe, &empty_attr); - upb_handlers_setendmsg(h, printer_endmsg_noframe, &empty_attr); - - upb_msg_field_begin(&i, md); - for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - - switch (upb_fielddef_type(f)) { - case UPB_TYPE_ENUM: - upb_handlers_setint32(h, f, putnull, &empty_attr); - break; - case UPB_TYPE_DOUBLE: - upb_handlers_setdouble(h, f, putdouble, &empty_attr); - break; - case UPB_TYPE_STRING: - upb_handlers_setstartstr(h, f, scalar_startstr_nokey, &empty_attr); - upb_handlers_setstring(h, f, scalar_str, &empty_attr); - upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr); - break; - case UPB_TYPE_BOOL: - upb_handlers_setbool(h, f, putbool, &empty_attr); - break; - case UPB_TYPE_MESSAGE: - break; - default: - UPB_ASSERT(false); - break; - } - } - - UPB_UNUSED(closure); -} - -#define WRAPPER_SETHANDLERS(wrapper, type, putmethod) \ -void printer_sethandlers_##wrapper(const void *closure, upb_handlers *h) { \ - const upb_msgdef *md = upb_handlers_msgdef(h); \ - const upb_fielddef* f = upb_msgdef_itof(md, 1); \ - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; \ - upb_handlers_setstartmsg(h, printer_startmsg_noframe, &empty_attr); \ - upb_handlers_setendmsg(h, printer_endmsg_noframe, &empty_attr); \ - upb_handlers_set##type(h, f, putmethod, &empty_attr); \ - UPB_UNUSED(closure); \ -} - -WRAPPER_SETHANDLERS(doublevalue, double, putdouble) -WRAPPER_SETHANDLERS(floatvalue, float, putfloat) -WRAPPER_SETHANDLERS(int64value, int64, putint64_t) -WRAPPER_SETHANDLERS(uint64value, uint64, putuint64_t) -WRAPPER_SETHANDLERS(int32value, int32, putint32_t) -WRAPPER_SETHANDLERS(uint32value, uint32, putuint32_t) -WRAPPER_SETHANDLERS(boolvalue, bool, putbool) -WRAPPER_SETHANDLERS(stringvalue, string, putstr_nokey) -WRAPPER_SETHANDLERS(bytesvalue, string, putbytes) - -#undef WRAPPER_SETHANDLERS - -void printer_sethandlers_listvalue(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - const upb_fielddef* f = upb_msgdef_itof(md, 1); - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - upb_handlers_setstartseq(h, f, startseq_nokey, &empty_attr); - upb_handlers_setendseq(h, f, endseq, &empty_attr); - - upb_handlers_setstartmsg(h, printer_startmsg_noframe, &empty_attr); - upb_handlers_setendmsg(h, printer_endmsg_noframe, &empty_attr); - - upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &empty_attr); - - UPB_UNUSED(closure); -} - -void printer_sethandlers_structvalue(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - const upb_fielddef* f = upb_msgdef_itof(md, 1); - - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - - upb_handlers_setstartseq(h, f, startmap_nokey, &empty_attr); - upb_handlers_setendseq(h, f, endmap, &empty_attr); - - upb_handlers_setstartmsg(h, printer_startmsg_noframe, &empty_attr); - upb_handlers_setendmsg(h, printer_endmsg_noframe, &empty_attr); - - upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &empty_attr); - - UPB_UNUSED(closure); -} - -void printer_sethandlers(const void *closure, upb_handlers *h) { - const upb_msgdef *md = upb_handlers_msgdef(h); - bool is_mapentry = upb_msgdef_mapentry(md); - upb_handlerattr empty_attr = UPB_HANDLERATTR_INIT; - upb_msg_field_iter i; - const upb_json_printercache *cache = closure; - const bool preserve_fieldnames = cache->preserve_fieldnames; - - if (is_mapentry) { - /* mapentry messages are sufficiently different that we handle them - * separately. */ - printer_sethandlers_mapentry(closure, preserve_fieldnames, h); - return; - } - - switch (upb_msgdef_wellknowntype(md)) { - case UPB_WELLKNOWN_UNSPECIFIED: - break; - case UPB_WELLKNOWN_ANY: - printer_sethandlers_any(closure, h); - return; - case UPB_WELLKNOWN_FIELDMASK: - printer_sethandlers_fieldmask(closure, h); - return; - case UPB_WELLKNOWN_DURATION: - printer_sethandlers_duration(closure, h); - return; - case UPB_WELLKNOWN_TIMESTAMP: - printer_sethandlers_timestamp(closure, h); - return; - case UPB_WELLKNOWN_VALUE: - printer_sethandlers_value(closure, h); - return; - case UPB_WELLKNOWN_LISTVALUE: - printer_sethandlers_listvalue(closure, h); - return; - case UPB_WELLKNOWN_STRUCT: - printer_sethandlers_structvalue(closure, h); - return; -#define WRAPPER(wellknowntype, name) \ - case wellknowntype: \ - printer_sethandlers_##name(closure, h); \ - return; \ - - WRAPPER(UPB_WELLKNOWN_DOUBLEVALUE, doublevalue); - WRAPPER(UPB_WELLKNOWN_FLOATVALUE, floatvalue); - WRAPPER(UPB_WELLKNOWN_INT64VALUE, int64value); - WRAPPER(UPB_WELLKNOWN_UINT64VALUE, uint64value); - WRAPPER(UPB_WELLKNOWN_INT32VALUE, int32value); - WRAPPER(UPB_WELLKNOWN_UINT32VALUE, uint32value); - WRAPPER(UPB_WELLKNOWN_BOOLVALUE, boolvalue); - WRAPPER(UPB_WELLKNOWN_STRINGVALUE, stringvalue); - WRAPPER(UPB_WELLKNOWN_BYTESVALUE, bytesvalue); - -#undef WRAPPER - } - - upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr); - upb_handlers_setendmsg(h, printer_endmsg, &empty_attr); - -#define TYPE(type, name, ctype) \ - case type: \ - if (upb_fielddef_isseq(f)) { \ - upb_handlers_set##name(h, f, repeated_##ctype, &empty_attr); \ - } else { \ - upb_handlers_set##name(h, f, scalar_##ctype, &name_attr); \ - } \ - break; - - upb_msg_field_begin(&i, md); - for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - - upb_handlerattr name_attr = UPB_HANDLERATTR_INIT; - name_attr.handler_data = newstrpc(h, f, preserve_fieldnames); - - if (upb_fielddef_ismap(f)) { - upb_handlers_setstartseq(h, f, startmap, &name_attr); - upb_handlers_setendseq(h, f, endmap, &name_attr); - } else if (upb_fielddef_isseq(f)) { - upb_handlers_setstartseq(h, f, startseq, &name_attr); - upb_handlers_setendseq(h, f, endseq, &empty_attr); - } - - switch (upb_fielddef_type(f)) { - TYPE(UPB_TYPE_FLOAT, float, float); - TYPE(UPB_TYPE_DOUBLE, double, double); - TYPE(UPB_TYPE_BOOL, bool, bool); - TYPE(UPB_TYPE_INT32, int32, int32_t); - TYPE(UPB_TYPE_UINT32, uint32, uint32_t); - TYPE(UPB_TYPE_INT64, int64, int64_t); - TYPE(UPB_TYPE_UINT64, uint64, uint64_t); - case UPB_TYPE_ENUM: { - /* For now, we always emit symbolic names for enums. We may want an - * option later to control this behavior, but we will wait for a real - * need first. */ - upb_handlerattr enum_attr = UPB_HANDLERATTR_INIT; - set_enum_hd(h, f, preserve_fieldnames, &enum_attr); - - if (upb_fielddef_isseq(f)) { - upb_handlers_setint32(h, f, repeated_enum, &enum_attr); - } else { - upb_handlers_setint32(h, f, scalar_enum, &enum_attr); - } - - break; - } - case UPB_TYPE_STRING: - if (upb_fielddef_isseq(f)) { - upb_handlers_setstartstr(h, f, repeated_startstr, &empty_attr); - upb_handlers_setstring(h, f, repeated_str, &empty_attr); - upb_handlers_setendstr(h, f, repeated_endstr, &empty_attr); - } else { - upb_handlers_setstartstr(h, f, scalar_startstr, &name_attr); - upb_handlers_setstring(h, f, scalar_str, &empty_attr); - upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr); - } - break; - case UPB_TYPE_BYTES: - /* XXX: this doesn't support strings that span buffers yet. The base64 - * encoder will need to be made resumable for this to work properly. */ - if (upb_fielddef_isseq(f)) { - upb_handlers_setstring(h, f, repeated_bytes, &empty_attr); - } else { - upb_handlers_setstring(h, f, scalar_bytes, &name_attr); - } - break; - case UPB_TYPE_MESSAGE: - if (upb_fielddef_isseq(f)) { - upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr); - } else { - upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr); - } - break; - } - } - -#undef TYPE -} - -static void json_printer_reset(upb_json_printer *p) { - p->depth_ = 0; -} - - -/* Public API *****************************************************************/ - -upb_json_printer *upb_json_printer_create(upb_arena *a, const upb_handlers *h, - upb_bytessink output) { - upb_json_printer *p = upb_arena_malloc(a, sizeof(upb_json_printer)); - if (!p) return NULL; - - p->output_ = output; - json_printer_reset(p); - upb_sink_reset(&p->input_, h, p); - p->seconds = 0; - p->nanos = 0; - - return p; -} - -upb_sink upb_json_printer_input(upb_json_printer *p) { - return p->input_; -} - -upb_handlercache *upb_json_printer_newcache(bool preserve_proto_fieldnames) { - upb_json_printercache *cache = upb_gmalloc(sizeof(*cache)); - upb_handlercache *ret = upb_handlercache_new(printer_sethandlers, cache); - - cache->preserve_fieldnames = preserve_proto_fieldnames; - upb_handlercache_addcleanup(ret, cache, upb_gfree); - - return ret; -} -/* See port_def.inc. This should #undef all macros #defined there. */ - -#undef UPB_MAPTYPE_STRING -#undef UPB_SIZE -#undef UPB_PTR_AT -#undef UPB_READ_ONEOF -#undef UPB_WRITE_ONEOF -#undef UPB_INLINE -#undef UPB_ALIGN_UP -#undef UPB_ALIGN_DOWN -#undef UPB_ALIGN_MALLOC -#undef UPB_ALIGN_OF -#undef UPB_FORCEINLINE -#undef UPB_NOINLINE -#undef UPB_NORETURN -#undef UPB_MAX -#undef UPB_MIN -#undef UPB_UNUSED -#undef UPB_ASSUME -#undef UPB_ASSERT -#undef UPB_ASSERT_DEBUGVAR -#undef UPB_UNREACHABLE -#undef UPB_INFINITY -#undef UPB_MSVC_VSNPRINTF -#undef _upb_snprintf -#undef _upb_vsnprintf -#undef _upb_va_copy diff --git a/php/ext/google/protobuf/upb.h b/php/ext/google/protobuf/upb.h deleted file mode 100644 index 179e49877742..000000000000 --- a/php/ext/google/protobuf/upb.h +++ /dev/null @@ -1,6796 +0,0 @@ -/* Amalgamated source file */ - -// php.h intentionally defined NDEBUG. We have to define this macro in order to -// be used together with php.h -#ifndef NDEBUG -#define NDEBUG -#endif - -#include /* -* This is where we define macros used across upb. -* -* All of these macros are undef'd in port_undef.inc to avoid leaking them to -* users. -* -* The correct usage is: -* -* #include "upb/foobar.h" -* #include "upb/baz.h" -* -* // MUST be last included header. -* #include "upb/port_def.inc" -* -* // Code for this file. -* // <...> -* -* // Can be omitted for .c files, required for .h. -* #include "upb/port_undef.inc" -* -* This file is private and must not be included by users! -*/ -#include -#include - -#if UINTPTR_MAX == 0xffffffff -#define UPB_SIZE(size32, size64) size32 -#else -#define UPB_SIZE(size32, size64) size64 -#endif - -/* If we always read/write as a consistent type to each address, this shouldn't - * violate aliasing. - */ -#define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) - -#define UPB_READ_ONEOF(msg, fieldtype, offset, case_offset, case_val, default) \ - *UPB_PTR_AT(msg, case_offset, int) == case_val \ - ? *UPB_PTR_AT(msg, offset, fieldtype) \ - : default - -#define UPB_WRITE_ONEOF(msg, fieldtype, offset, value, case_offset, case_val) \ - *UPB_PTR_AT(msg, case_offset, int) = case_val; \ - *UPB_PTR_AT(msg, offset, fieldtype) = value; - -#define UPB_MAPTYPE_STRING 0 - -/* UPB_INLINE: inline if possible, emit standalone code if required. */ -#ifdef __cplusplus -#define UPB_INLINE inline -#elif defined (__GNUC__) || defined(__clang__) -#define UPB_INLINE static __inline__ -#else -#define UPB_INLINE static -#endif - -#define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) -#define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) -#define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, 16) -#define UPB_ALIGN_OF(type) offsetof (struct { char c; type member; }, member) - -/* Hints to the compiler about likely/unlikely branches. */ -#if defined (__GNUC__) || defined(__clang__) -#define UPB_LIKELY(x) __builtin_expect((x),1) -#define UPB_UNLIKELY(x) __builtin_expect((x),0) -#else -#define UPB_LIKELY(x) (x) -#define UPB_UNLIKELY(x) (x) -#endif - -/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler - * doesn't provide these preprocessor symbols. */ -#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define UPB_BIG_ENDIAN -#endif - -/* Macros for function attributes on compilers that support them. */ -#ifdef __GNUC__ -#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) -#define UPB_NOINLINE __attribute__((noinline)) -#define UPB_NORETURN __attribute__((__noreturn__)) -#else /* !defined(__GNUC__) */ -#define UPB_FORCEINLINE -#define UPB_NOINLINE -#define UPB_NORETURN -#endif - -#if __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L -/* C99/C++11 versions. */ -#include -#define _upb_snprintf snprintf -#define _upb_vsnprintf vsnprintf -#define _upb_va_copy(a, b) va_copy(a, b) -#elif defined(_MSC_VER) -/* Microsoft C/C++ versions. */ -#include -#include -#if _MSC_VER < 1900 -int msvc_snprintf(char* s, size_t n, const char* format, ...); -int msvc_vsnprintf(char* s, size_t n, const char* format, va_list arg); -#define UPB_MSVC_VSNPRINTF -#define _upb_snprintf msvc_snprintf -#define _upb_vsnprintf msvc_vsnprintf -#else -#define _upb_snprintf snprintf -#define _upb_vsnprintf vsnprintf -#endif -#define _upb_va_copy(a, b) va_copy(a, b) -#elif defined __GNUC__ -/* A few hacky workarounds for functions not in C89. - * For internal use only! - * TODO(haberman): fix these by including our own implementations, or finding - * another workaround. - */ -#define _upb_snprintf __builtin_snprintf -#define _upb_vsnprintf __builtin_vsnprintf -#define _upb_va_copy(a, b) __va_copy(a, b) -#else -#error Need implementations of [v]snprintf and va_copy -#endif - -#ifdef __cplusplus -#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || \ - (defined(_MSC_VER) && _MSC_VER >= 1900) -/* C++11 is present */ -#else -#error upb requires C++11 for C++ support -#endif -#endif - -#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) -#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) - -#define UPB_UNUSED(var) (void)var - -/* UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. - */ -#ifdef NDEBUG -#ifdef __GNUC__ -#define UPB_ASSUME(expr) if (!(expr)) __builtin_unreachable() -#else -#define UPB_ASSUME(expr) do {} if (false && (expr)) -#endif -#else -#define UPB_ASSUME(expr) assert(expr) -#endif - -/* UPB_ASSERT(): in release mode, we use the expression without letting it be - * evaluated. This prevents "unused variable" warnings. */ -#ifdef NDEBUG -#define UPB_ASSERT(expr) do {} while (false && (expr)) -#else -#define UPB_ASSERT(expr) assert(expr) -#endif - -/* UPB_ASSERT_DEBUGVAR(): assert that uses functions or variables that only - * exist in debug mode. This turns into regular assert. */ -#define UPB_ASSERT_DEBUGVAR(expr) assert(expr) - -#if defined(__GNUC__) || defined(__clang__) -#define UPB_UNREACHABLE() do { assert(0); __builtin_unreachable(); } while(0) -#else -#define UPB_UNREACHABLE() do { assert(0); } while(0) -#endif - -/* UPB_INFINITY representing floating-point positive infinity. */ -#include -#ifdef INFINITY -#define UPB_INFINITY INFINITY -#else -#define UPB_INFINITY (1.0 / 0.0) -#endif -/* -** upb_decode: parsing into a upb_msg using a upb_msglayout. -*/ - -#ifndef UPB_DECODE_H_ -#define UPB_DECODE_H_ - -/* -** Our memory representation for parsing tables and messages themselves. -** Functions in this file are used by generated code and possibly reflection. -** -** The definitions in this file are internal to upb. -**/ - -#ifndef UPB_MSG_H_ -#define UPB_MSG_H_ - -#include -#include - -/* -** upb_table -** -** This header is INTERNAL-ONLY! Its interfaces are not public or stable! -** This file defines very fast int->upb_value (inttable) and string->upb_value -** (strtable) hash tables. -** -** The table uses chained scatter with Brent's variation (inspired by the Lua -** implementation of hash tables). The hash function for strings is Austin -** Appleby's "MurmurHash." -** -** The inttable uses uintptr_t as its key, which guarantees it can be used to -** store pointers or integers of at least 32 bits (upb isn't really useful on -** systems where sizeof(void*) < 4). -** -** The table must be homogenous (all values of the same type). In debug -** mode, we check this on insert and lookup. -*/ - -#ifndef UPB_TABLE_H_ -#define UPB_TABLE_H_ - -#include -#include -/* -** This file contains shared definitions that are widely used across upb. -*/ - -#ifndef UPB_H_ -#define UPB_H_ - -#include -#include -#include -#include -#include -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_status *****************************************************************/ - -#define UPB_STATUS_MAX_MESSAGE 127 - -typedef struct { - bool ok; - char msg[UPB_STATUS_MAX_MESSAGE]; /* Error message; NULL-terminated. */ -} upb_status; - -const char *upb_status_errmsg(const upb_status *status); -bool upb_ok(const upb_status *status); - -/* These are no-op if |status| is NULL. */ -void upb_status_clear(upb_status *status); -void upb_status_seterrmsg(upb_status *status, const char *msg); -void upb_status_seterrf(upb_status *status, const char *fmt, ...); -void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args); - -/** upb_strview ************************************************************/ - -typedef struct { - const char *data; - size_t size; -} upb_strview; - -UPB_INLINE upb_strview upb_strview_make(const char *data, size_t size) { - upb_strview ret; - ret.data = data; - ret.size = size; - return ret; -} - -UPB_INLINE upb_strview upb_strview_makez(const char *data) { - return upb_strview_make(data, strlen(data)); -} - -UPB_INLINE bool upb_strview_eql(upb_strview a, upb_strview b) { - return a.size == b.size && memcmp(a.data, b.data, a.size) == 0; -} - -#define UPB_STRVIEW_INIT(ptr, len) {ptr, len} - -#define UPB_STRVIEW_FORMAT "%.*s" -#define UPB_STRVIEW_ARGS(view) (int)(view).size, (view).data - -/** upb_alloc *****************************************************************/ - -/* A upb_alloc is a possibly-stateful allocator object. - * - * It could either be an arena allocator (which doesn't require individual - * free() calls) or a regular malloc() (which does). The client must therefore - * free memory unless it knows that the allocator is an arena allocator. */ - -struct upb_alloc; -typedef struct upb_alloc upb_alloc; - -/* A malloc()/free() function. - * If "size" is 0 then the function acts like free(), otherwise it acts like - * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */ -typedef void *upb_alloc_func(upb_alloc *alloc, void *ptr, size_t oldsize, - size_t size); - -struct upb_alloc { - upb_alloc_func *func; -}; - -UPB_INLINE void *upb_malloc(upb_alloc *alloc, size_t size) { - UPB_ASSERT(alloc); - return alloc->func(alloc, NULL, 0, size); -} - -UPB_INLINE void *upb_realloc(upb_alloc *alloc, void *ptr, size_t oldsize, - size_t size) { - UPB_ASSERT(alloc); - return alloc->func(alloc, ptr, oldsize, size); -} - -UPB_INLINE void upb_free(upb_alloc *alloc, void *ptr) { - assert(alloc); - alloc->func(alloc, ptr, 0, 0); -} - -/* The global allocator used by upb. Uses the standard malloc()/free(). */ - -extern upb_alloc upb_alloc_global; - -/* Functions that hard-code the global malloc. - * - * We still get benefit because we can put custom logic into our global - * allocator, like injecting out-of-memory faults in debug/testing builds. */ - -UPB_INLINE void *upb_gmalloc(size_t size) { - return upb_malloc(&upb_alloc_global, size); -} - -UPB_INLINE void *upb_grealloc(void *ptr, size_t oldsize, size_t size) { - return upb_realloc(&upb_alloc_global, ptr, oldsize, size); -} - -UPB_INLINE void upb_gfree(void *ptr) { - upb_free(&upb_alloc_global, ptr); -} - -/* upb_arena ******************************************************************/ - -/* upb_arena is a specific allocator implementation that uses arena allocation. - * The user provides an allocator that will be used to allocate the underlying - * arena blocks. Arenas by nature do not require the individual allocations - * to be freed. However the Arena does allow users to register cleanup - * functions that will run when the arena is destroyed. - * - * A upb_arena is *not* thread-safe. - * - * You could write a thread-safe arena allocator that satisfies the - * upb_alloc interface, but it would not be as efficient for the - * single-threaded case. */ - -typedef void upb_cleanup_func(void *ud); - -struct upb_arena; -typedef struct upb_arena upb_arena; - -typedef struct { - /* We implement the allocator interface. - * This must be the first member of upb_arena! - * TODO(haberman): remove once handlers are gone. */ - upb_alloc alloc; - - char *ptr, *end; -} _upb_arena_head; - -/* Creates an arena from the given initial block (if any -- n may be 0). - * Additional blocks will be allocated from |alloc|. If |alloc| is NULL, this - * is a fixed-size arena and cannot grow. */ -upb_arena *upb_arena_init(void *mem, size_t n, upb_alloc *alloc); -void upb_arena_free(upb_arena *a); -bool upb_arena_addcleanup(upb_arena *a, void *ud, upb_cleanup_func *func); -void upb_arena_fuse(upb_arena *a, upb_arena *b); -void *_upb_arena_slowmalloc(upb_arena *a, size_t size); - -UPB_INLINE upb_alloc *upb_arena_alloc(upb_arena *a) { return (upb_alloc*)a; } - -UPB_INLINE void *upb_arena_malloc(upb_arena *a, size_t size) { - _upb_arena_head *h = (_upb_arena_head*)a; - void* ret; - size = UPB_ALIGN_MALLOC(size); - - if (UPB_UNLIKELY((size_t)(h->end - h->ptr) < size)) { - return _upb_arena_slowmalloc(a, size); - } - - ret = h->ptr; - h->ptr += size; - return ret; -} - -UPB_INLINE void *upb_arena_realloc(upb_arena *a, void *ptr, size_t oldsize, - size_t size) { - void *ret = upb_arena_malloc(a, size); - - if (ret && oldsize > 0) { - memcpy(ret, ptr, oldsize); - } - - return ret; -} - -UPB_INLINE upb_arena *upb_arena_new(void) { - return upb_arena_init(NULL, 0, &upb_alloc_global); -} - -/* Constants ******************************************************************/ - -/* Generic function type. */ -typedef void upb_func(void); - -/* A list of types as they are encoded on-the-wire. */ -typedef enum { - UPB_WIRE_TYPE_VARINT = 0, - UPB_WIRE_TYPE_64BIT = 1, - UPB_WIRE_TYPE_DELIMITED = 2, - UPB_WIRE_TYPE_START_GROUP = 3, - UPB_WIRE_TYPE_END_GROUP = 4, - UPB_WIRE_TYPE_32BIT = 5 -} upb_wiretype_t; - -/* The types a field can have. Note that this list is not identical to the - * types defined in descriptor.proto, which gives INT32 and SINT32 separate - * types (we distinguish the two with the "integer encoding" enum below). */ -typedef enum { - UPB_TYPE_BOOL = 1, - UPB_TYPE_FLOAT = 2, - UPB_TYPE_INT32 = 3, - UPB_TYPE_UINT32 = 4, - UPB_TYPE_ENUM = 5, /* Enum values are int32. */ - UPB_TYPE_MESSAGE = 6, - UPB_TYPE_DOUBLE = 7, - UPB_TYPE_INT64 = 8, - UPB_TYPE_UINT64 = 9, - UPB_TYPE_STRING = 10, - UPB_TYPE_BYTES = 11 -} upb_fieldtype_t; - -/* The repeated-ness of each field; this matches descriptor.proto. */ -typedef enum { - UPB_LABEL_OPTIONAL = 1, - UPB_LABEL_REQUIRED = 2, - UPB_LABEL_REPEATED = 3 -} upb_label_t; - -/* Descriptor types, as defined in descriptor.proto. */ -typedef enum { - /* Old (long) names. TODO(haberman): remove */ - UPB_DESCRIPTOR_TYPE_DOUBLE = 1, - UPB_DESCRIPTOR_TYPE_FLOAT = 2, - UPB_DESCRIPTOR_TYPE_INT64 = 3, - UPB_DESCRIPTOR_TYPE_UINT64 = 4, - UPB_DESCRIPTOR_TYPE_INT32 = 5, - UPB_DESCRIPTOR_TYPE_FIXED64 = 6, - UPB_DESCRIPTOR_TYPE_FIXED32 = 7, - UPB_DESCRIPTOR_TYPE_BOOL = 8, - UPB_DESCRIPTOR_TYPE_STRING = 9, - UPB_DESCRIPTOR_TYPE_GROUP = 10, - UPB_DESCRIPTOR_TYPE_MESSAGE = 11, - UPB_DESCRIPTOR_TYPE_BYTES = 12, - UPB_DESCRIPTOR_TYPE_UINT32 = 13, - UPB_DESCRIPTOR_TYPE_ENUM = 14, - UPB_DESCRIPTOR_TYPE_SFIXED32 = 15, - UPB_DESCRIPTOR_TYPE_SFIXED64 = 16, - UPB_DESCRIPTOR_TYPE_SINT32 = 17, - UPB_DESCRIPTOR_TYPE_SINT64 = 18, - - UPB_DTYPE_DOUBLE = 1, - UPB_DTYPE_FLOAT = 2, - UPB_DTYPE_INT64 = 3, - UPB_DTYPE_UINT64 = 4, - UPB_DTYPE_INT32 = 5, - UPB_DTYPE_FIXED64 = 6, - UPB_DTYPE_FIXED32 = 7, - UPB_DTYPE_BOOL = 8, - UPB_DTYPE_STRING = 9, - UPB_DTYPE_GROUP = 10, - UPB_DTYPE_MESSAGE = 11, - UPB_DTYPE_BYTES = 12, - UPB_DTYPE_UINT32 = 13, - UPB_DTYPE_ENUM = 14, - UPB_DTYPE_SFIXED32 = 15, - UPB_DTYPE_SFIXED64 = 16, - UPB_DTYPE_SINT32 = 17, - UPB_DTYPE_SINT64 = 18 -} upb_descriptortype_t; - -#define UPB_MAP_BEGIN -1 - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_H_ */ - - -#ifdef __cplusplus -extern "C" { -#endif - - -/* upb_value ******************************************************************/ - -/* A tagged union (stored untagged inside the table) so that we can check that - * clients calling table accessors are correctly typed without having to have - * an explosion of accessors. */ -typedef enum { - UPB_CTYPE_INT32 = 1, - UPB_CTYPE_INT64 = 2, - UPB_CTYPE_UINT32 = 3, - UPB_CTYPE_UINT64 = 4, - UPB_CTYPE_BOOL = 5, - UPB_CTYPE_CSTR = 6, - UPB_CTYPE_PTR = 7, - UPB_CTYPE_CONSTPTR = 8, - UPB_CTYPE_FPTR = 9, - UPB_CTYPE_FLOAT = 10, - UPB_CTYPE_DOUBLE = 11 -} upb_ctype_t; - -typedef struct { - uint64_t val; -} upb_value; - -/* Like strdup(), which isn't always available since it's not ANSI C. */ -char *upb_strdup(const char *s, upb_alloc *a); -/* Variant that works with a length-delimited rather than NULL-delimited string, - * as supported by strtable. */ -char *upb_strdup2(const char *s, size_t len, upb_alloc *a); - -UPB_INLINE char *upb_gstrdup(const char *s) { - return upb_strdup(s, &upb_alloc_global); -} - -UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val) { - v->val = val; -} - -UPB_INLINE upb_value _upb_value_val(uint64_t val) { - upb_value ret; - _upb_value_setval(&ret, val); - return ret; -} - -/* For each value ctype, define the following set of functions: - * - * // Get/set an int32 from a upb_value. - * int32_t upb_value_getint32(upb_value val); - * void upb_value_setint32(upb_value *val, int32_t cval); - * - * // Construct a new upb_value from an int32. - * upb_value upb_value_int32(int32_t val); */ -#define FUNCS(name, membername, type_t, converter, proto_type) \ - UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \ - val->val = (converter)cval; \ - } \ - UPB_INLINE upb_value upb_value_ ## name(type_t val) { \ - upb_value ret; \ - upb_value_set ## name(&ret, val); \ - return ret; \ - } \ - UPB_INLINE type_t upb_value_get ## name(upb_value val) { \ - return (type_t)(converter)val.val; \ - } - -FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32) -FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64) -FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32) -FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64) -FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL) -FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR) -FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR) -FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR) -FUNCS(fptr, fptr, upb_func*, uintptr_t, UPB_CTYPE_FPTR) - -#undef FUNCS - -UPB_INLINE void upb_value_setfloat(upb_value *val, float cval) { - memcpy(&val->val, &cval, sizeof(cval)); -} - -UPB_INLINE void upb_value_setdouble(upb_value *val, double cval) { - memcpy(&val->val, &cval, sizeof(cval)); -} - -UPB_INLINE upb_value upb_value_float(float cval) { - upb_value ret; - upb_value_setfloat(&ret, cval); - return ret; -} - -UPB_INLINE upb_value upb_value_double(double cval) { - upb_value ret; - upb_value_setdouble(&ret, cval); - return ret; -} - -#undef SET_TYPE - - -/* upb_tabkey *****************************************************************/ - -/* Either: - * 1. an actual integer key, or - * 2. a pointer to a string prefixed by its uint32_t length, owned by us. - * - * ...depending on whether this is a string table or an int table. We would - * make this a union of those two types, but C89 doesn't support statically - * initializing a non-first union member. */ -typedef uintptr_t upb_tabkey; - -UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) { - char* mem = (char*)key; - if (len) memcpy(len, mem, sizeof(*len)); - return mem + sizeof(*len); -} - - -/* upb_tabval *****************************************************************/ - -typedef struct { - uint64_t val; -} upb_tabval; - -#define UPB_TABVALUE_EMPTY_INIT {-1} - -/* upb_table ******************************************************************/ - -typedef struct _upb_tabent { - upb_tabkey key; - upb_tabval val; - - /* Internal chaining. This is const so we can create static initializers for - * tables. We cast away const sometimes, but *only* when the containing - * upb_table is known to be non-const. This requires a bit of care, but - * the subtlety is confined to table.c. */ - const struct _upb_tabent *next; -} upb_tabent; - -typedef struct { - size_t count; /* Number of entries in the hash part. */ - size_t mask; /* Mask to turn hash value -> bucket. */ - uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ - - /* Hash table entries. - * Making this const isn't entirely accurate; what we really want is for it to - * have the same const-ness as the table it's inside. But there's no way to - * declare that in C. So we have to make it const so that we can statically - * initialize const hash tables. Then we cast away const when we have to. - */ - const upb_tabent *entries; -} upb_table; - -typedef struct { - upb_table t; -} upb_strtable; - -typedef struct { - upb_table t; /* For entries that don't fit in the array part. */ - const upb_tabval *array; /* Array part of the table. See const note above. */ - size_t array_size; /* Array part size. */ - size_t array_count; /* Array part number of elements. */ -} upb_inttable; - -#define UPB_ARRAY_EMPTYENT -1 - -UPB_INLINE size_t upb_table_size(const upb_table *t) { - if (t->size_lg2 == 0) - return 0; - else - return 1 << t->size_lg2; -} - -/* Internal-only functions, in .h file only out of necessity. */ -UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) { - return e->key == 0; -} - -/* Used by some of the unit tests for generic hashing functionality. */ -uint32_t upb_murmur_hash2(const void * key, size_t len, uint32_t seed); - -UPB_INLINE uintptr_t upb_intkey(uintptr_t key) { - return key; -} - -UPB_INLINE uint32_t upb_inthash(uintptr_t key) { - return (uint32_t)key; -} - -static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) { - return t->entries + (hash & t->mask); -} - -UPB_INLINE bool upb_arrhas(upb_tabval key) { - return key.val != (uint64_t)-1; -} - -/* Initialize and uninitialize a table, respectively. If memory allocation - * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a); -bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, upb_alloc *a); -void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a); -void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a); - -UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) { - return upb_inttable_init2(table, ctype, &upb_alloc_global); -} - -UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) { - return upb_strtable_init2(table, ctype, &upb_alloc_global); -} - -UPB_INLINE void upb_inttable_uninit(upb_inttable *table) { - upb_inttable_uninit2(table, &upb_alloc_global); -} - -UPB_INLINE void upb_strtable_uninit(upb_strtable *table) { - upb_strtable_uninit2(table, &upb_alloc_global); -} - -/* Returns the number of values in the table. */ -size_t upb_inttable_count(const upb_inttable *t); -UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) { - return t->t.count; -} - -void upb_inttable_packedsize(const upb_inttable *t, size_t *size); -void upb_strtable_packedsize(const upb_strtable *t, size_t *size); -upb_inttable *upb_inttable_pack(const upb_inttable *t, void *p, size_t *ofs, - size_t size); -upb_strtable *upb_strtable_pack(const upb_strtable *t, void *p, size_t *ofs, - size_t size); -void upb_strtable_clear(upb_strtable *t); - -/* Inserts the given key into the hashtable with the given value. The key must - * not already exist in the hash table. For string tables, the key must be - * NULL-terminated, and the table will make an internal copy of the key. - * Inttables must not insert a value of UINTPTR_MAX. - * - * If a table resize was required but memory allocation failed, false is - * returned and the table is unchanged. */ -bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, - upb_alloc *a); -bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len, - upb_value val, upb_alloc *a); - -UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key, - upb_value val) { - return upb_inttable_insert2(t, key, val, &upb_alloc_global); -} - -UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key, - size_t len, upb_value val) { - return upb_strtable_insert3(t, key, len, val, &upb_alloc_global); -} - -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key, - upb_value val) { - return upb_strtable_insert2(t, key, strlen(key), val); -} - -/* Looks up key in this table, returning "true" if the key was found. - * If v is non-NULL, copies the value for this key into *v. */ -bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v); -bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, - upb_value *v); - -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key, - upb_value *v) { - return upb_strtable_lookup2(t, key, strlen(key), v); -} - -/* Removes an item from the table. Returns true if the remove was successful, - * and stores the removed item in *val if non-NULL. */ -bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val); -bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, - upb_value *val, upb_alloc *alloc); - -UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key, - size_t len, upb_value *val) { - return upb_strtable_remove3(t, key, len, val, &upb_alloc_global); -} - -/* For NULL-terminated strings. */ -UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key, - upb_value *v) { - return upb_strtable_remove2(t, key, strlen(key), v); -} - -/* Updates an existing entry in an inttable. If the entry does not exist, - * returns false and does nothing. Unlike insert/remove, this does not - * invalidate iterators. */ -bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); - -/* Handy routines for treating an inttable like a stack. May not be mixed with - * other insert/remove calls. */ -bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a); -upb_value upb_inttable_pop(upb_inttable *t); - -UPB_INLINE bool upb_inttable_push(upb_inttable *t, upb_value val) { - return upb_inttable_push2(t, val, &upb_alloc_global); -} - -/* Convenience routines for inttables with pointer keys. */ -bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, - upb_alloc *a); -bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val); -bool upb_inttable_lookupptr( - const upb_inttable *t, const void *key, upb_value *val); - -UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key, - upb_value val) { - return upb_inttable_insertptr2(t, key, val, &upb_alloc_global); -} - -/* Optimizes the table for the current set of entries, for both memory use and - * lookup time. Client should call this after all entries have been inserted; - * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact2(upb_inttable *t, upb_alloc *a); - -UPB_INLINE void upb_inttable_compact(upb_inttable *t) { - upb_inttable_compact2(t, &upb_alloc_global); -} - -/* A special-case inlinable version of the lookup routine for 32-bit - * integers. */ -UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, - upb_value *v) { - *v = upb_value_int32(0); /* Silence compiler warnings. */ - if (key < t->array_size) { - upb_tabval arrval = t->array[key]; - if (upb_arrhas(arrval)) { - _upb_value_setval(v, arrval.val); - return true; - } else { - return false; - } - } else { - const upb_tabent *e; - if (t->t.entries == NULL) return false; - for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) { - if ((uint32_t)e->key == key) { - _upb_value_setval(v, e->val.val); - return true; - } - if (e->next == NULL) return false; - } - } -} - -/* Exposed for testing only. */ -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a); - -/* Iterators ******************************************************************/ - -/* Iterators for int and string tables. We are subject to some kind of unusual - * design constraints: - * - * For high-level languages: - * - we must be able to guarantee that we don't crash or corrupt memory even if - * the program accesses an invalidated iterator. - * - * For C++11 range-based for: - * - iterators must be copyable - * - iterators must be comparable - * - it must be possible to construct an "end" value. - * - * Iteration order is undefined. - * - * Modifying the table invalidates iterators. upb_{str,int}table_done() is - * guaranteed to work even on an invalidated iterator, as long as the table it - * is iterating over has not been freed. Calling next() or accessing data from - * an invalidated iterator yields unspecified elements from the table, but it is - * guaranteed not to crash and to return real table elements (except when done() - * is true). */ - - -/* upb_strtable_iter **********************************************************/ - -/* upb_strtable_iter i; - * upb_strtable_begin(&i, t); - * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { - * const char *key = upb_strtable_iter_key(&i); - * const upb_value val = upb_strtable_iter_value(&i); - * // ... - * } - */ - -typedef struct { - const upb_strtable *t; - size_t index; -} upb_strtable_iter; - -void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t); -void upb_strtable_next(upb_strtable_iter *i); -bool upb_strtable_done(const upb_strtable_iter *i); -upb_strview upb_strtable_iter_key(const upb_strtable_iter *i); -upb_value upb_strtable_iter_value(const upb_strtable_iter *i); -void upb_strtable_iter_setdone(upb_strtable_iter *i); -bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, - const upb_strtable_iter *i2); - - -/* upb_inttable_iter **********************************************************/ - -/* upb_inttable_iter i; - * upb_inttable_begin(&i, t); - * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { - * uintptr_t key = upb_inttable_iter_key(&i); - * upb_value val = upb_inttable_iter_value(&i); - * // ... - * } - */ - -typedef struct { - const upb_inttable *t; - size_t index; - bool array_part; -} upb_inttable_iter; - -UPB_INLINE const upb_tabent *str_tabent(const upb_strtable_iter *i) { - return &i->t->t.entries[i->index]; -} - -void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t); -void upb_inttable_next(upb_inttable_iter *i); -bool upb_inttable_done(const upb_inttable_iter *i); -uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i); -upb_value upb_inttable_iter_value(const upb_inttable_iter *i); -void upb_inttable_iter_setdone(upb_inttable_iter *i); -bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, - const upb_inttable_iter *i2); - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_TABLE_H_ */ - - -#ifdef __cplusplus -extern "C" { -#endif - -#define PTR_AT(msg, ofs, type) (type*)((const char*)msg + ofs) - -typedef void upb_msg; - -/** upb_msglayout *************************************************************/ - -/* upb_msglayout represents the memory layout of a given upb_msgdef. The - * members are public so generated code can initialize them, but users MUST NOT - * read or write any of its members. */ - -/* These aren't real labels according to descriptor.proto, but in the table we - * use these for map/packed fields instead of UPB_LABEL_REPEATED. */ -enum { - _UPB_LABEL_MAP = 4, - _UPB_LABEL_PACKED = 7 /* Low 3 bits are common with UPB_LABEL_REPEATED. */ -}; - -typedef struct { - uint32_t number; - uint16_t offset; - int16_t presence; /* If >0, hasbit_index. If <0, -oneof_index. */ - uint16_t submsg_index; /* undefined if descriptortype != MESSAGE or GROUP. */ - uint8_t descriptortype; - uint8_t label; -} upb_msglayout_field; - -typedef struct upb_msglayout { - const struct upb_msglayout *const* submsgs; - const upb_msglayout_field *fields; - /* Must be aligned to sizeof(void*). Doesn't include internal members like - * unknown fields, extension dict, pointer to msglayout, etc. */ - uint16_t size; - uint16_t field_count; - bool extendable; -} upb_msglayout; - -/** upb_msg *******************************************************************/ - -/* Internal members of a upb_msg. We can change this without breaking binary - * compatibility. We put these before the user's data. The user's upb_msg* - * points after the upb_msg_internal. */ - -/* Used when a message is not extendable. */ -typedef struct { - char *unknown; - size_t unknown_len; - size_t unknown_size; -} upb_msg_internal; - -/* Used when a message is extendable. */ -typedef struct { - upb_inttable *extdict; - upb_msg_internal base; -} upb_msg_internal_withext; - -/* Maps upb_fieldtype_t -> memory size. */ -extern char _upb_fieldtype_to_size[12]; - -/* Creates a new messages with the given layout on the given arena. */ -upb_msg *_upb_msg_new(const upb_msglayout *l, upb_arena *a); - -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -bool _upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, - upb_arena *arena); - -/* Returns a reference to the message's unknown data. */ -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); - -UPB_INLINE bool _upb_has_field(const void *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, const char) & (1 << (idx % 8))) != 0; -} - -UPB_INLINE bool _upb_sethas(const void *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, char)) |= (char)(1 << (idx % 8)); -} - -UPB_INLINE bool _upb_clearhas(const void *msg, size_t idx) { - return (*PTR_AT(msg, idx / 8, char)) &= (char)(~(1 << (idx % 8))); -} - -UPB_INLINE bool _upb_has_oneof_field(const void *msg, size_t case_ofs, int32_t num) { - return *PTR_AT(msg, case_ofs, int32_t) == num; -} - -UPB_INLINE bool _upb_has_submsg_nohasbit(const void *msg, size_t ofs) { - return *PTR_AT(msg, ofs, const void*) != NULL; -} - -UPB_INLINE bool _upb_isrepeated(const upb_msglayout_field *field) { - return (field->label & 3) == UPB_LABEL_REPEATED; -} - -/** upb_array *****************************************************************/ - -/* Our internal representation for repeated fields. */ -typedef struct { - uintptr_t data; /* Tagged ptr: low 3 bits of ptr are lg2(elem size). */ - size_t len; /* Measured in elements. */ - size_t size; /* Measured in elements. */ -} upb_array; - -UPB_INLINE const void *_upb_array_constptr(const upb_array *arr) { - return (void*)(arr->data & ~(uintptr_t)7); -} - -UPB_INLINE void *_upb_array_ptr(upb_array *arr) { - return (void*)_upb_array_constptr(arr); -} - -/* Creates a new array on the given arena. */ -upb_array *_upb_array_new(upb_arena *a, upb_fieldtype_t type); - -/* Resizes the capacity of the array to be at least min_size. */ -bool _upb_array_realloc(upb_array *arr, size_t min_size, upb_arena *arena); - -/* Fallback functions for when the accessors require a resize. */ -void *_upb_array_resize_fallback(upb_array **arr_ptr, size_t size, - upb_fieldtype_t type, upb_arena *arena); -bool _upb_array_append_fallback(upb_array **arr_ptr, const void *value, - upb_fieldtype_t type, upb_arena *arena); - -UPB_INLINE const void *_upb_array_accessor(const void *msg, size_t ofs, - size_t *size) { - const upb_array *arr = *PTR_AT(msg, ofs, const upb_array*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_constptr(arr); - } else { - if (size) *size = 0; - return NULL; - } -} - -UPB_INLINE void *_upb_array_mutable_accessor(void *msg, size_t ofs, - size_t *size) { - upb_array *arr = *PTR_AT(msg, ofs, upb_array*); - if (arr) { - if (size) *size = arr->len; - return _upb_array_ptr(arr); - } else { - if (size) *size = 0; - return NULL; - } -} - -UPB_INLINE void *_upb_array_resize_accessor(void *msg, size_t ofs, size_t size, - upb_fieldtype_t type, - upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); - upb_array *arr = *arr_ptr; - if (!arr || arr->size < size) { - return _upb_array_resize_fallback(arr_ptr, size, type, arena); - } - arr->len = size; - return _upb_array_ptr(arr); -} - - -UPB_INLINE bool _upb_array_append_accessor(void *msg, size_t ofs, - size_t elem_size, - upb_fieldtype_t type, - const void *value, - upb_arena *arena) { - upb_array **arr_ptr = PTR_AT(msg, ofs, upb_array*); - upb_array *arr = *arr_ptr; - void* ptr; - if (!arr || arr->len == arr->size) { - return _upb_array_append_fallback(arr_ptr, value, type, arena); - } - ptr = _upb_array_ptr(arr); - memcpy(PTR_AT(ptr, arr->len * elem_size, char), value, elem_size); - arr->len++; - return true; -} - -/** upb_map *******************************************************************/ - -/* Right now we use strmaps for everything. We'll likely want to use - * integer-specific maps for integer-keyed maps.*/ -typedef struct { - /* Size of key and val, based on the map type. Strings are represented as '0' - * because they must be handled specially. */ - char key_size; - char val_size; - - upb_strtable table; -} upb_map; - -/* Map entries aren't actually stored, they are only used during parsing. For - * parsing, it helps a lot if all map entry messages have the same layout. - * The compiler and def.c must ensure that all map entries have this layout. */ -typedef struct { - upb_msg_internal internal; - union { - upb_strview str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } k; - union { - upb_strview str; /* For str/bytes. */ - upb_value val; /* For all other types. */ - } v; -} upb_map_entry; - -/* Creates a new map on the given arena with this key/value type. */ -upb_map *_upb_map_new(upb_arena *a, size_t key_size, size_t value_size); - -/* Converting between internal table representation and user values. - * - * _upb_map_tokey() and _upb_map_fromkey() are inverses. - * _upb_map_tovalue() and _upb_map_fromvalue() are inverses. - * - * These functions account for the fact that strings are treated differently - * from other types when stored in a map. - */ - -UPB_INLINE upb_strview _upb_map_tokey(const void *key, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - return *(upb_strview*)key; - } else { - return upb_strview_make((const char*)key, size); - } -} - -UPB_INLINE void _upb_map_fromkey(upb_strview key, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - memcpy(out, &key, sizeof(key)); - } else { - memcpy(out, key.data, size); - } -} - -UPB_INLINE upb_value _upb_map_tovalue(const void *val, size_t size, - upb_arena *a) { - upb_value ret = {0}; - if (size == UPB_MAPTYPE_STRING) { - upb_strview *strp = (upb_strview*)upb_arena_malloc(a, sizeof(*strp)); - *strp = *(upb_strview*)val; - memcpy(&ret, &strp, sizeof(strp)); - } else { - memcpy(&ret, val, size); - } - return ret; -} - -UPB_INLINE void _upb_map_fromvalue(upb_value val, void* out, size_t size) { - if (size == UPB_MAPTYPE_STRING) { - const upb_strview *strp = (const upb_strview*)upb_value_getptr(val); - memcpy(out, strp, sizeof(upb_strview)); - } else { - memcpy(out, &val, size); - } -} - -/* Map operations, shared by reflection and generated code. */ - -UPB_INLINE size_t _upb_map_size(const upb_map *map) { - return map->table.t.count; -} - -UPB_INLINE bool _upb_map_get(const upb_map *map, const void *key, - size_t key_size, void *val, size_t val_size) { - upb_value tabval; - upb_strview k = _upb_map_tokey(key, key_size); - bool ret = upb_strtable_lookup2(&map->table, k.data, k.size, &tabval); - if (ret) { - _upb_map_fromvalue(tabval, val, val_size); - } - return ret; -} - -UPB_INLINE void* _upb_map_next(const upb_map *map, size_t *iter) { - upb_strtable_iter it; - it.t = &map->table; - it.index = *iter; - upb_strtable_next(&it); - if (upb_strtable_done(&it)) return NULL; - *iter = it.index; - return (void*)str_tabent(&it); -} - -UPB_INLINE bool _upb_map_set(upb_map *map, const void *key, size_t key_size, - void *val, size_t val_size, upb_arena *arena) { - upb_strview strkey = _upb_map_tokey(key, key_size); - upb_value tabval = _upb_map_tovalue(val, val_size, arena); - upb_alloc *a = upb_arena_alloc(arena); - - /* TODO(haberman): add overwrite operation to minimize number of lookups. */ - upb_strtable_remove3(&map->table, strkey.data, strkey.size, NULL, a); - return upb_strtable_insert3(&map->table, strkey.data, strkey.size, tabval, a); -} - -UPB_INLINE bool _upb_map_delete(upb_map *map, const void *key, size_t key_size) { - upb_strview k = _upb_map_tokey(key, key_size); - return upb_strtable_remove3(&map->table, k.data, k.size, NULL, NULL); -} - -UPB_INLINE void _upb_map_clear(upb_map *map) { - upb_strtable_clear(&map->table); -} - -/* Message map operations, these get the map from the message first. */ - -UPB_INLINE size_t _upb_msg_map_size(const upb_msg *msg, size_t ofs) { - upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *); - return map ? _upb_map_size(map) : 0; -} - -UPB_INLINE bool _upb_msg_map_get(const upb_msg *msg, size_t ofs, - const void *key, size_t key_size, void *val, - size_t val_size) { - upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *); - if (!map) return false; - return _upb_map_get(map, key, key_size, val, val_size); -} - -UPB_INLINE void *_upb_msg_map_next(const upb_msg *msg, size_t ofs, - size_t *iter) { - upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *); - if (!map) return NULL; - return _upb_map_next(map, iter); -} - -UPB_INLINE bool _upb_msg_map_set(upb_msg *msg, size_t ofs, const void *key, - size_t key_size, void *val, size_t val_size, - upb_arena *arena) { - upb_map **map = PTR_AT(msg, ofs, upb_map *); - if (!*map) { - *map = _upb_map_new(arena, key_size, val_size); - } - return _upb_map_set(*map, key, key_size, val, val_size, arena); -} - -UPB_INLINE bool _upb_msg_map_delete(upb_msg *msg, size_t ofs, const void *key, - size_t key_size) { - upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *); - if (!map) return false; - return _upb_map_delete(map, key, key_size); -} - -UPB_INLINE void _upb_msg_map_clear(upb_msg *msg, size_t ofs) { - upb_map *map = *UPB_PTR_AT(msg, ofs, upb_map *); - if (!map) return; - _upb_map_clear(map); -} - -/* Accessing map key/value from a pointer, used by generated code only. */ - -UPB_INLINE void _upb_msg_map_key(const void* msg, void* key, size_t size) { - const upb_tabent *ent = (const upb_tabent*)msg; - uint32_t u32len; - upb_strview k; - k.data = upb_tabstr(ent->key, &u32len); - k.size = u32len; - _upb_map_fromkey(k, key, size); -} - -UPB_INLINE void _upb_msg_map_value(const void* msg, void* val, size_t size) { - const upb_tabent *ent = (const upb_tabent*)msg; - upb_value v; - _upb_value_setval(&v, ent->val.val); - _upb_map_fromvalue(v, val, size); -} - -UPB_INLINE void _upb_msg_map_set_value(void* msg, const void* val, size_t size) { - upb_tabent *ent = (upb_tabent*)msg; - /* This is like _upb_map_tovalue() except the entry already exists so we can - * reuse the allocated upb_strview for string fields. */ - if (size == UPB_MAPTYPE_STRING) { - upb_strview *strp = (upb_strview*)ent->val.val; - memcpy(strp, val, sizeof(*strp)); - } else { - memcpy(&ent->val.val, val, size); - } -} - -#undef PTR_AT - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_MSG_H_ */ - -#ifdef __cplusplus -extern "C" { -#endif - -bool upb_decode(const char *buf, size_t size, upb_msg *msg, - const upb_msglayout *l, upb_arena *arena); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_DECODE_H_ */ -/* -** upb_encode: parsing into a upb_msg using a upb_msglayout. -*/ - -#ifndef UPB_ENCODE_H_ -#define UPB_ENCODE_H_ - - -#ifdef __cplusplus -extern "C" { -#endif - -char *upb_encode(const void *msg, const upb_msglayout *l, upb_arena *arena, - size_t *size); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_ENCODE_H_ */ -/* This file was generated by upbc (the upb compiler) from the input - * file: - * - * google/protobuf/descriptor.proto - * - * Do not edit -- your changes will be discarded when the file is - * regenerated. */ - -#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ -#define GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ - - - -#ifdef __cplusplus -extern "C" { -#endif - -struct google_protobuf_FileDescriptorSet; -struct google_protobuf_FileDescriptorProto; -struct google_protobuf_DescriptorProto; -struct google_protobuf_DescriptorProto_ExtensionRange; -struct google_protobuf_DescriptorProto_ReservedRange; -struct google_protobuf_ExtensionRangeOptions; -struct google_protobuf_FieldDescriptorProto; -struct google_protobuf_OneofDescriptorProto; -struct google_protobuf_EnumDescriptorProto; -struct google_protobuf_EnumDescriptorProto_EnumReservedRange; -struct google_protobuf_EnumValueDescriptorProto; -struct google_protobuf_ServiceDescriptorProto; -struct google_protobuf_MethodDescriptorProto; -struct google_protobuf_FileOptions; -struct google_protobuf_MessageOptions; -struct google_protobuf_FieldOptions; -struct google_protobuf_OneofOptions; -struct google_protobuf_EnumOptions; -struct google_protobuf_EnumValueOptions; -struct google_protobuf_ServiceOptions; -struct google_protobuf_MethodOptions; -struct google_protobuf_UninterpretedOption; -struct google_protobuf_UninterpretedOption_NamePart; -struct google_protobuf_SourceCodeInfo; -struct google_protobuf_SourceCodeInfo_Location; -struct google_protobuf_GeneratedCodeInfo; -struct google_protobuf_GeneratedCodeInfo_Annotation; -typedef struct google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet; -typedef struct google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto; -typedef struct google_protobuf_DescriptorProto google_protobuf_DescriptorProto; -typedef struct google_protobuf_DescriptorProto_ExtensionRange google_protobuf_DescriptorProto_ExtensionRange; -typedef struct google_protobuf_DescriptorProto_ReservedRange google_protobuf_DescriptorProto_ReservedRange; -typedef struct google_protobuf_ExtensionRangeOptions google_protobuf_ExtensionRangeOptions; -typedef struct google_protobuf_FieldDescriptorProto google_protobuf_FieldDescriptorProto; -typedef struct google_protobuf_OneofDescriptorProto google_protobuf_OneofDescriptorProto; -typedef struct google_protobuf_EnumDescriptorProto google_protobuf_EnumDescriptorProto; -typedef struct google_protobuf_EnumDescriptorProto_EnumReservedRange google_protobuf_EnumDescriptorProto_EnumReservedRange; -typedef struct google_protobuf_EnumValueDescriptorProto google_protobuf_EnumValueDescriptorProto; -typedef struct google_protobuf_ServiceDescriptorProto google_protobuf_ServiceDescriptorProto; -typedef struct google_protobuf_MethodDescriptorProto google_protobuf_MethodDescriptorProto; -typedef struct google_protobuf_FileOptions google_protobuf_FileOptions; -typedef struct google_protobuf_MessageOptions google_protobuf_MessageOptions; -typedef struct google_protobuf_FieldOptions google_protobuf_FieldOptions; -typedef struct google_protobuf_OneofOptions google_protobuf_OneofOptions; -typedef struct google_protobuf_EnumOptions google_protobuf_EnumOptions; -typedef struct google_protobuf_EnumValueOptions google_protobuf_EnumValueOptions; -typedef struct google_protobuf_ServiceOptions google_protobuf_ServiceOptions; -typedef struct google_protobuf_MethodOptions google_protobuf_MethodOptions; -typedef struct google_protobuf_UninterpretedOption google_protobuf_UninterpretedOption; -typedef struct google_protobuf_UninterpretedOption_NamePart google_protobuf_UninterpretedOption_NamePart; -typedef struct google_protobuf_SourceCodeInfo google_protobuf_SourceCodeInfo; -typedef struct google_protobuf_SourceCodeInfo_Location google_protobuf_SourceCodeInfo_Location; -typedef struct google_protobuf_GeneratedCodeInfo google_protobuf_GeneratedCodeInfo; -typedef struct google_protobuf_GeneratedCodeInfo_Annotation google_protobuf_GeneratedCodeInfo_Annotation; -extern const upb_msglayout google_protobuf_FileDescriptorSet_msginit; -extern const upb_msglayout google_protobuf_FileDescriptorProto_msginit; -extern const upb_msglayout google_protobuf_DescriptorProto_msginit; -extern const upb_msglayout google_protobuf_DescriptorProto_ExtensionRange_msginit; -extern const upb_msglayout google_protobuf_DescriptorProto_ReservedRange_msginit; -extern const upb_msglayout google_protobuf_ExtensionRangeOptions_msginit; -extern const upb_msglayout google_protobuf_FieldDescriptorProto_msginit; -extern const upb_msglayout google_protobuf_OneofDescriptorProto_msginit; -extern const upb_msglayout google_protobuf_EnumDescriptorProto_msginit; -extern const upb_msglayout google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit; -extern const upb_msglayout google_protobuf_EnumValueDescriptorProto_msginit; -extern const upb_msglayout google_protobuf_ServiceDescriptorProto_msginit; -extern const upb_msglayout google_protobuf_MethodDescriptorProto_msginit; -extern const upb_msglayout google_protobuf_FileOptions_msginit; -extern const upb_msglayout google_protobuf_MessageOptions_msginit; -extern const upb_msglayout google_protobuf_FieldOptions_msginit; -extern const upb_msglayout google_protobuf_OneofOptions_msginit; -extern const upb_msglayout google_protobuf_EnumOptions_msginit; -extern const upb_msglayout google_protobuf_EnumValueOptions_msginit; -extern const upb_msglayout google_protobuf_ServiceOptions_msginit; -extern const upb_msglayout google_protobuf_MethodOptions_msginit; -extern const upb_msglayout google_protobuf_UninterpretedOption_msginit; -extern const upb_msglayout google_protobuf_UninterpretedOption_NamePart_msginit; -extern const upb_msglayout google_protobuf_SourceCodeInfo_msginit; -extern const upb_msglayout google_protobuf_SourceCodeInfo_Location_msginit; -extern const upb_msglayout google_protobuf_GeneratedCodeInfo_msginit; -extern const upb_msglayout google_protobuf_GeneratedCodeInfo_Annotation_msginit; - -typedef enum { - google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, - google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, - google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 -} google_protobuf_FieldDescriptorProto_Label; - -typedef enum { - google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, - google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, - google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, - google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, - google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, - google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, - google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, - google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, - google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, - google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, - google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, - google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, - google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, - google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, - google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, - google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, - google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, - google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 -} google_protobuf_FieldDescriptorProto_Type; - -typedef enum { - google_protobuf_FieldOptions_STRING = 0, - google_protobuf_FieldOptions_CORD = 1, - google_protobuf_FieldOptions_STRING_PIECE = 2 -} google_protobuf_FieldOptions_CType; - -typedef enum { - google_protobuf_FieldOptions_JS_NORMAL = 0, - google_protobuf_FieldOptions_JS_STRING = 1, - google_protobuf_FieldOptions_JS_NUMBER = 2 -} google_protobuf_FieldOptions_JSType; - -typedef enum { - google_protobuf_FileOptions_SPEED = 1, - google_protobuf_FileOptions_CODE_SIZE = 2, - google_protobuf_FileOptions_LITE_RUNTIME = 3 -} google_protobuf_FileOptions_OptimizeMode; - -typedef enum { - google_protobuf_MethodOptions_IDEMPOTENCY_UNKNOWN = 0, - google_protobuf_MethodOptions_NO_SIDE_EFFECTS = 1, - google_protobuf_MethodOptions_IDEMPOTENT = 2 -} google_protobuf_MethodOptions_IdempotencyLevel; - - -/* google.protobuf.FileDescriptorSet */ - -UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_new(upb_arena *arena) { - return (google_protobuf_FileDescriptorSet *)_upb_msg_new(&google_protobuf_FileDescriptorSet_msginit, arena); -} -UPB_INLINE google_protobuf_FileDescriptorSet *google_protobuf_FileDescriptorSet_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_FileDescriptorSet *ret = google_protobuf_FileDescriptorSet_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_FileDescriptorSet_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_FileDescriptorSet_serialize(const google_protobuf_FileDescriptorSet *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_FileDescriptorSet_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_FileDescriptorSet_has_file(const google_protobuf_FileDescriptorSet *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_FileDescriptorProto* const* google_protobuf_FileDescriptorSet_file(const google_protobuf_FileDescriptorSet *msg, size_t *len) { return (const google_protobuf_FileDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } - -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_mutable_file(google_protobuf_FileDescriptorSet *msg, size_t *len) { - return (google_protobuf_FileDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_FileDescriptorProto** google_protobuf_FileDescriptorSet_resize_file(google_protobuf_FileDescriptorSet *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FileDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_FileDescriptorProto* google_protobuf_FileDescriptorSet_add_file(google_protobuf_FileDescriptorSet *msg, upb_arena *arena) { - struct google_protobuf_FileDescriptorProto* sub = (struct google_protobuf_FileDescriptorProto*)_upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.FileDescriptorProto */ - -UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_FileDescriptorProto *)_upb_msg_new(&google_protobuf_FileDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_FileDescriptorProto *ret = google_protobuf_FileDescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_FileDescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_FileDescriptorProto_serialize(const google_protobuf_FileDescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_FileDescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_name(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_name(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_package(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_package(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); } -UPB_INLINE upb_strview const* google_protobuf_FileDescriptorProto_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_message_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_FileDescriptorProto_message_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_enum_type(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(44, 88)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_FileDescriptorProto_enum_type(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_service(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(48, 96)); } -UPB_INLINE const google_protobuf_ServiceDescriptorProto* const* google_protobuf_FileDescriptorProto_service(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_ServiceDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(48, 96), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_extension(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(52, 104)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_FileDescriptorProto_extension(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(52, 104), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_options(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 4); } -UPB_INLINE const google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_options(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_FileOptions*); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 5); } -UPB_INLINE const google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_source_code_info(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 64), const google_protobuf_SourceCodeInfo*); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_public_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(56, 112), len); } -UPB_INLINE int32_t const* google_protobuf_FileDescriptorProto_weak_dependency(const google_protobuf_FileDescriptorProto *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(60, 120), len); } -UPB_INLINE bool google_protobuf_FileDescriptorProto_has_syntax(const google_protobuf_FileDescriptorProto *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE upb_strview google_protobuf_FileDescriptorProto_syntax(const google_protobuf_FileDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); } - -UPB_INLINE void google_protobuf_FileDescriptorProto_set_name(google_protobuf_FileDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_package(google_protobuf_FileDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value; -} -UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_mutable_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); -} -UPB_INLINE upb_strview* google_protobuf_FileDescriptorProto_resize_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_TYPE_STRING, arena); -} -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_dependency(google_protobuf_FileDescriptorProto *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(36, 72), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, - arena); -} -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_mutable_message_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); -} -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_FileDescriptorProto_resize_message_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_FileDescriptorProto_add_message_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(40, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_mutable_enum_type(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); -} -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_FileDescriptorProto_resize_enum_type(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_FileDescriptorProto_add_enum_type(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(44, 88), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_mutable_service(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_ServiceDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(48, 96), len); -} -UPB_INLINE google_protobuf_ServiceDescriptorProto** google_protobuf_FileDescriptorProto_resize_service(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_ServiceDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(48, 96), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_ServiceDescriptorProto* google_protobuf_FileDescriptorProto_add_service(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_ServiceDescriptorProto* sub = (struct google_protobuf_ServiceDescriptorProto*)_upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(48, 96), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_mutable_extension(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(52, 104), len); -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_FileDescriptorProto_resize_extension(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(52, 104), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_FileDescriptorProto_add_extension(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(52, 104), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_options(google_protobuf_FileDescriptorProto *msg, google_protobuf_FileOptions* value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_FileOptions*) = value; -} -UPB_INLINE struct google_protobuf_FileOptions* google_protobuf_FileDescriptorProto_mutable_options(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FileOptions* sub = (struct google_protobuf_FileOptions*)google_protobuf_FileDescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_FileOptions*)_upb_msg_new(&google_protobuf_FileOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_FileDescriptorProto_set_options(msg, sub); - } - return sub; -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_source_code_info(google_protobuf_FileDescriptorProto *msg, google_protobuf_SourceCodeInfo* value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(32, 64), google_protobuf_SourceCodeInfo*) = value; -} -UPB_INLINE struct google_protobuf_SourceCodeInfo* google_protobuf_FileDescriptorProto_mutable_source_code_info(google_protobuf_FileDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_SourceCodeInfo* sub = (struct google_protobuf_SourceCodeInfo*)google_protobuf_FileDescriptorProto_source_code_info(msg); - if (sub == NULL) { - sub = (struct google_protobuf_SourceCodeInfo*)_upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); - if (!sub) return NULL; - google_protobuf_FileDescriptorProto_set_source_code_info(msg, sub); - } - return sub; -} -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 112), len); -} -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_public_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(56, 112), len, UPB_TYPE_INT32, arena); -} -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_public_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(56, 112), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, - arena); -} -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_mutable_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(60, 120), len); -} -UPB_INLINE int32_t* google_protobuf_FileDescriptorProto_resize_weak_dependency(google_protobuf_FileDescriptorProto *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(60, 120), len, UPB_TYPE_INT32, arena); -} -UPB_INLINE bool google_protobuf_FileDescriptorProto_add_weak_dependency(google_protobuf_FileDescriptorProto *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(60, 120), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, - arena); -} -UPB_INLINE void google_protobuf_FileDescriptorProto_set_syntax(google_protobuf_FileDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value; -} - -/* google.protobuf.DescriptorProto */ - -UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_new(upb_arena *arena) { - return (google_protobuf_DescriptorProto *)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_DescriptorProto *ret = google_protobuf_DescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_DescriptorProto_serialize(const google_protobuf_DescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_DescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_DescriptorProto_has_name(const google_protobuf_DescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE upb_strview google_protobuf_DescriptorProto_name(const google_protobuf_DescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_field(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_field(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_nested_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_DescriptorProto* const* google_protobuf_DescriptorProto_nested_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_enum_type(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(24, 48)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto* const* google_protobuf_DescriptorProto_enum_type(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 56)); } -UPB_INLINE const google_protobuf_DescriptorProto_ExtensionRange* const* google_protobuf_DescriptorProto_extension_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ExtensionRange* const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_extension(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(32, 64)); } -UPB_INLINE const google_protobuf_FieldDescriptorProto* const* google_protobuf_DescriptorProto_extension(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_FieldDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(32, 64), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_options(const google_protobuf_DescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE const google_protobuf_MessageOptions* google_protobuf_DescriptorProto_options(const google_protobuf_DescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_MessageOptions*); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_oneof_decl(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(36, 72)); } -UPB_INLINE const google_protobuf_OneofDescriptorProto* const* google_protobuf_DescriptorProto_oneof_decl(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_OneofDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(36, 72), len); } -UPB_INLINE bool google_protobuf_DescriptorProto_has_reserved_range(const google_protobuf_DescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(40, 80)); } -UPB_INLINE const google_protobuf_DescriptorProto_ReservedRange* const* google_protobuf_DescriptorProto_reserved_range(const google_protobuf_DescriptorProto *msg, size_t *len) { return (const google_protobuf_DescriptorProto_ReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(40, 80), len); } -UPB_INLINE upb_strview const* google_protobuf_DescriptorProto_reserved_name(const google_protobuf_DescriptorProto *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(44, 88), len); } - -UPB_INLINE void google_protobuf_DescriptorProto_set_name(google_protobuf_DescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_field(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_field(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_field(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_mutable_nested_type(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); -} -UPB_INLINE google_protobuf_DescriptorProto** google_protobuf_DescriptorProto_resize_nested_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_DescriptorProto* google_protobuf_DescriptorProto_add_nested_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto* sub = (struct google_protobuf_DescriptorProto*)_upb_msg_new(&google_protobuf_DescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(20, 40), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_mutable_enum_type(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); -} -UPB_INLINE google_protobuf_EnumDescriptorProto** google_protobuf_DescriptorProto_resize_enum_type(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_EnumDescriptorProto* google_protobuf_DescriptorProto_add_enum_type(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumDescriptorProto* sub = (struct google_protobuf_EnumDescriptorProto*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(24, 48), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_mutable_extension_range(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); -} -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange** google_protobuf_DescriptorProto_resize_extension_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto_ExtensionRange**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_DescriptorProto_ExtensionRange* google_protobuf_DescriptorProto_add_extension_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto_ExtensionRange* sub = (struct google_protobuf_DescriptorProto_ExtensionRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(28, 56), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_mutable_extension(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(32, 64), len); -} -UPB_INLINE google_protobuf_FieldDescriptorProto** google_protobuf_DescriptorProto_resize_extension(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(32, 64), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_FieldDescriptorProto* google_protobuf_DescriptorProto_add_extension(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FieldDescriptorProto* sub = (struct google_protobuf_FieldDescriptorProto*)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(32, 64), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE void google_protobuf_DescriptorProto_set_options(google_protobuf_DescriptorProto *msg, google_protobuf_MessageOptions* value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_MessageOptions*) = value; -} -UPB_INLINE struct google_protobuf_MessageOptions* google_protobuf_DescriptorProto_mutable_options(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_MessageOptions* sub = (struct google_protobuf_MessageOptions*)google_protobuf_DescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_MessageOptions*)_upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_DescriptorProto_set_options(msg, sub); - } - return sub; -} -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_mutable_oneof_decl(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_OneofDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(36, 72), len); -} -UPB_INLINE google_protobuf_OneofDescriptorProto** google_protobuf_DescriptorProto_resize_oneof_decl(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_OneofDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(36, 72), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_OneofDescriptorProto* google_protobuf_DescriptorProto_add_oneof_decl(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_OneofDescriptorProto* sub = (struct google_protobuf_OneofDescriptorProto*)_upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(36, 72), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_mutable_reserved_range(google_protobuf_DescriptorProto *msg, size_t *len) { - return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(40, 80), len); -} -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange** google_protobuf_DescriptorProto_resize_reserved_range(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_DescriptorProto_ReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(40, 80), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_DescriptorProto_ReservedRange* google_protobuf_DescriptorProto_add_reserved_range(google_protobuf_DescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_DescriptorProto_ReservedRange* sub = (struct google_protobuf_DescriptorProto_ReservedRange*)_upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(40, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE upb_strview* google_protobuf_DescriptorProto_mutable_reserved_name(google_protobuf_DescriptorProto *msg, size_t *len) { - return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(44, 88), len); -} -UPB_INLINE upb_strview* google_protobuf_DescriptorProto_resize_reserved_name(google_protobuf_DescriptorProto *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(44, 88), len, UPB_TYPE_STRING, arena); -} -UPB_INLINE bool google_protobuf_DescriptorProto_add_reserved_name(google_protobuf_DescriptorProto *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(44, 88), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, - arena); -} - -/* google.protobuf.DescriptorProto.ExtensionRange */ - -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_new(upb_arena *arena) { - return (google_protobuf_DescriptorProto_ExtensionRange *)_upb_msg_new(&google_protobuf_DescriptorProto_ExtensionRange_msginit, arena); -} -UPB_INLINE google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_DescriptorProto_ExtensionRange *ret = google_protobuf_DescriptorProto_ExtensionRange_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_DescriptorProto_ExtensionRange_serialize(const google_protobuf_DescriptorProto_ExtensionRange *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_DescriptorProto_ExtensionRange_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_start(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE int32_t google_protobuf_DescriptorProto_ExtensionRange_end(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ExtensionRange_has_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE const google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_options(const google_protobuf_DescriptorProto_ExtensionRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), const google_protobuf_ExtensionRangeOptions*); } - -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_start(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_end(google_protobuf_DescriptorProto_ExtensionRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ExtensionRange_set_options(google_protobuf_DescriptorProto_ExtensionRange *msg, google_protobuf_ExtensionRangeOptions* value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(12, 16), google_protobuf_ExtensionRangeOptions*) = value; -} -UPB_INLINE struct google_protobuf_ExtensionRangeOptions* google_protobuf_DescriptorProto_ExtensionRange_mutable_options(google_protobuf_DescriptorProto_ExtensionRange *msg, upb_arena *arena) { - struct google_protobuf_ExtensionRangeOptions* sub = (struct google_protobuf_ExtensionRangeOptions*)google_protobuf_DescriptorProto_ExtensionRange_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_ExtensionRangeOptions*)_upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_DescriptorProto_ExtensionRange_set_options(msg, sub); - } - return sub; -} - -/* google.protobuf.DescriptorProto.ReservedRange */ - -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_new(upb_arena *arena) { - return (google_protobuf_DescriptorProto_ReservedRange *)_upb_msg_new(&google_protobuf_DescriptorProto_ReservedRange_msginit, arena); -} -UPB_INLINE google_protobuf_DescriptorProto_ReservedRange *google_protobuf_DescriptorProto_ReservedRange_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_DescriptorProto_ReservedRange *ret = google_protobuf_DescriptorProto_ReservedRange_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_DescriptorProto_ReservedRange_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_DescriptorProto_ReservedRange_serialize(const google_protobuf_DescriptorProto_ReservedRange *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_DescriptorProto_ReservedRange_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_start(const google_protobuf_DescriptorProto_ReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_DescriptorProto_ReservedRange_has_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE int32_t google_protobuf_DescriptorProto_ReservedRange_end(const google_protobuf_DescriptorProto_ReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } - -UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_start(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_DescriptorProto_ReservedRange_set_end(google_protobuf_DescriptorProto_ReservedRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} - -/* google.protobuf.ExtensionRangeOptions */ - -UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_new(upb_arena *arena) { - return (google_protobuf_ExtensionRangeOptions *)_upb_msg_new(&google_protobuf_ExtensionRangeOptions_msginit, arena); -} -UPB_INLINE google_protobuf_ExtensionRangeOptions *google_protobuf_ExtensionRangeOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_ExtensionRangeOptions *ret = google_protobuf_ExtensionRangeOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_ExtensionRangeOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_ExtensionRangeOptions_serialize(const google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_ExtensionRangeOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_ExtensionRangeOptions_has_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ExtensionRangeOptions_uninterpreted_option(const google_protobuf_ExtensionRangeOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } - -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_mutable_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ExtensionRangeOptions_resize_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ExtensionRangeOptions_add_uninterpreted_option(google_protobuf_ExtensionRangeOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.FieldDescriptorProto */ - -UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_FieldDescriptorProto *)_upb_msg_new(&google_protobuf_FieldDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_FieldDescriptorProto *ret = google_protobuf_FieldDescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_FieldDescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_FieldDescriptorProto_serialize(const google_protobuf_FieldDescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_FieldDescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 6); } -UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_strview); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_extendee(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 7); } -UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_extendee(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 56), upb_strview); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_number(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_number(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_label(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_label(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_type(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_type_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 8); } -UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_type_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 72), upb_strview); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_default_value(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 9); } -UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_default_value(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 88), upb_strview); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_options(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 11); } -UPB_INLINE const google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_options(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 120), const google_protobuf_FieldOptions*); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 4); } -UPB_INLINE int32_t google_protobuf_FieldDescriptorProto_oneof_index(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 28), int32_t); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_json_name(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 10); } -UPB_INLINE upb_strview google_protobuf_FieldDescriptorProto_json_name(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 104), upb_strview); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_has_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return _upb_has_field(msg, 5); } -UPB_INLINE bool google_protobuf_FieldDescriptorProto_proto3_optional(const google_protobuf_FieldDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), bool); } - -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(36, 40), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_extendee(google_protobuf_FieldDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(44, 56), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_number(google_protobuf_FieldDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_label(google_protobuf_FieldDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type(google_protobuf_FieldDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_type_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(52, 72), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_default_value(google_protobuf_FieldDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 9); - *UPB_PTR_AT(msg, UPB_SIZE(60, 88), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_options(google_protobuf_FieldDescriptorProto *msg, google_protobuf_FieldOptions* value) { - _upb_sethas(msg, 11); - *UPB_PTR_AT(msg, UPB_SIZE(76, 120), google_protobuf_FieldOptions*) = value; -} -UPB_INLINE struct google_protobuf_FieldOptions* google_protobuf_FieldDescriptorProto_mutable_options(google_protobuf_FieldDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_FieldOptions* sub = (struct google_protobuf_FieldOptions*)google_protobuf_FieldDescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_FieldOptions*)_upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_FieldDescriptorProto_set_options(msg, sub); - } - return sub; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_oneof_index(google_protobuf_FieldDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(28, 28), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_json_name(google_protobuf_FieldDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(68, 104), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FieldDescriptorProto_set_proto3_optional(google_protobuf_FieldDescriptorProto *msg, bool value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(32, 32), bool) = value; -} - -/* google.protobuf.OneofDescriptorProto */ - -UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_OneofDescriptorProto *)_upb_msg_new(&google_protobuf_OneofDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_OneofDescriptorProto *google_protobuf_OneofDescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_OneofDescriptorProto *ret = google_protobuf_OneofDescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_OneofDescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_OneofDescriptorProto_serialize(const google_protobuf_OneofDescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_OneofDescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_name(const google_protobuf_OneofDescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE upb_strview google_protobuf_OneofDescriptorProto_name(const google_protobuf_OneofDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_OneofDescriptorProto_has_options(const google_protobuf_OneofDescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE const google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_options(const google_protobuf_OneofDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_OneofOptions*); } - -UPB_INLINE void google_protobuf_OneofDescriptorProto_set_name(google_protobuf_OneofDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE void google_protobuf_OneofDescriptorProto_set_options(google_protobuf_OneofDescriptorProto *msg, google_protobuf_OneofOptions* value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_OneofOptions*) = value; -} -UPB_INLINE struct google_protobuf_OneofOptions* google_protobuf_OneofDescriptorProto_mutable_options(google_protobuf_OneofDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_OneofOptions* sub = (struct google_protobuf_OneofOptions*)google_protobuf_OneofDescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_OneofOptions*)_upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_OneofDescriptorProto_set_options(msg, sub); - } - return sub; -} - -/* google.protobuf.EnumDescriptorProto */ - -UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto *)_upb_msg_new(&google_protobuf_EnumDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_EnumDescriptorProto *ret = google_protobuf_EnumDescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_EnumDescriptorProto_serialize(const google_protobuf_EnumDescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_EnumDescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_name(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE upb_strview google_protobuf_EnumDescriptorProto_name(const google_protobuf_EnumDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_value(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_EnumValueDescriptorProto* const* google_protobuf_EnumDescriptorProto_value(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumValueDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_options(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE const google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_options(const google_protobuf_EnumDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_EnumOptions*); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_has_reserved_range(const google_protobuf_EnumDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 40)); } -UPB_INLINE const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* google_protobuf_EnumDescriptorProto_reserved_range(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (const google_protobuf_EnumDescriptorProto_EnumReservedRange* const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE upb_strview const* google_protobuf_EnumDescriptorProto_reserved_name(const google_protobuf_EnumDescriptorProto *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } - -UPB_INLINE void google_protobuf_EnumDescriptorProto_set_name(google_protobuf_EnumDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_mutable_value(google_protobuf_EnumDescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); -} -UPB_INLINE google_protobuf_EnumValueDescriptorProto** google_protobuf_EnumDescriptorProto_resize_value(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumValueDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_EnumValueDescriptorProto* google_protobuf_EnumDescriptorProto_add_value(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumValueDescriptorProto* sub = (struct google_protobuf_EnumValueDescriptorProto*)_upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE void google_protobuf_EnumDescriptorProto_set_options(google_protobuf_EnumDescriptorProto *msg, google_protobuf_EnumOptions* value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_EnumOptions*) = value; -} -UPB_INLINE struct google_protobuf_EnumOptions* google_protobuf_EnumDescriptorProto_mutable_options(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumOptions* sub = (struct google_protobuf_EnumOptions*)google_protobuf_EnumDescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_EnumOptions*)_upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_EnumDescriptorProto_set_options(msg, sub); - } - return sub; -} -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_mutable_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t *len) { - return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); -} -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange** google_protobuf_EnumDescriptorProto_resize_reserved_range(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto_EnumReservedRange**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_EnumDescriptorProto_EnumReservedRange* google_protobuf_EnumDescriptorProto_add_reserved_range(google_protobuf_EnumDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumDescriptorProto_EnumReservedRange* sub = (struct google_protobuf_EnumDescriptorProto_EnumReservedRange*)_upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(20, 40), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_mutable_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t *len) { - return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); -} -UPB_INLINE upb_strview* google_protobuf_EnumDescriptorProto_resize_reserved_name(google_protobuf_EnumDescriptorProto *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_STRING, arena); -} -UPB_INLINE bool google_protobuf_EnumDescriptorProto_add_reserved_name(google_protobuf_EnumDescriptorProto *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(24, 48), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, - arena); -} - -/* google.protobuf.EnumDescriptorProto.EnumReservedRange */ - -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_new(upb_arena *arena) { - return (google_protobuf_EnumDescriptorProto_EnumReservedRange *)_upb_msg_new(&google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena); -} -UPB_INLINE google_protobuf_EnumDescriptorProto_EnumReservedRange *google_protobuf_EnumDescriptorProto_EnumReservedRange_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_EnumDescriptorProto_EnumReservedRange *ret = google_protobuf_EnumDescriptorProto_EnumReservedRange_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_EnumDescriptorProto_EnumReservedRange_serialize(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_EnumDescriptorProto_EnumReservedRange_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_start(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumDescriptorProto_EnumReservedRange_has_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE int32_t google_protobuf_EnumDescriptorProto_EnumReservedRange_end(const google_protobuf_EnumDescriptorProto_EnumReservedRange *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } - -UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end(google_protobuf_EnumDescriptorProto_EnumReservedRange *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} - -/* google.protobuf.EnumValueDescriptorProto */ - -UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_EnumValueDescriptorProto *)_upb_msg_new(&google_protobuf_EnumValueDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_EnumValueDescriptorProto *ret = google_protobuf_EnumValueDescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumValueDescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_EnumValueDescriptorProto_serialize(const google_protobuf_EnumValueDescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_EnumValueDescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_name(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE upb_strview google_protobuf_EnumValueDescriptorProto_name(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_number(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_EnumValueDescriptorProto_number(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_EnumValueDescriptorProto_has_options(const google_protobuf_EnumValueDescriptorProto *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE const google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_options(const google_protobuf_EnumValueDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 24), const google_protobuf_EnumValueOptions*); } - -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_name(google_protobuf_EnumValueDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), upb_strview) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_number(google_protobuf_EnumValueDescriptorProto *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_EnumValueDescriptorProto_set_options(google_protobuf_EnumValueDescriptorProto *msg, google_protobuf_EnumValueOptions* value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(16, 24), google_protobuf_EnumValueOptions*) = value; -} -UPB_INLINE struct google_protobuf_EnumValueOptions* google_protobuf_EnumValueDescriptorProto_mutable_options(google_protobuf_EnumValueDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_EnumValueOptions* sub = (struct google_protobuf_EnumValueOptions*)google_protobuf_EnumValueDescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_EnumValueOptions*)_upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_EnumValueDescriptorProto_set_options(msg, sub); - } - return sub; -} - -/* google.protobuf.ServiceDescriptorProto */ - -UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_ServiceDescriptorProto *)_upb_msg_new(&google_protobuf_ServiceDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_ServiceDescriptorProto *google_protobuf_ServiceDescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_ServiceDescriptorProto *ret = google_protobuf_ServiceDescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_ServiceDescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_ServiceDescriptorProto_serialize(const google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_ServiceDescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_name(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE upb_strview google_protobuf_ServiceDescriptorProto_name(const google_protobuf_ServiceDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_method(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(16, 32)); } -UPB_INLINE const google_protobuf_MethodDescriptorProto* const* google_protobuf_ServiceDescriptorProto_method(const google_protobuf_ServiceDescriptorProto *msg, size_t *len) { return (const google_protobuf_MethodDescriptorProto* const*)_upb_array_accessor(msg, UPB_SIZE(16, 32), len); } -UPB_INLINE bool google_protobuf_ServiceDescriptorProto_has_options(const google_protobuf_ServiceDescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE const google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_options(const google_protobuf_ServiceDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), const google_protobuf_ServiceOptions*); } - -UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_name(google_protobuf_ServiceDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_mutable_method(google_protobuf_ServiceDescriptorProto *msg, size_t *len) { - return (google_protobuf_MethodDescriptorProto**)_upb_array_mutable_accessor(msg, UPB_SIZE(16, 32), len); -} -UPB_INLINE google_protobuf_MethodDescriptorProto** google_protobuf_ServiceDescriptorProto_resize_method(google_protobuf_ServiceDescriptorProto *msg, size_t len, upb_arena *arena) { - return (google_protobuf_MethodDescriptorProto**)_upb_array_resize_accessor(msg, UPB_SIZE(16, 32), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_MethodDescriptorProto* google_protobuf_ServiceDescriptorProto_add_method(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_MethodDescriptorProto* sub = (struct google_protobuf_MethodDescriptorProto*)_upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(16, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE void google_protobuf_ServiceDescriptorProto_set_options(google_protobuf_ServiceDescriptorProto *msg, google_protobuf_ServiceOptions* value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), google_protobuf_ServiceOptions*) = value; -} -UPB_INLINE struct google_protobuf_ServiceOptions* google_protobuf_ServiceDescriptorProto_mutable_options(google_protobuf_ServiceDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_ServiceOptions* sub = (struct google_protobuf_ServiceOptions*)google_protobuf_ServiceDescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_ServiceOptions*)_upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_ServiceDescriptorProto_set_options(msg, sub); - } - return sub; -} - -/* google.protobuf.MethodDescriptorProto */ - -UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_new(upb_arena *arena) { - return (google_protobuf_MethodDescriptorProto *)_upb_msg_new(&google_protobuf_MethodDescriptorProto_msginit, arena); -} -UPB_INLINE google_protobuf_MethodDescriptorProto *google_protobuf_MethodDescriptorProto_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_MethodDescriptorProto *ret = google_protobuf_MethodDescriptorProto_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_MethodDescriptorProto_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_MethodDescriptorProto_serialize(const google_protobuf_MethodDescriptorProto *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_MethodDescriptorProto_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_name(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_name(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_input_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 4); } -UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_input_type(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_output_type(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 5); } -UPB_INLINE upb_strview google_protobuf_MethodDescriptorProto_output_type(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_options(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 6); } -UPB_INLINE const google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_options(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 56), const google_protobuf_MethodOptions*); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_client_streaming(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_has_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE bool google_protobuf_MethodDescriptorProto_server_streaming(const google_protobuf_MethodDescriptorProto *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } - -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_name(google_protobuf_MethodDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_input_type(google_protobuf_MethodDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_output_type(google_protobuf_MethodDescriptorProto *msg, upb_strview value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(20, 40), upb_strview) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_options(google_protobuf_MethodDescriptorProto *msg, google_protobuf_MethodOptions* value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(28, 56), google_protobuf_MethodOptions*) = value; -} -UPB_INLINE struct google_protobuf_MethodOptions* google_protobuf_MethodDescriptorProto_mutable_options(google_protobuf_MethodDescriptorProto *msg, upb_arena *arena) { - struct google_protobuf_MethodOptions* sub = (struct google_protobuf_MethodOptions*)google_protobuf_MethodDescriptorProto_options(msg); - if (sub == NULL) { - sub = (struct google_protobuf_MethodOptions*)_upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); - if (!sub) return NULL; - google_protobuf_MethodDescriptorProto_set_options(msg, sub); - } - return sub; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_client_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE void google_protobuf_MethodDescriptorProto_set_server_streaming(google_protobuf_MethodDescriptorProto *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; -} - -/* google.protobuf.FileOptions */ - -UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_new(upb_arena *arena) { - return (google_protobuf_FileOptions *)_upb_msg_new(&google_protobuf_FileOptions_msginit, arena); -} -UPB_INLINE google_protobuf_FileOptions *google_protobuf_FileOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_FileOptions *ret = google_protobuf_FileOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_FileOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_FileOptions_serialize(const google_protobuf_FileOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_FileOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_FileOptions_has_java_package(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 11); } -UPB_INLINE upb_strview google_protobuf_FileOptions_java_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(28, 32), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_outer_classname(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 12); } -UPB_INLINE upb_strview google_protobuf_FileOptions_java_outer_classname(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(36, 48), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_optimize_for(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_FileOptions_optimize_for(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_multiple_files(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE bool google_protobuf_FileOptions_java_multiple_files(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_go_package(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 13); } -UPB_INLINE upb_strview google_protobuf_FileOptions_go_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(44, 64), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE bool google_protobuf_FileOptions_cc_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 4); } -UPB_INLINE bool google_protobuf_FileOptions_java_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(18, 18), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_py_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 5); } -UPB_INLINE bool google_protobuf_FileOptions_py_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(19, 19), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 6); } -UPB_INLINE bool google_protobuf_FileOptions_java_generate_equals_and_hash(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_deprecated(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 7); } -UPB_INLINE bool google_protobuf_FileOptions_deprecated(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(21, 21), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 8); } -UPB_INLINE bool google_protobuf_FileOptions_java_string_check_utf8(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(22, 22), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 9); } -UPB_INLINE bool google_protobuf_FileOptions_cc_enable_arenas(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(23, 23), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_objc_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 14); } -UPB_INLINE upb_strview google_protobuf_FileOptions_objc_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(52, 80), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_csharp_namespace(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 15); } -UPB_INLINE upb_strview google_protobuf_FileOptions_csharp_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_swift_prefix(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 16); } -UPB_INLINE upb_strview google_protobuf_FileOptions_swift_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(68, 112), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_class_prefix(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 17); } -UPB_INLINE upb_strview google_protobuf_FileOptions_php_class_prefix(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(76, 128), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_namespace(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 18); } -UPB_INLINE upb_strview google_protobuf_FileOptions_php_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(84, 144), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_generic_services(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 10); } -UPB_INLINE bool google_protobuf_FileOptions_php_generic_services(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool); } -UPB_INLINE bool google_protobuf_FileOptions_has_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 19); } -UPB_INLINE upb_strview google_protobuf_FileOptions_php_metadata_namespace(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(92, 160), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_ruby_package(const google_protobuf_FileOptions *msg) { return _upb_has_field(msg, 20); } -UPB_INLINE upb_strview google_protobuf_FileOptions_ruby_package(const google_protobuf_FileOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(100, 176), upb_strview); } -UPB_INLINE bool google_protobuf_FileOptions_has_uninterpreted_option(const google_protobuf_FileOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(108, 192)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FileOptions_uninterpreted_option(const google_protobuf_FileOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(108, 192), len); } - -UPB_INLINE void google_protobuf_FileOptions_set_java_package(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 11); - *UPB_PTR_AT(msg, UPB_SIZE(28, 32), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_outer_classname(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 12); - *UPB_PTR_AT(msg, UPB_SIZE(36, 48), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_optimize_for(google_protobuf_FileOptions *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_multiple_files(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_go_package(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 13); - *UPB_PTR_AT(msg, UPB_SIZE(44, 64), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(17, 17), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(18, 18), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_py_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(19, 19), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_generate_equals_and_hash(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(20, 20), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_deprecated(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 7); - *UPB_PTR_AT(msg, UPB_SIZE(21, 21), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_java_string_check_utf8(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 8); - *UPB_PTR_AT(msg, UPB_SIZE(22, 22), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_cc_enable_arenas(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 9); - *UPB_PTR_AT(msg, UPB_SIZE(23, 23), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_objc_class_prefix(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 14); - *UPB_PTR_AT(msg, UPB_SIZE(52, 80), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_csharp_namespace(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 15); - *UPB_PTR_AT(msg, UPB_SIZE(60, 96), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_swift_prefix(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 16); - *UPB_PTR_AT(msg, UPB_SIZE(68, 112), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_class_prefix(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 17); - *UPB_PTR_AT(msg, UPB_SIZE(76, 128), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_namespace(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 18); - *UPB_PTR_AT(msg, UPB_SIZE(84, 144), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_generic_services(google_protobuf_FileOptions *msg, bool value) { - _upb_sethas(msg, 10); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_php_metadata_namespace(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 19); - *UPB_PTR_AT(msg, UPB_SIZE(92, 160), upb_strview) = value; -} -UPB_INLINE void google_protobuf_FileOptions_set_ruby_package(google_protobuf_FileOptions *msg, upb_strview value) { - _upb_sethas(msg, 20); - *UPB_PTR_AT(msg, UPB_SIZE(100, 176), upb_strview) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_mutable_uninterpreted_option(google_protobuf_FileOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(108, 192), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FileOptions_resize_uninterpreted_option(google_protobuf_FileOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(108, 192), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FileOptions_add_uninterpreted_option(google_protobuf_FileOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(108, 192), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.MessageOptions */ - -UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_new(upb_arena *arena) { - return (google_protobuf_MessageOptions *)_upb_msg_new(&google_protobuf_MessageOptions_msginit, arena); -} -UPB_INLINE google_protobuf_MessageOptions *google_protobuf_MessageOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_MessageOptions *ret = google_protobuf_MessageOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_MessageOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_MessageOptions_serialize(const google_protobuf_MessageOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_MessageOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_MessageOptions_has_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE bool google_protobuf_MessageOptions_message_set_wire_format(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE bool google_protobuf_MessageOptions_no_standard_descriptor_accessor(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_deprecated(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE bool google_protobuf_MessageOptions_deprecated(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_map_entry(const google_protobuf_MessageOptions *msg) { return _upb_has_field(msg, 4); } -UPB_INLINE bool google_protobuf_MessageOptions_map_entry(const google_protobuf_MessageOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool); } -UPB_INLINE bool google_protobuf_MessageOptions_has_uninterpreted_option(const google_protobuf_MessageOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(8, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MessageOptions_uninterpreted_option(const google_protobuf_MessageOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(8, 8), len); } - -UPB_INLINE void google_protobuf_MessageOptions_set_message_set_wire_format(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_no_standard_descriptor_accessor(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_deprecated(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(3, 3), bool) = value; -} -UPB_INLINE void google_protobuf_MessageOptions_set_map_entry(google_protobuf_MessageOptions *msg, bool value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), bool) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_mutable_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(8, 8), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MessageOptions_resize_uninterpreted_option(google_protobuf_MessageOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(8, 8), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MessageOptions_add_uninterpreted_option(google_protobuf_MessageOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(8, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.FieldOptions */ - -UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_new(upb_arena *arena) { - return (google_protobuf_FieldOptions *)_upb_msg_new(&google_protobuf_FieldOptions_msginit, arena); -} -UPB_INLINE google_protobuf_FieldOptions *google_protobuf_FieldOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_FieldOptions *ret = google_protobuf_FieldOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_FieldOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_FieldOptions_serialize(const google_protobuf_FieldOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_FieldOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_FieldOptions_has_ctype(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_FieldOptions_ctype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_FieldOptions_has_packed(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE bool google_protobuf_FieldOptions_packed(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_deprecated(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 4); } -UPB_INLINE bool google_protobuf_FieldOptions_deprecated(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(25, 25), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_lazy(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 5); } -UPB_INLINE bool google_protobuf_FieldOptions_lazy(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(26, 26), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_jstype(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE int32_t google_protobuf_FieldOptions_jstype(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t); } -UPB_INLINE bool google_protobuf_FieldOptions_has_weak(const google_protobuf_FieldOptions *msg) { return _upb_has_field(msg, 6); } -UPB_INLINE bool google_protobuf_FieldOptions_weak(const google_protobuf_FieldOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(27, 27), bool); } -UPB_INLINE bool google_protobuf_FieldOptions_has_uninterpreted_option(const google_protobuf_FieldOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(28, 32)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_FieldOptions_uninterpreted_option(const google_protobuf_FieldOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(28, 32), len); } - -UPB_INLINE void google_protobuf_FieldOptions_set_ctype(google_protobuf_FieldOptions *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_packed(google_protobuf_FieldOptions *msg, bool value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), bool) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_deprecated(google_protobuf_FieldOptions *msg, bool value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(25, 25), bool) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_lazy(google_protobuf_FieldOptions *msg, bool value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(26, 26), bool) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_jstype(google_protobuf_FieldOptions *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int32_t) = value; -} -UPB_INLINE void google_protobuf_FieldOptions_set_weak(google_protobuf_FieldOptions *msg, bool value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(27, 27), bool) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_mutable_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 32), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_FieldOptions_resize_uninterpreted_option(google_protobuf_FieldOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(28, 32), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_FieldOptions_add_uninterpreted_option(google_protobuf_FieldOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(28, 32), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.OneofOptions */ - -UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_new(upb_arena *arena) { - return (google_protobuf_OneofOptions *)_upb_msg_new(&google_protobuf_OneofOptions_msginit, arena); -} -UPB_INLINE google_protobuf_OneofOptions *google_protobuf_OneofOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_OneofOptions *ret = google_protobuf_OneofOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_OneofOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_OneofOptions_serialize(const google_protobuf_OneofOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_OneofOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_OneofOptions_has_uninterpreted_option(const google_protobuf_OneofOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_OneofOptions_uninterpreted_option(const google_protobuf_OneofOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } - -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_mutable_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_OneofOptions_resize_uninterpreted_option(google_protobuf_OneofOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_OneofOptions_add_uninterpreted_option(google_protobuf_OneofOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.EnumOptions */ - -UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_new(upb_arena *arena) { - return (google_protobuf_EnumOptions *)_upb_msg_new(&google_protobuf_EnumOptions_msginit, arena); -} -UPB_INLINE google_protobuf_EnumOptions *google_protobuf_EnumOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_EnumOptions *ret = google_protobuf_EnumOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_EnumOptions_serialize(const google_protobuf_EnumOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_EnumOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_EnumOptions_has_allow_alias(const google_protobuf_EnumOptions *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE bool google_protobuf_EnumOptions_allow_alias(const google_protobuf_EnumOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_deprecated(const google_protobuf_EnumOptions *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE bool google_protobuf_EnumOptions_deprecated(const google_protobuf_EnumOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool); } -UPB_INLINE bool google_protobuf_EnumOptions_has_uninterpreted_option(const google_protobuf_EnumOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumOptions_uninterpreted_option(const google_protobuf_EnumOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } - -UPB_INLINE void google_protobuf_EnumOptions_set_allow_alias(google_protobuf_EnumOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE void google_protobuf_EnumOptions_set_deprecated(google_protobuf_EnumOptions *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(2, 2), bool) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_mutable_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumOptions_resize_uninterpreted_option(google_protobuf_EnumOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumOptions_add_uninterpreted_option(google_protobuf_EnumOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.EnumValueOptions */ - -UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_new(upb_arena *arena) { - return (google_protobuf_EnumValueOptions *)_upb_msg_new(&google_protobuf_EnumValueOptions_msginit, arena); -} -UPB_INLINE google_protobuf_EnumValueOptions *google_protobuf_EnumValueOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_EnumValueOptions *ret = google_protobuf_EnumValueOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_EnumValueOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_EnumValueOptions_serialize(const google_protobuf_EnumValueOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_EnumValueOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_EnumValueOptions_has_deprecated(const google_protobuf_EnumValueOptions *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE bool google_protobuf_EnumValueOptions_deprecated(const google_protobuf_EnumValueOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_EnumValueOptions_has_uninterpreted_option(const google_protobuf_EnumValueOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_EnumValueOptions_uninterpreted_option(const google_protobuf_EnumValueOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } - -UPB_INLINE void google_protobuf_EnumValueOptions_set_deprecated(google_protobuf_EnumValueOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_mutable_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_EnumValueOptions_resize_uninterpreted_option(google_protobuf_EnumValueOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_EnumValueOptions_add_uninterpreted_option(google_protobuf_EnumValueOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.ServiceOptions */ - -UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_new(upb_arena *arena) { - return (google_protobuf_ServiceOptions *)_upb_msg_new(&google_protobuf_ServiceOptions_msginit, arena); -} -UPB_INLINE google_protobuf_ServiceOptions *google_protobuf_ServiceOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_ServiceOptions *ret = google_protobuf_ServiceOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_ServiceOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_ServiceOptions_serialize(const google_protobuf_ServiceOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_ServiceOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_ServiceOptions_has_deprecated(const google_protobuf_ServiceOptions *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE bool google_protobuf_ServiceOptions_deprecated(const google_protobuf_ServiceOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } -UPB_INLINE bool google_protobuf_ServiceOptions_has_uninterpreted_option(const google_protobuf_ServiceOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(4, 8)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_ServiceOptions_uninterpreted_option(const google_protobuf_ServiceOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(4, 8), len); } - -UPB_INLINE void google_protobuf_ServiceOptions_set_deprecated(google_protobuf_ServiceOptions *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_mutable_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(4, 8), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_ServiceOptions_resize_uninterpreted_option(google_protobuf_ServiceOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(4, 8), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_ServiceOptions_add_uninterpreted_option(google_protobuf_ServiceOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(4, 8), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.MethodOptions */ - -UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_new(upb_arena *arena) { - return (google_protobuf_MethodOptions *)_upb_msg_new(&google_protobuf_MethodOptions_msginit, arena); -} -UPB_INLINE google_protobuf_MethodOptions *google_protobuf_MethodOptions_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_MethodOptions *ret = google_protobuf_MethodOptions_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_MethodOptions_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_MethodOptions_serialize(const google_protobuf_MethodOptions *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_MethodOptions_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_MethodOptions_has_deprecated(const google_protobuf_MethodOptions *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE bool google_protobuf_MethodOptions_deprecated(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool); } -UPB_INLINE bool google_protobuf_MethodOptions_has_idempotency_level(const google_protobuf_MethodOptions *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_MethodOptions_idempotency_level(const google_protobuf_MethodOptions *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } -UPB_INLINE bool google_protobuf_MethodOptions_has_uninterpreted_option(const google_protobuf_MethodOptions *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(20, 24)); } -UPB_INLINE const google_protobuf_UninterpretedOption* const* google_protobuf_MethodOptions_uninterpreted_option(const google_protobuf_MethodOptions *msg, size_t *len) { return (const google_protobuf_UninterpretedOption* const*)_upb_array_accessor(msg, UPB_SIZE(20, 24), len); } - -UPB_INLINE void google_protobuf_MethodOptions_set_deprecated(google_protobuf_MethodOptions *msg, bool value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), bool) = value; -} -UPB_INLINE void google_protobuf_MethodOptions_set_idempotency_level(google_protobuf_MethodOptions *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_mutable_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t *len) { - return (google_protobuf_UninterpretedOption**)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 24), len); -} -UPB_INLINE google_protobuf_UninterpretedOption** google_protobuf_MethodOptions_resize_uninterpreted_option(google_protobuf_MethodOptions *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption**)_upb_array_resize_accessor(msg, UPB_SIZE(20, 24), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption* google_protobuf_MethodOptions_add_uninterpreted_option(google_protobuf_MethodOptions *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption* sub = (struct google_protobuf_UninterpretedOption*)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(20, 24), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.UninterpretedOption */ - -UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_new(upb_arena *arena) { - return (google_protobuf_UninterpretedOption *)_upb_msg_new(&google_protobuf_UninterpretedOption_msginit, arena); -} -UPB_INLINE google_protobuf_UninterpretedOption *google_protobuf_UninterpretedOption_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_UninterpretedOption *ret = google_protobuf_UninterpretedOption_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_UninterpretedOption_serialize(const google_protobuf_UninterpretedOption *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_UninterpretedOption_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_UninterpretedOption_has_name(const google_protobuf_UninterpretedOption *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(56, 80)); } -UPB_INLINE const google_protobuf_UninterpretedOption_NamePart* const* google_protobuf_UninterpretedOption_name(const google_protobuf_UninterpretedOption *msg, size_t *len) { return (const google_protobuf_UninterpretedOption_NamePart* const*)_upb_array_accessor(msg, UPB_SIZE(56, 80), len); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_identifier_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 4); } -UPB_INLINE upb_strview google_protobuf_UninterpretedOption_identifier_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_strview); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE uint64_t google_protobuf_UninterpretedOption_positive_int_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE int64_t google_protobuf_UninterpretedOption_negative_int_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_double_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE double google_protobuf_UninterpretedOption_double_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_string_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 5); } -UPB_INLINE upb_strview google_protobuf_UninterpretedOption_string_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_strview); } -UPB_INLINE bool google_protobuf_UninterpretedOption_has_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return _upb_has_field(msg, 6); } -UPB_INLINE upb_strview google_protobuf_UninterpretedOption_aggregate_value(const google_protobuf_UninterpretedOption *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_strview); } - -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_mutable_name(google_protobuf_UninterpretedOption *msg, size_t *len) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_mutable_accessor(msg, UPB_SIZE(56, 80), len); -} -UPB_INLINE google_protobuf_UninterpretedOption_NamePart** google_protobuf_UninterpretedOption_resize_name(google_protobuf_UninterpretedOption *msg, size_t len, upb_arena *arena) { - return (google_protobuf_UninterpretedOption_NamePart**)_upb_array_resize_accessor(msg, UPB_SIZE(56, 80), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_UninterpretedOption_NamePart* google_protobuf_UninterpretedOption_add_name(google_protobuf_UninterpretedOption *msg, upb_arena *arena) { - struct google_protobuf_UninterpretedOption_NamePart* sub = (struct google_protobuf_UninterpretedOption_NamePart*)_upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(56, 80), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_identifier_value(google_protobuf_UninterpretedOption *msg, upb_strview value) { - _upb_sethas(msg, 4); - *UPB_PTR_AT(msg, UPB_SIZE(32, 32), upb_strview) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_positive_int_value(google_protobuf_UninterpretedOption *msg, uint64_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), uint64_t) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_negative_int_value(google_protobuf_UninterpretedOption *msg, int64_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(16, 16), int64_t) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_double_value(google_protobuf_UninterpretedOption *msg, double value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(24, 24), double) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_string_value(google_protobuf_UninterpretedOption *msg, upb_strview value) { - _upb_sethas(msg, 5); - *UPB_PTR_AT(msg, UPB_SIZE(40, 48), upb_strview) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_set_aggregate_value(google_protobuf_UninterpretedOption *msg, upb_strview value) { - _upb_sethas(msg, 6); - *UPB_PTR_AT(msg, UPB_SIZE(48, 64), upb_strview) = value; -} - -/* google.protobuf.UninterpretedOption.NamePart */ - -UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_new(upb_arena *arena) { - return (google_protobuf_UninterpretedOption_NamePart *)_upb_msg_new(&google_protobuf_UninterpretedOption_NamePart_msginit, arena); -} -UPB_INLINE google_protobuf_UninterpretedOption_NamePart *google_protobuf_UninterpretedOption_NamePart_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_UninterpretedOption_NamePart *ret = google_protobuf_UninterpretedOption_NamePart_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_UninterpretedOption_NamePart_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_UninterpretedOption_NamePart_serialize(const google_protobuf_UninterpretedOption_NamePart *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_UninterpretedOption_NamePart_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE upb_strview google_protobuf_UninterpretedOption_NamePart_name_part(const google_protobuf_UninterpretedOption_NamePart *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_has_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE bool google_protobuf_UninterpretedOption_NamePart_is_extension(const google_protobuf_UninterpretedOption_NamePart *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool); } - -UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_name_part(google_protobuf_UninterpretedOption_NamePart *msg, upb_strview value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE void google_protobuf_UninterpretedOption_NamePart_set_is_extension(google_protobuf_UninterpretedOption_NamePart *msg, bool value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(1, 1), bool) = value; -} - -/* google.protobuf.SourceCodeInfo */ - -UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_new(upb_arena *arena) { - return (google_protobuf_SourceCodeInfo *)_upb_msg_new(&google_protobuf_SourceCodeInfo_msginit, arena); -} -UPB_INLINE google_protobuf_SourceCodeInfo *google_protobuf_SourceCodeInfo_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_SourceCodeInfo *ret = google_protobuf_SourceCodeInfo_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_SourceCodeInfo_serialize(const google_protobuf_SourceCodeInfo *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_SourceCodeInfo_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_SourceCodeInfo_has_location(const google_protobuf_SourceCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_SourceCodeInfo_Location* const* google_protobuf_SourceCodeInfo_location(const google_protobuf_SourceCodeInfo *msg, size_t *len) { return (const google_protobuf_SourceCodeInfo_Location* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } - -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_mutable_location(google_protobuf_SourceCodeInfo *msg, size_t *len) { - return (google_protobuf_SourceCodeInfo_Location**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_SourceCodeInfo_Location** google_protobuf_SourceCodeInfo_resize_location(google_protobuf_SourceCodeInfo *msg, size_t len, upb_arena *arena) { - return (google_protobuf_SourceCodeInfo_Location**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_SourceCodeInfo_Location* google_protobuf_SourceCodeInfo_add_location(google_protobuf_SourceCodeInfo *msg, upb_arena *arena) { - struct google_protobuf_SourceCodeInfo_Location* sub = (struct google_protobuf_SourceCodeInfo_Location*)_upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.SourceCodeInfo.Location */ - -UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_new(upb_arena *arena) { - return (google_protobuf_SourceCodeInfo_Location *)_upb_msg_new(&google_protobuf_SourceCodeInfo_Location_msginit, arena); -} -UPB_INLINE google_protobuf_SourceCodeInfo_Location *google_protobuf_SourceCodeInfo_Location_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_SourceCodeInfo_Location *ret = google_protobuf_SourceCodeInfo_Location_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_SourceCodeInfo_Location_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_SourceCodeInfo_Location_serialize(const google_protobuf_SourceCodeInfo_Location *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_SourceCodeInfo_Location_msginit, arena, len); -} - -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_path(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 40), len); } -UPB_INLINE int32_t const* google_protobuf_SourceCodeInfo_Location_span(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(24, 48), len); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE upb_strview google_protobuf_SourceCodeInfo_Location_leading_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview); } -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_has_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE upb_strview google_protobuf_SourceCodeInfo_Location_trailing_comments(const google_protobuf_SourceCodeInfo_Location *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview); } -UPB_INLINE upb_strview const* google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { return (upb_strview const*)_upb_array_accessor(msg, UPB_SIZE(28, 56), len); } - -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_path(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 40), len); -} -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_path(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 40), len, UPB_TYPE_INT32, arena); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_path(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(20, 40), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, - arena); -} -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_mutable_span(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(24, 48), len); -} -UPB_INLINE int32_t* google_protobuf_SourceCodeInfo_Location_resize_span(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(24, 48), len, UPB_TYPE_INT32, arena); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_span(google_protobuf_SourceCodeInfo_Location *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(24, 48), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, - arena); -} -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_leading_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 8), upb_strview) = value; -} -UPB_INLINE void google_protobuf_SourceCodeInfo_Location_set_trailing_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(12, 24), upb_strview) = value; -} -UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_mutable_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t *len) { - return (upb_strview*)_upb_array_mutable_accessor(msg, UPB_SIZE(28, 56), len); -} -UPB_INLINE upb_strview* google_protobuf_SourceCodeInfo_Location_resize_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, size_t len, upb_arena *arena) { - return (upb_strview*)_upb_array_resize_accessor(msg, UPB_SIZE(28, 56), len, UPB_TYPE_STRING, arena); -} -UPB_INLINE bool google_protobuf_SourceCodeInfo_Location_add_leading_detached_comments(google_protobuf_SourceCodeInfo_Location *msg, upb_strview val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(28, 56), UPB_SIZE(8, 16), UPB_TYPE_STRING, &val, - arena); -} - -/* google.protobuf.GeneratedCodeInfo */ - -UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_new(upb_arena *arena) { - return (google_protobuf_GeneratedCodeInfo *)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_msginit, arena); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo *google_protobuf_GeneratedCodeInfo_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_GeneratedCodeInfo *ret = google_protobuf_GeneratedCodeInfo_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_GeneratedCodeInfo_serialize(const google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_msginit, arena, len); -} - -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_has_annotation(const google_protobuf_GeneratedCodeInfo *msg) { return _upb_has_submsg_nohasbit(msg, UPB_SIZE(0, 0)); } -UPB_INLINE const google_protobuf_GeneratedCodeInfo_Annotation* const* google_protobuf_GeneratedCodeInfo_annotation(const google_protobuf_GeneratedCodeInfo *msg, size_t *len) { return (const google_protobuf_GeneratedCodeInfo_Annotation* const*)_upb_array_accessor(msg, UPB_SIZE(0, 0), len); } - -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_mutable_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t *len) { - return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_mutable_accessor(msg, UPB_SIZE(0, 0), len); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation** google_protobuf_GeneratedCodeInfo_resize_annotation(google_protobuf_GeneratedCodeInfo *msg, size_t len, upb_arena *arena) { - return (google_protobuf_GeneratedCodeInfo_Annotation**)_upb_array_resize_accessor(msg, UPB_SIZE(0, 0), len, UPB_TYPE_MESSAGE, arena); -} -UPB_INLINE struct google_protobuf_GeneratedCodeInfo_Annotation* google_protobuf_GeneratedCodeInfo_add_annotation(google_protobuf_GeneratedCodeInfo *msg, upb_arena *arena) { - struct google_protobuf_GeneratedCodeInfo_Annotation* sub = (struct google_protobuf_GeneratedCodeInfo_Annotation*)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); - bool ok = _upb_array_append_accessor( - msg, UPB_SIZE(0, 0), UPB_SIZE(4, 8), UPB_TYPE_MESSAGE, &sub, arena); - if (!ok) return NULL; - return sub; -} - -/* google.protobuf.GeneratedCodeInfo.Annotation */ - -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_new(upb_arena *arena) { - return (google_protobuf_GeneratedCodeInfo_Annotation *)_upb_msg_new(&google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena); -} -UPB_INLINE google_protobuf_GeneratedCodeInfo_Annotation *google_protobuf_GeneratedCodeInfo_Annotation_parse(const char *buf, size_t size, - upb_arena *arena) { - google_protobuf_GeneratedCodeInfo_Annotation *ret = google_protobuf_GeneratedCodeInfo_Annotation_new(arena); - return (ret && upb_decode(buf, size, ret, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena)) ? ret : NULL; -} -UPB_INLINE char *google_protobuf_GeneratedCodeInfo_Annotation_serialize(const google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_arena *arena, size_t *len) { - return upb_encode(msg, &google_protobuf_GeneratedCodeInfo_Annotation_msginit, arena, len); -} - -UPB_INLINE int32_t const* google_protobuf_GeneratedCodeInfo_Annotation_path(const google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { return (int32_t const*)_upb_array_accessor(msg, UPB_SIZE(20, 32), len); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_has_field(msg, 3); } -UPB_INLINE upb_strview google_protobuf_GeneratedCodeInfo_Annotation_source_file(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_strview); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_has_field(msg, 1); } -UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_begin(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t); } -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_has_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return _upb_has_field(msg, 2); } -UPB_INLINE int32_t google_protobuf_GeneratedCodeInfo_Annotation_end(const google_protobuf_GeneratedCodeInfo_Annotation *msg) { return *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t); } - -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_mutable_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t *len) { - return (int32_t*)_upb_array_mutable_accessor(msg, UPB_SIZE(20, 32), len); -} -UPB_INLINE int32_t* google_protobuf_GeneratedCodeInfo_Annotation_resize_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, size_t len, upb_arena *arena) { - return (int32_t*)_upb_array_resize_accessor(msg, UPB_SIZE(20, 32), len, UPB_TYPE_INT32, arena); -} -UPB_INLINE bool google_protobuf_GeneratedCodeInfo_Annotation_add_path(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t val, upb_arena *arena) { - return _upb_array_append_accessor(msg, UPB_SIZE(20, 32), UPB_SIZE(4, 4), UPB_TYPE_INT32, &val, - arena); -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_source_file(google_protobuf_GeneratedCodeInfo_Annotation *msg, upb_strview value) { - _upb_sethas(msg, 3); - *UPB_PTR_AT(msg, UPB_SIZE(12, 16), upb_strview) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_begin(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 1); - *UPB_PTR_AT(msg, UPB_SIZE(4, 4), int32_t) = value; -} -UPB_INLINE void google_protobuf_GeneratedCodeInfo_Annotation_set_end(google_protobuf_GeneratedCodeInfo_Annotation *msg, int32_t value) { - _upb_sethas(msg, 2); - *UPB_PTR_AT(msg, UPB_SIZE(8, 8), int32_t) = value; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_PROTO_UPB_H_ */ -/* -** Defs are upb's internal representation of the constructs that can appear -** in a .proto file: -** -** - upb_msgdef: describes a "message" construct. -** - upb_fielddef: describes a message field. -** - upb_filedef: describes a .proto file and its defs. -** - upb_enumdef: describes an enum. -** - upb_oneofdef: describes a oneof. -** -** TODO: definitions of services. -*/ - -#ifndef UPB_DEF_H_ -#define UPB_DEF_H_ - - - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -struct upb_enumdef; -typedef struct upb_enumdef upb_enumdef; -struct upb_fielddef; -typedef struct upb_fielddef upb_fielddef; -struct upb_filedef; -typedef struct upb_filedef upb_filedef; -struct upb_msgdef; -typedef struct upb_msgdef upb_msgdef; -struct upb_oneofdef; -typedef struct upb_oneofdef upb_oneofdef; -struct upb_symtab; -typedef struct upb_symtab upb_symtab; - -typedef enum { - UPB_SYNTAX_PROTO2 = 2, - UPB_SYNTAX_PROTO3 = 3 -} upb_syntax_t; - -/* All the different kind of well known type messages. For simplicity of check, - * number wrappers and string wrappers are grouped together. Make sure the - * order and merber of these groups are not changed. - */ -typedef enum { - UPB_WELLKNOWN_UNSPECIFIED, - UPB_WELLKNOWN_ANY, - UPB_WELLKNOWN_FIELDMASK, - UPB_WELLKNOWN_DURATION, - UPB_WELLKNOWN_TIMESTAMP, - /* number wrappers */ - UPB_WELLKNOWN_DOUBLEVALUE, - UPB_WELLKNOWN_FLOATVALUE, - UPB_WELLKNOWN_INT64VALUE, - UPB_WELLKNOWN_UINT64VALUE, - UPB_WELLKNOWN_INT32VALUE, - UPB_WELLKNOWN_UINT32VALUE, - /* string wrappers */ - UPB_WELLKNOWN_STRINGVALUE, - UPB_WELLKNOWN_BYTESVALUE, - UPB_WELLKNOWN_BOOLVALUE, - UPB_WELLKNOWN_VALUE, - UPB_WELLKNOWN_LISTVALUE, - UPB_WELLKNOWN_STRUCT -} upb_wellknowntype_t; - -/* upb_fielddef ***************************************************************/ - -/* Maximum field number allowed for FieldDefs. This is an inherent limit of the - * protobuf wire format. */ -#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) - -const char *upb_fielddef_fullname(const upb_fielddef *f); -upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f); -upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f); -upb_label_t upb_fielddef_label(const upb_fielddef *f); -uint32_t upb_fielddef_number(const upb_fielddef *f); -const char *upb_fielddef_name(const upb_fielddef *f); -const char *upb_fielddef_jsonname(const upb_fielddef *f); -bool upb_fielddef_isextension(const upb_fielddef *f); -bool upb_fielddef_lazy(const upb_fielddef *f); -bool upb_fielddef_packed(const upb_fielddef *f); -const upb_filedef *upb_fielddef_file(const upb_fielddef *f); -const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); -const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f); -const upb_oneofdef *upb_fielddef_realcontainingoneof(const upb_fielddef *f); -uint32_t upb_fielddef_index(const upb_fielddef *f); -bool upb_fielddef_issubmsg(const upb_fielddef *f); -bool upb_fielddef_isstring(const upb_fielddef *f); -bool upb_fielddef_isseq(const upb_fielddef *f); -bool upb_fielddef_isprimitive(const upb_fielddef *f); -bool upb_fielddef_ismap(const upb_fielddef *f); -int64_t upb_fielddef_defaultint64(const upb_fielddef *f); -int32_t upb_fielddef_defaultint32(const upb_fielddef *f); -uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f); -uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f); -bool upb_fielddef_defaultbool(const upb_fielddef *f); -float upb_fielddef_defaultfloat(const upb_fielddef *f); -double upb_fielddef_defaultdouble(const upb_fielddef *f); -const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len); -bool upb_fielddef_hassubdef(const upb_fielddef *f); -bool upb_fielddef_haspresence(const upb_fielddef *f); -const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); -const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); -const upb_msglayout_field *upb_fielddef_layout(const upb_fielddef *f); - -/* Internal only. */ -uint32_t upb_fielddef_selectorbase(const upb_fielddef *f); - -/* upb_oneofdef ***************************************************************/ - -typedef upb_inttable_iter upb_oneof_iter; - -const char *upb_oneofdef_name(const upb_oneofdef *o); -const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o); -int upb_oneofdef_numfields(const upb_oneofdef *o); -uint32_t upb_oneofdef_index(const upb_oneofdef *o); -bool upb_oneofdef_issynthetic(const upb_oneofdef *o); - -/* Oneof lookups: - * - ntof: look up a field by name. - * - ntofz: look up a field by name (as a null-terminated string). - * - itof: look up a field by number. */ -const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, - const char *name, size_t length); -UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o, - const char *name) { - return upb_oneofdef_ntof(o, name, strlen(name)); -} -const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num); - -/* upb_oneof_iter i; - * for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) { - * // ... - * } - */ -void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o); -void upb_oneof_next(upb_oneof_iter *iter); -bool upb_oneof_done(upb_oneof_iter *iter); -upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter); -void upb_oneof_iter_setdone(upb_oneof_iter *iter); -bool upb_oneof_iter_isequal(const upb_oneof_iter *iter1, - const upb_oneof_iter *iter2); - -/* upb_msgdef *****************************************************************/ - -typedef upb_inttable_iter upb_msg_field_iter; -typedef upb_strtable_iter upb_msg_oneof_iter; - -/* Well-known field tag numbers for map-entry messages. */ -#define UPB_MAPENTRY_KEY 1 -#define UPB_MAPENTRY_VALUE 2 - -/* Well-known field tag numbers for Any messages. */ -#define UPB_ANY_TYPE 1 -#define UPB_ANY_VALUE 2 - -/* Well-known field tag numbers for timestamp messages. */ -#define UPB_DURATION_SECONDS 1 -#define UPB_DURATION_NANOS 2 - -/* Well-known field tag numbers for duration messages. */ -#define UPB_TIMESTAMP_SECONDS 1 -#define UPB_TIMESTAMP_NANOS 2 - -const char *upb_msgdef_fullname(const upb_msgdef *m); -const upb_filedef *upb_msgdef_file(const upb_msgdef *m); -const char *upb_msgdef_name(const upb_msgdef *m); -int upb_msgdef_numfields(const upb_msgdef *m); -int upb_msgdef_numoneofs(const upb_msgdef *m); -int upb_msgdef_numrealoneofs(const upb_msgdef *m); -upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m); -bool upb_msgdef_mapentry(const upb_msgdef *m); -upb_wellknowntype_t upb_msgdef_wellknowntype(const upb_msgdef *m); -bool upb_msgdef_isnumberwrapper(const upb_msgdef *m); -const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i); -const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, - size_t len); -const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, - size_t len); -const upb_msglayout *upb_msgdef_layout(const upb_msgdef *m); -const upb_fielddef *_upb_msgdef_field(const upb_msgdef *m, int i); - -UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m, - const char *name) { - return upb_msgdef_ntoo(m, name, strlen(name)); -} - -UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m, - const char *name) { - return upb_msgdef_ntof(m, name, strlen(name)); -} - -/* Internal-only. */ -size_t upb_msgdef_selectorcount(const upb_msgdef *m); -uint32_t upb_msgdef_submsgfieldcount(const upb_msgdef *m); - -/* Lookup of either field or oneof by name. Returns whether either was found. - * If the return is true, then the found def will be set, and the non-found - * one set to NULL. */ -bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, - const upb_fielddef **f, const upb_oneofdef **o); - -UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name, - const upb_fielddef **f, - const upb_oneofdef **o) { - return upb_msgdef_lookupname(m, name, strlen(name), f, o); -} - -/* Returns a field by either JSON name or regular proto name. */ -const upb_fielddef *upb_msgdef_lookupjsonname(const upb_msgdef *m, - const char *name, size_t len); - -/* Iteration over fields and oneofs. For example: - * - * upb_msg_field_iter i; - * for(upb_msg_field_begin(&i, m); - * !upb_msg_field_done(&i); - * upb_msg_field_next(&i)) { - * upb_fielddef *f = upb_msg_iter_field(&i); - * // ... - * } - * - * For C we don't have separate iterators for const and non-const. - * It is the caller's responsibility to cast the upb_fielddef* to - * const if the upb_msgdef* is const. */ -void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m); -void upb_msg_field_next(upb_msg_field_iter *iter); -bool upb_msg_field_done(const upb_msg_field_iter *iter); -upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter); -void upb_msg_field_iter_setdone(upb_msg_field_iter *iter); -bool upb_msg_field_iter_isequal(const upb_msg_field_iter * iter1, - const upb_msg_field_iter * iter2); - -/* Similar to above, we also support iterating through the oneofs in a - * msgdef. */ -void upb_msg_oneof_begin(upb_msg_oneof_iter * iter, const upb_msgdef *m); -void upb_msg_oneof_next(upb_msg_oneof_iter * iter); -bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter); -const upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter); -void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter * iter); -bool upb_msg_oneof_iter_isequal(const upb_msg_oneof_iter *iter1, - const upb_msg_oneof_iter *iter2); - -/* upb_enumdef ****************************************************************/ - -typedef upb_strtable_iter upb_enum_iter; - -const char *upb_enumdef_fullname(const upb_enumdef *e); -const char *upb_enumdef_name(const upb_enumdef *e); -const upb_filedef *upb_enumdef_file(const upb_enumdef *e); -int32_t upb_enumdef_default(const upb_enumdef *e); -int upb_enumdef_numvals(const upb_enumdef *e); - -/* Enum lookups: - * - ntoi: look up a name with specified length. - * - ntoiz: look up a name provided as a null-terminated string. - * - iton: look up an integer, returning the name as a null-terminated - * string. */ -bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len, - int32_t *num); -UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e, - const char *name, int32_t *num) { - return upb_enumdef_ntoi(e, name, strlen(name), num); -} -const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num); - -/* upb_enum_iter i; - * for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) { - * // ... - * } - */ -void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e); -void upb_enum_next(upb_enum_iter *iter); -bool upb_enum_done(upb_enum_iter *iter); -const char *upb_enum_iter_name(upb_enum_iter *iter); -int32_t upb_enum_iter_number(upb_enum_iter *iter); - -/* upb_filedef ****************************************************************/ - -const char *upb_filedef_name(const upb_filedef *f); -const char *upb_filedef_package(const upb_filedef *f); -const char *upb_filedef_phpprefix(const upb_filedef *f); -const char *upb_filedef_phpnamespace(const upb_filedef *f); -upb_syntax_t upb_filedef_syntax(const upb_filedef *f); -int upb_filedef_depcount(const upb_filedef *f); -int upb_filedef_msgcount(const upb_filedef *f); -int upb_filedef_enumcount(const upb_filedef *f); -const upb_filedef *upb_filedef_dep(const upb_filedef *f, int i); -const upb_msgdef *upb_filedef_msg(const upb_filedef *f, int i); -const upb_enumdef *upb_filedef_enum(const upb_filedef *f, int i); - -/* upb_symtab *****************************************************************/ - -upb_symtab *upb_symtab_new(void); -void upb_symtab_free(upb_symtab* s); -const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym); -const upb_msgdef *upb_symtab_lookupmsg2( - const upb_symtab *s, const char *sym, size_t len); -const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym); -const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name); -const upb_filedef *upb_symtab_lookupfile2( - const upb_symtab *s, const char *name, size_t len); -int upb_symtab_filecount(const upb_symtab *s); -const upb_filedef *upb_symtab_addfile( - upb_symtab *s, const google_protobuf_FileDescriptorProto *file, - upb_status *status); - -/* For generated code only: loads a generated descriptor. */ -typedef struct upb_def_init { - struct upb_def_init **deps; /* Dependencies of this file. */ - const upb_msglayout **layouts; /* Pre-order layouts of all messages. */ - const char *filename; - upb_strview descriptor; /* Serialized descriptor. */ -} upb_def_init; - -bool _upb_symtab_loaddefinit(upb_symtab *s, const upb_def_init *init); - - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ - -#endif /* UPB_DEF_H_ */ - -#ifndef UPB_REFLECTION_H_ -#define UPB_REFLECTION_H_ - - - -typedef union { - bool bool_val; - float float_val; - double double_val; - int32_t int32_val; - int64_t int64_val; - uint32_t uint32_val; - uint64_t uint64_val; - const upb_map* map_val; - const upb_msg* msg_val; - const upb_array* array_val; - upb_strview str_val; -} upb_msgval; - -typedef union { - upb_map* map; - upb_msg* msg; - upb_array* array; -} upb_mutmsgval; - -/** upb_msg *******************************************************************/ - -/* Creates a new message of the given type in the given arena. */ -upb_msg *upb_msg_new(const upb_msgdef *m, upb_arena *a); - -/* Returns the value associated with this field. */ -upb_msgval upb_msg_get(const upb_msg *msg, const upb_fielddef *f); - -/* Returns a mutable pointer to a map, array, or submessage value. If the given - * arena is non-NULL this will construct a new object if it was not previously - * present. May not be called for primitive fields. */ -upb_mutmsgval upb_msg_mutable(upb_msg *msg, const upb_fielddef *f, upb_arena *a); - -/* May only be called for fields where upb_fielddef_haspresence(f) == true. */ -bool upb_msg_has(const upb_msg *msg, const upb_fielddef *f); - -/* Returns whether any field is set in the oneof. */ -bool upb_msg_hasoneof(const upb_msg *msg, const upb_oneofdef *o); - -/* Sets the given field to the given value. For a msg/array/map/string, the - * value must be in the same arena. */ -void upb_msg_set(upb_msg *msg, const upb_fielddef *f, upb_msgval val, - upb_arena *a); - -/* Clears any field presence and sets the value back to its default. */ -void upb_msg_clearfield(upb_msg *msg, const upb_fielddef *f); - -/* Iterate over present fields. - * - * size_t iter = UPB_MSG_BEGIN; - * const upb_fielddef *f; - * upb_msgval val; - * while (upb_msg_next(msg, m, ext_pool, &f, &val, &iter)) { - * process_field(f, val); - * } - * - * If ext_pool is NULL, no extensions will be returned. If the given symtab - * returns extensions that don't match what is in this message, those extensions - * will be skipped. - */ - -#define UPB_MSG_BEGIN -1 -bool upb_msg_next(const upb_msg *msg, const upb_msgdef *m, - const upb_symtab *ext_pool, const upb_fielddef **f, - upb_msgval *val, size_t *iter); - -/* Adds unknown data (serialized protobuf data) to the given message. The data - * is copied into the message instance. */ -void upb_msg_addunknown(upb_msg *msg, const char *data, size_t len, - upb_arena *arena); - -/* Returns a reference to the message's unknown data. */ -const char *upb_msg_getunknown(const upb_msg *msg, size_t *len); - -/** upb_array *****************************************************************/ - -/* Creates a new array on the given arena that holds elements of this type. */ -upb_array *upb_array_new(upb_arena *a, upb_fieldtype_t type); - -/* Returns the size of the array. */ -size_t upb_array_size(const upb_array *arr); - -/* Returns the given element, which must be within the array's current size. */ -upb_msgval upb_array_get(const upb_array *arr, size_t i); - -/* Sets the given element, which must be within the array's current size. */ -void upb_array_set(upb_array *arr, size_t i, upb_msgval val); - -/* Appends an element to the array. Returns false on allocation failure. */ -bool upb_array_append(upb_array *array, upb_msgval val, upb_arena *arena); - -/* Changes the size of a vector. New elements are initialized to empty/0. - * Returns false on allocation failure. */ -bool upb_array_resize(upb_array *array, size_t size, upb_arena *arena); - -/** upb_map *******************************************************************/ - -/* Creates a new map on the given arena with the given key/value size. */ -upb_map *upb_map_new(upb_arena *a, upb_fieldtype_t key_type, - upb_fieldtype_t value_type); - -/* Returns the number of entries in the map. */ -size_t upb_map_size(const upb_map *map); - -/* Stores a value for the given key into |*val| (or the zero value if the key is - * not present). Returns whether the key was present. The |val| pointer may be - * NULL, in which case the function tests whether the given key is present. */ -bool upb_map_get(const upb_map *map, upb_msgval key, upb_msgval *val); - -/* Removes all entries in the map. */ -void upb_map_clear(upb_map *map); - -/* Sets the given key to the given value. Returns true if this was a new key in - * the map, or false if an existing key was replaced. */ -bool upb_map_set(upb_map *map, upb_msgval key, upb_msgval val, - upb_arena *arena); - -/* Deletes this key from the table. Returns true if the key was present. */ -bool upb_map_delete(upb_map *map, upb_msgval key); - -/* Map iteration: - * - * size_t iter = UPB_MAP_BEGIN; - * while (upb_mapiter_next(map, &iter)) { - * upb_msgval key = upb_mapiter_key(map, iter); - * upb_msgval val = upb_mapiter_value(map, iter); - * - * // If mutating is desired. - * upb_mapiter_setvalue(map, iter, value2); - * } - */ - -/* Advances to the next entry. Returns false if no more entries are present. */ -bool upb_mapiter_next(const upb_map *map, size_t *iter); - -/* Returns the key and value for this entry of the map. */ -upb_msgval upb_mapiter_key(const upb_map *map, size_t iter); -upb_msgval upb_mapiter_value(const upb_map *map, size_t iter); - -/* Sets the value for this entry. The iterator must not be done, and the - * iterator must not have been initialized const. */ -void upb_mapiter_setvalue(upb_map *map, size_t iter, upb_msgval value); - - -#endif /* UPB_REFLECTION_H_ */ -/* -** upb::Handlers (upb_handlers) -** -** A upb_handlers is like a virtual table for a upb_msgdef. Each field of the -** message can have associated functions that will be called when we are -** parsing or visiting a stream of data. This is similar to how handlers work -** in SAX (the Simple API for XML). -** -** The handlers have no idea where the data is coming from, so a single set of -** handlers could be used with two completely different data sources (for -** example, a parser and a visitor over in-memory objects). This decoupling is -** the most important feature of upb, because it allows parsers and serializers -** to be highly reusable. -** -** This is a mixed C/C++ interface that offers a full API to both languages. -** See the top-level README for more information. -*/ - -#ifndef UPB_HANDLERS_H -#define UPB_HANDLERS_H - - - -#ifdef __cplusplus -namespace upb { -class HandlersPtr; -class HandlerCache; -template class Handler; -template struct CanonicalType; -} /* namespace upb */ -#endif - - -/* The maximum depth that the handler graph can have. This is a resource limit - * for the C stack since we sometimes need to recursively traverse the graph. - * Cycles are ok; the traversal will stop when it detects a cycle, but we must - * hit the cycle before the maximum depth is reached. - * - * If having a single static limit is too inflexible, we can add another variant - * of Handlers::Freeze that allows specifying this as a parameter. */ -#define UPB_MAX_HANDLER_DEPTH 64 - -/* All the different types of handlers that can be registered. - * Only needed for the advanced functions in upb::Handlers. */ -typedef enum { - UPB_HANDLER_INT32, - UPB_HANDLER_INT64, - UPB_HANDLER_UINT32, - UPB_HANDLER_UINT64, - UPB_HANDLER_FLOAT, - UPB_HANDLER_DOUBLE, - UPB_HANDLER_BOOL, - UPB_HANDLER_STARTSTR, - UPB_HANDLER_STRING, - UPB_HANDLER_ENDSTR, - UPB_HANDLER_STARTSUBMSG, - UPB_HANDLER_ENDSUBMSG, - UPB_HANDLER_STARTSEQ, - UPB_HANDLER_ENDSEQ -} upb_handlertype_t; - -#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1) - -#define UPB_BREAK NULL - -/* A convenient definition for when no closure is needed. */ -extern char _upb_noclosure; -#define UPB_NO_CLOSURE &_upb_noclosure - -/* A selector refers to a specific field handler in the Handlers object - * (for example: the STARTSUBMSG handler for field "field15"). */ -typedef int32_t upb_selector_t; - -/* Static selectors for upb::Handlers. */ -#define UPB_STARTMSG_SELECTOR 0 -#define UPB_ENDMSG_SELECTOR 1 -#define UPB_UNKNOWN_SELECTOR 2 -#define UPB_STATIC_SELECTOR_COUNT 3 /* Warning: also in upb/def.c. */ - -/* Static selectors for upb::BytesHandler. */ -#define UPB_STARTSTR_SELECTOR 0 -#define UPB_STRING_SELECTOR 1 -#define UPB_ENDSTR_SELECTOR 2 - -#ifdef __cplusplus -template const void *UniquePtrForType() { - static const char ch = 0; - return &ch; -} -#endif - -/* upb_handlers ************************************************************/ - -/* Handler attributes, to be registered with the handler itself. */ -typedef struct { - const void *handler_data; - const void *closure_type; - const void *return_closure_type; - bool alwaysok; -} upb_handlerattr; - -#define UPB_HANDLERATTR_INIT {NULL, NULL, NULL, false} - -/* Bufhandle, data passed along with a buffer to indicate its provenance. */ -typedef struct { - /* The beginning of the buffer. This may be different than the pointer - * passed to a StringBuf handler because the handler may receive data - * that is from the middle or end of a larger buffer. */ - const char *buf; - - /* The offset within the attached object where this buffer begins. Only - * meaningful if there is an attached object. */ - size_t objofs; - - /* The attached object (if any) and a pointer representing its type. */ - const void *obj; - const void *objtype; - -#ifdef __cplusplus - template - void SetAttachedObject(const T* _obj) { - obj = _obj; - objtype = UniquePtrForType(); - } - - template - const T *GetAttachedObject() const { - return objtype == UniquePtrForType() ? static_cast(obj) - : NULL; - } -#endif -} upb_bufhandle; - -#define UPB_BUFHANDLE_INIT {NULL, 0, NULL, NULL} - -/* Handler function typedefs. */ -typedef void upb_handlerfree(void *d); -typedef bool upb_unknown_handlerfunc(void *c, const void *hd, const char *buf, - size_t n); -typedef bool upb_startmsg_handlerfunc(void *c, const void*); -typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status); -typedef void* upb_startfield_handlerfunc(void *c, const void *hd); -typedef bool upb_endfield_handlerfunc(void *c, const void *hd); -typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val); -typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val); -typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val); -typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val); -typedef bool upb_float_handlerfunc(void *c, const void *hd, float val); -typedef bool upb_double_handlerfunc(void *c, const void *hd, double val); -typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val); -typedef void *upb_startstr_handlerfunc(void *c, const void *hd, - size_t size_hint); -typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf, - size_t n, const upb_bufhandle* handle); - -struct upb_handlers; -typedef struct upb_handlers upb_handlers; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Mutating accessors. */ -const upb_status *upb_handlers_status(upb_handlers *h); -void upb_handlers_clearerr(upb_handlers *h); -const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h); -bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree); -bool upb_handlers_setunknown(upb_handlers *h, upb_unknown_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f, - upb_int32_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f, - upb_int64_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f, - upb_uint32_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f, - upb_uint64_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f, - upb_float_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f, - upb_double_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f, - upb_bool_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f, - upb_startstr_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f, - upb_string_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f, - upb_endfield_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f, - upb_startfield_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f, - upb_startfield_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f, - upb_endfield_handlerfunc *func, - const upb_handlerattr *attr); -bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f, - upb_endfield_handlerfunc *func, - const upb_handlerattr *attr); - -/* Read-only accessors. */ -const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, - const upb_fielddef *f); -const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, - upb_selector_t sel); -upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s, - const void **handler_data); -bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s, - upb_handlerattr *attr); - -/* "Static" methods */ -upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f); -bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, - upb_selector_t *s); -UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) { - return start + 1; -} - -#ifdef __cplusplus -} /* extern "C" */ - -namespace upb { -typedef upb_handlers Handlers; -} - -/* Convenience macros for creating a Handler object that is wrapped with a - * type-safe wrapper function that converts the "void*" parameters/returns - * of the underlying C API into nice C++ function. - * - * Sample usage: - * void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) { - * // do stuff ... - * } - * - * // Handler that doesn't need any data bound to it. - * void OnValue2(MyClosure* c, int32_t val) { - * // do stuff ... - * } - * - * // Handler that returns bool so it can return failure if necessary. - * bool OnValue3(MyClosure* c, int32_t val) { - * // do stuff ... - * return ok; - * } - * - * // Member function handler. - * class MyClosure { - * public: - * void OnValue(int32_t val) { - * // do stuff ... - * } - * }; - * - * // Takes ownership of the MyHandlerData. - * handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...))); - * handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2)); - * handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3)); - * handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue)); - */ - -/* In C++11, the "template" disambiguator can appear even outside templates, - * so all calls can safely use this pair of macros. */ - -#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc() - -/* We have to be careful to only evaluate "d" once. */ -#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc((d)) - -/* Handler: a struct that contains the (handler, data, deleter) tuple that is - * used to register all handlers. Users can Make() these directly but it's - * more convenient to use the UpbMakeHandler/UpbBind macros above. */ -template class upb::Handler { - public: - /* The underlying, handler function signature that upb uses internally. */ - typedef T FuncPtr; - - /* Intentionally implicit. */ - template Handler(F func); - ~Handler() { UPB_ASSERT(registered_); } - - void AddCleanup(upb_handlers* h) const; - FuncPtr handler() const { return handler_; } - const upb_handlerattr& attr() const { return attr_; } - - private: - Handler(const Handler&) = delete; - Handler& operator=(const Handler&) = delete; - - FuncPtr handler_; - mutable upb_handlerattr attr_; - mutable bool registered_; - void *cleanup_data_; - upb_handlerfree *cleanup_func_; -}; - -/* A upb::Handlers object represents the set of handlers associated with a - * message in the graph of messages. You can think of it as a big virtual - * table with functions corresponding to all the events that can fire while - * parsing or visiting a message of a specific type. - * - * Any handlers that are not set behave as if they had successfully consumed - * the value. Any unset Start* handlers will propagate their closure to the - * inner frame. - * - * The easiest way to create the *Handler objects needed by the Set* methods is - * with the UpbBind() and UpbMakeHandler() macros; see below. */ -class upb::HandlersPtr { - public: - HandlersPtr(upb_handlers* ptr) : ptr_(ptr) {} - - upb_handlers* ptr() const { return ptr_; } - - typedef upb_selector_t Selector; - typedef upb_handlertype_t Type; - - typedef Handler StartFieldHandler; - typedef Handler EndFieldHandler; - typedef Handler StartMessageHandler; - typedef Handler - EndMessageHandler; - typedef Handler StartStringHandler; - typedef Handler - StringHandler; - - template struct ValueHandler { - typedef Handler H; - }; - - typedef ValueHandler::H Int32Handler; - typedef ValueHandler::H Int64Handler; - typedef ValueHandler::H UInt32Handler; - typedef ValueHandler::H UInt64Handler; - typedef ValueHandler::H FloatHandler; - typedef ValueHandler::H DoubleHandler; - typedef ValueHandler::H BoolHandler; - - /* Any function pointer can be converted to this and converted back to its - * correct type. */ - typedef void GenericFunction(); - - typedef void HandlersCallback(const void *closure, upb_handlers *h); - - /* Returns the msgdef associated with this handlers object. */ - MessageDefPtr message_def() const { - return MessageDefPtr(upb_handlers_msgdef(ptr())); - } - - /* Adds the given pointer and function to the list of cleanup functions that - * will be run when these handlers are freed. If this pointer has previously - * been registered, the function returns false and does nothing. */ - bool AddCleanup(void *ptr, upb_handlerfree *cleanup) { - return upb_handlers_addcleanup(ptr_, ptr, cleanup); - } - - /* Sets the startmsg handler for the message, which is defined as follows: - * - * bool startmsg(MyType* closure) { - * // Called when the message begins. Returns true if processing should - * // continue. - * return true; - * } - */ - bool SetStartMessageHandler(const StartMessageHandler &h) { - h.AddCleanup(ptr()); - return upb_handlers_setstartmsg(ptr(), h.handler(), &h.attr()); - } - - /* Sets the endmsg handler for the message, which is defined as follows: - * - * bool endmsg(MyType* closure, upb_status *status) { - * // Called when processing of this message ends, whether in success or - * // failure. "status" indicates the final status of processing, and - * // can also be modified in-place to update the final status. - * } - */ - bool SetEndMessageHandler(const EndMessageHandler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setendmsg(ptr(), h.handler(), &h.attr()); - } - - /* Sets the value handler for the given field, which is defined as follows - * (this is for an int32 field; other field types will pass their native - * C/C++ type for "val"): - * - * bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) { - * // Called when the field's value is encountered. "d" contains - * // whatever data was bound to this field when it was registered. - * // Returns true if processing should continue. - * return true; - * } - * - * handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...))); - * - * The value type must exactly match f->type(). - * For example, a handler that takes an int32_t parameter may only be used for - * fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM. - * - * Returns false if the handler failed to register; in this case the cleanup - * handler (if any) will be called immediately. - */ - bool SetInt32Handler(FieldDefPtr f, const Int32Handler &h) { - h.AddCleanup(ptr()); - return upb_handlers_setint32(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetInt64Handler (FieldDefPtr f, const Int64Handler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setint64(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetUInt32Handler(FieldDefPtr f, const UInt32Handler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setuint32(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetUInt64Handler(FieldDefPtr f, const UInt64Handler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setuint64(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetFloatHandler (FieldDefPtr f, const FloatHandler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setfloat(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetDoubleHandler(FieldDefPtr f, const DoubleHandler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setdouble(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetBoolHandler(FieldDefPtr f, const BoolHandler &h) { - h.AddCleanup(ptr()); - return upb_handlers_setbool(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - /* Like the previous, but templated on the type on the value (ie. int32). - * This is mostly useful to call from other templates. To call this you must - * specify the template parameter explicitly, ie: - * h->SetValueHandler(f, UpbBind(MyHandler, MyData)); */ - template - bool SetValueHandler( - FieldDefPtr f, - const typename ValueHandler::Type>::H &handler); - - /* Sets handlers for a string field, which are defined as follows: - * - * MySubClosure* startstr(MyClosure* c, const MyHandlerData* d, - * size_t size_hint) { - * // Called when a string value begins. The return value indicates the - * // closure for the string. "size_hint" indicates the size of the - * // string if it is known, however if the string is length-delimited - * // and the end-of-string is not available size_hint will be zero. - * // This case is indistinguishable from the case where the size is - * // known to be zero. - * // - * // TODO(haberman): is it important to distinguish these cases? - * // If we had ssize_t as a type we could make -1 "unknown", but - * // ssize_t is POSIX (not ANSI) and therefore less portable. - * // In practice I suspect it won't be important to distinguish. - * return closure; - * } - * - * size_t str(MyClosure* closure, const MyHandlerData* d, - * const char *str, size_t len) { - * // Called for each buffer of string data; the multiple physical buffers - * // are all part of the same logical string. The return value indicates - * // how many bytes were consumed. If this number is less than "len", - * // this will also indicate that processing should be halted for now, - * // like returning false or UPB_BREAK from any other callback. If - * // number is greater than "len", the excess bytes will be skipped over - * // and not passed to the callback. - * return len; - * } - * - * bool endstr(MyClosure* c, const MyHandlerData* d) { - * // Called when a string value ends. Return value indicates whether - * // processing should continue. - * return true; - * } - */ - bool SetStartStringHandler(FieldDefPtr f, const StartStringHandler &h) { - h.AddCleanup(ptr()); - return upb_handlers_setstartstr(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetStringHandler(FieldDefPtr f, const StringHandler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setstring(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - bool SetEndStringHandler(FieldDefPtr f, const EndFieldHandler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setendstr(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - /* Sets the startseq handler, which is defined as follows: - * - * MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) { - * // Called when a sequence (repeated field) begins. The returned - * // pointer indicates the closure for the sequence (or UPB_BREAK - * // to interrupt processing). - * return closure; - * } - * - * h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...))); - * - * Returns "false" if "f" does not belong to this message or is not a - * repeated field. - */ - bool SetStartSequenceHandler(FieldDefPtr f, const StartFieldHandler &h) { - h.AddCleanup(ptr()); - return upb_handlers_setstartseq(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - /* Sets the startsubmsg handler for the given field, which is defined as - * follows: - * - * MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) { - * // Called when a submessage begins. The returned pointer indicates the - * // closure for the sequence (or UPB_BREAK to interrupt processing). - * return closure; - * } - * - * h->SetStartSubMessageHandler(f, UpbBind(startsubmsg, - * new MyHandlerData(...))); - * - * Returns "false" if "f" does not belong to this message or is not a - * submessage/group field. - */ - bool SetStartSubMessageHandler(FieldDefPtr f, const StartFieldHandler& h) { - h.AddCleanup(ptr()); - return upb_handlers_setstartsubmsg(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - /* Sets the endsubmsg handler for the given field, which is defined as - * follows: - * - * bool endsubmsg(MyClosure* c, const MyHandlerData* d) { - * // Called when a submessage ends. Returns true to continue processing. - * return true; - * } - * - * Returns "false" if "f" does not belong to this message or is not a - * submessage/group field. - */ - bool SetEndSubMessageHandler(FieldDefPtr f, const EndFieldHandler &h) { - h.AddCleanup(ptr()); - return upb_handlers_setendsubmsg(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - /* Starts the endsubseq handler for the given field, which is defined as - * follows: - * - * bool endseq(MyClosure* c, const MyHandlerData* d) { - * // Called when a sequence ends. Returns true continue processing. - * return true; - * } - * - * Returns "false" if "f" does not belong to this message or is not a - * repeated field. - */ - bool SetEndSequenceHandler(FieldDefPtr f, const EndFieldHandler &h) { - h.AddCleanup(ptr()); - return upb_handlers_setendseq(ptr(), f.ptr(), h.handler(), &h.attr()); - } - - private: - upb_handlers* ptr_; -}; - -#endif /* __cplusplus */ - -/* upb_handlercache ***********************************************************/ - -/* A upb_handlercache lazily builds and caches upb_handlers. You pass it a - * function (with optional closure) that can build handlers for a given - * message on-demand, and the cache maintains a map of msgdef->handlers. */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct upb_handlercache; -typedef struct upb_handlercache upb_handlercache; - -typedef void upb_handlers_callback(const void *closure, upb_handlers *h); - -upb_handlercache *upb_handlercache_new(upb_handlers_callback *callback, - const void *closure); -void upb_handlercache_free(upb_handlercache *cache); -const upb_handlers *upb_handlercache_get(upb_handlercache *cache, - const upb_msgdef *md); -bool upb_handlercache_addcleanup(upb_handlercache *h, void *p, - upb_handlerfree *hfree); - -#ifdef __cplusplus -} /* extern "C" */ - -class upb::HandlerCache { - public: - HandlerCache(upb_handlers_callback *callback, const void *closure) - : ptr_(upb_handlercache_new(callback, closure), upb_handlercache_free) {} - HandlerCache(HandlerCache&&) = default; - HandlerCache& operator=(HandlerCache&&) = default; - HandlerCache(upb_handlercache* c) : ptr_(c, upb_handlercache_free) {} - - upb_handlercache* ptr() { return ptr_.get(); } - - const upb_handlers *Get(MessageDefPtr md) { - return upb_handlercache_get(ptr_.get(), md.ptr()); - } - - private: - std::unique_ptr ptr_; -}; - -#endif /* __cplusplus */ - -/* upb_byteshandler ***********************************************************/ - -typedef struct { - upb_func *func; - - /* It is wasteful to include the entire attributes here: - * - * * Some of the information is redundant (like storing the closure type - * separately for each handler that must match). - * * Some of the info is only needed prior to freeze() (like closure types). - * * alignment padding wastes a lot of space for alwaysok_. - * - * If/when the size and locality of handlers is an issue, we can optimize this - * not to store the entire attr like this. We do not expose the table's - * layout to allow this optimization in the future. */ - upb_handlerattr attr; -} upb_handlers_tabent; - -#define UPB_TABENT_INIT {NULL, UPB_HANDLERATTR_INIT} - -typedef struct { - upb_handlers_tabent table[3]; -} upb_byteshandler; - -#define UPB_BYTESHANDLER_INIT \ - { \ - { UPB_TABENT_INIT, UPB_TABENT_INIT, UPB_TABENT_INIT } \ - } - -UPB_INLINE void upb_byteshandler_init(upb_byteshandler *handler) { - upb_byteshandler init = UPB_BYTESHANDLER_INIT; - *handler = init; -} - -#ifdef __cplusplus -extern "C" { -#endif - -/* Caller must ensure that "d" outlives the handlers. */ -bool upb_byteshandler_setstartstr(upb_byteshandler *h, - upb_startstr_handlerfunc *func, void *d); -bool upb_byteshandler_setstring(upb_byteshandler *h, - upb_string_handlerfunc *func, void *d); -bool upb_byteshandler_setendstr(upb_byteshandler *h, - upb_endfield_handlerfunc *func, void *d); - -#ifdef __cplusplus -} /* extern "C" */ - -namespace upb { -typedef upb_byteshandler BytesHandler; -} -#endif - -/** Message handlers ******************************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -/* These are the handlers used internally by upb_msgfactory_getmergehandlers(). - * They write scalar data to a known offset from the message pointer. - * - * These would be trivial for anyone to implement themselves, but it's better - * to use these because some JITs will recognize and specialize these instead - * of actually calling the function. */ - -/* Sets a handler for the given primitive field that will write the data at the - * given offset. If hasbit > 0, also sets a hasbit at the given bit offset - * (addressing each byte low to high). */ -bool upb_msg_setscalarhandler(upb_handlers *h, - const upb_fielddef *f, - size_t offset, - int32_t hasbit); - -/* If the given handler is a msghandlers_primitive field, returns true and sets - * *type, *offset and *hasbit. Otherwise returns false. */ -bool upb_msg_getscalarhandlerdata(const upb_handlers *h, - upb_selector_t s, - upb_fieldtype_t *type, - size_t *offset, - int32_t *hasbit); - - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -/* -** Inline definitions for handlers.h, which are particularly long and a bit -** tricky. -*/ - -#ifndef UPB_HANDLERS_INL_H_ -#define UPB_HANDLERS_INL_H_ - -#include -#include - - -#ifdef __cplusplus - -/* Type detection and typedefs for integer types. - * For platforms where there are multiple 32-bit or 64-bit types, we need to be - * able to enumerate them so we can properly create overloads for all variants. - * - * If any platform existed where there were three integer types with the same - * size, this would have to become more complicated. For example, short, int, - * and long could all be 32-bits. Even more diabolically, short, int, long, - * and long long could all be 64 bits and still be standard-compliant. - * However, few platforms are this strange, and it's unlikely that upb will be - * used on the strangest ones. */ - -/* Can't count on stdint.h limits like INT32_MAX, because in C++ these are - * only defined when __STDC_LIMIT_MACROS are defined before the *first* include - * of stdint.h. We can't guarantee that someone else didn't include these first - * without defining __STDC_LIMIT_MACROS. */ -#define UPB_INT32_MAX 0x7fffffffLL -#define UPB_INT32_MIN (-UPB_INT32_MAX - 1) -#define UPB_INT64_MAX 0x7fffffffffffffffLL -#define UPB_INT64_MIN (-UPB_INT64_MAX - 1) - -#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN -#define UPB_INT_IS_32BITS 1 -#endif - -#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN -#define UPB_LONG_IS_32BITS 1 -#endif - -#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN -#define UPB_LONG_IS_64BITS 1 -#endif - -#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN -#define UPB_LLONG_IS_64BITS 1 -#endif - -/* We use macros instead of typedefs so we can undefine them later and avoid - * leaking them outside this header file. */ -#if UPB_INT_IS_32BITS -#define UPB_INT32_T int -#define UPB_UINT32_T unsigned int - -#if UPB_LONG_IS_32BITS -#define UPB_TWO_32BIT_TYPES 1 -#define UPB_INT32ALT_T long -#define UPB_UINT32ALT_T unsigned long -#endif /* UPB_LONG_IS_32BITS */ - -#elif UPB_LONG_IS_32BITS /* && !UPB_INT_IS_32BITS */ -#define UPB_INT32_T long -#define UPB_UINT32_T unsigned long -#endif /* UPB_INT_IS_32BITS */ - - -#if UPB_LONG_IS_64BITS -#define UPB_INT64_T long -#define UPB_UINT64_T unsigned long - -#if UPB_LLONG_IS_64BITS -#define UPB_TWO_64BIT_TYPES 1 -#define UPB_INT64ALT_T long long -#define UPB_UINT64ALT_T unsigned long long -#endif /* UPB_LLONG_IS_64BITS */ - -#elif UPB_LLONG_IS_64BITS /* && !UPB_LONG_IS_64BITS */ -#define UPB_INT64_T long long -#define UPB_UINT64_T unsigned long long -#endif /* UPB_LONG_IS_64BITS */ - -#undef UPB_INT32_MAX -#undef UPB_INT32_MIN -#undef UPB_INT64_MAX -#undef UPB_INT64_MIN -#undef UPB_INT_IS_32BITS -#undef UPB_LONG_IS_32BITS -#undef UPB_LONG_IS_64BITS -#undef UPB_LLONG_IS_64BITS - - -namespace upb { - -typedef void CleanupFunc(void *ptr); - -/* Template to remove "const" from "const T*" and just return "T*". - * - * We define a nonsense default because otherwise it will fail to instantiate as - * a function parameter type even in cases where we don't expect any caller to - * actually match the overload. */ -class CouldntRemoveConst {}; -template struct remove_constptr { typedef CouldntRemoveConst type; }; -template struct remove_constptr { typedef T *type; }; - -/* Template that we use below to remove a template specialization from - * consideration if it matches a specific type. */ -template struct disable_if_same { typedef void Type; }; -template struct disable_if_same {}; - -template void DeletePointer(void *p) { delete static_cast(p); } - -template -struct FirstUnlessVoidOrBool { - typedef T1 value; -}; - -template -struct FirstUnlessVoidOrBool { - typedef T2 value; -}; - -template -struct FirstUnlessVoidOrBool { - typedef T2 value; -}; - -template -struct is_same { - static bool value; -}; - -template -struct is_same { - static bool value; -}; - -template -bool is_same::value = false; - -template -bool is_same::value = true; - -/* FuncInfo *******************************************************************/ - -/* Info about the user's original, pre-wrapped function. */ -template -struct FuncInfo { - /* The type of the closure that the function takes (its first param). */ - typedef C Closure; - - /* The return type. */ - typedef R Return; -}; - -/* Func ***********************************************************************/ - -/* Func1, Func2, Func3: Template classes representing a function and its - * signature. - * - * Since the function is a template parameter, calling the function can be - * inlined at compile-time and does not require a function pointer at runtime. - * These functions are not bound to a handler data so have no data or cleanup - * handler. */ -struct UnboundFunc { - CleanupFunc *GetCleanup() { return nullptr; } - void *GetData() { return nullptr; } -}; - -template -struct Func1 : public UnboundFunc { - typedef R Return; - typedef I FuncInfo; - static R Call(P1 p1) { return F(p1); } -}; - -template -struct Func2 : public UnboundFunc { - typedef R Return; - typedef I FuncInfo; - static R Call(P1 p1, P2 p2) { return F(p1, p2); } -}; - -template -struct Func3 : public UnboundFunc { - typedef R Return; - typedef I FuncInfo; - static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } -}; - -template -struct Func4 : public UnboundFunc { - typedef R Return; - typedef I FuncInfo; - static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); } -}; - -template -struct Func5 : public UnboundFunc { - typedef R Return; - typedef I FuncInfo; - static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { - return F(p1, p2, p3, p4, p5); - } -}; - -/* BoundFunc ******************************************************************/ - -/* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that - * shall be bound to the function's second parameter. - * - * Note that the second parameter is a const pointer, but our stored bound value - * is non-const so we can free it when the handlers are destroyed. */ -template -struct BoundFunc { - typedef typename remove_constptr::type MutableP2; - explicit BoundFunc(MutableP2 data_) : data(data_) {} - CleanupFunc *GetCleanup() { return &DeletePointer; } - MutableP2 GetData() { return data; } - MutableP2 data; -}; - -template -struct BoundFunc2 : public BoundFunc { - typedef BoundFunc Base; - typedef I FuncInfo; - explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} -}; - -template -struct BoundFunc3 : public BoundFunc { - typedef BoundFunc Base; - typedef I FuncInfo; - explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} -}; - -template -struct BoundFunc4 : public BoundFunc { - typedef BoundFunc Base; - typedef I FuncInfo; - explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} -}; - -template -struct BoundFunc5 : public BoundFunc { - typedef BoundFunc Base; - typedef I FuncInfo; - explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {} -}; - -/* FuncSig ********************************************************************/ - -/* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function - * *signature*, but without a specific function attached. - * - * These classes contain member functions that can be invoked with a - * specific function to return a Func/BoundFunc class. */ -template -struct FuncSig1 { - template - Func1 > GetFunc() { - return Func1 >(); - } -}; - -template -struct FuncSig2 { - template - Func2 > GetFunc() { - return Func2 >(); - } - - template - BoundFunc2 > GetFunc( - typename remove_constptr::type param2) { - return BoundFunc2 >(param2); - } -}; - -template -struct FuncSig3 { - template - Func3 > GetFunc() { - return Func3 >(); - } - - template - BoundFunc3 > GetFunc( - typename remove_constptr::type param2) { - return BoundFunc3 >(param2); - } -}; - -template -struct FuncSig4 { - template - Func4 > GetFunc() { - return Func4 >(); - } - - template - BoundFunc4 > GetFunc( - typename remove_constptr::type param2) { - return BoundFunc4 >(param2); - } -}; - -template -struct FuncSig5 { - template - Func5 > GetFunc() { - return Func5 >(); - } - - template - BoundFunc5 > GetFunc( - typename remove_constptr::type param2) { - return BoundFunc5 >(param2); - } -}; - -/* Overloaded template function that can construct the appropriate FuncSig* - * class given a function pointer by deducing the template parameters. */ -template -inline FuncSig1 MatchFunc(R (*f)(P1)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return FuncSig1(); -} - -template -inline FuncSig2 MatchFunc(R (*f)(P1, P2)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return FuncSig2(); -} - -template -inline FuncSig3 MatchFunc(R (*f)(P1, P2, P3)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return FuncSig3(); -} - -template -inline FuncSig4 MatchFunc(R (*f)(P1, P2, P3, P4)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return FuncSig4(); -} - -template -inline FuncSig5 MatchFunc(R (*f)(P1, P2, P3, P4, P5)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return FuncSig5(); -} - -/* MethodSig ******************************************************************/ - -/* CallMethod*: a function template that calls a given method. */ -template -R CallMethod0(C *obj) { - return ((*obj).*F)(); -} - -template -R CallMethod1(C *obj, P1 arg1) { - return ((*obj).*F)(arg1); -} - -template -R CallMethod2(C *obj, P1 arg1, P2 arg2) { - return ((*obj).*F)(arg1, arg2); -} - -template -R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { - return ((*obj).*F)(arg1, arg2, arg3); -} - -template -R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) { - return ((*obj).*F)(arg1, arg2, arg3, arg4); -} - -/* MethodSig: like FuncSig, but for member functions. - * - * GetFunc() returns a normal FuncN object, so after calling GetFunc() no - * more logic is required to special-case methods. */ -template -struct MethodSig0 { - template - Func1, FuncInfo > GetFunc() { - return Func1, FuncInfo >(); - } -}; - -template -struct MethodSig1 { - template - Func2, FuncInfo > GetFunc() { - return Func2, FuncInfo >(); - } - - template - BoundFunc2, FuncInfo > GetFunc( - typename remove_constptr::type param1) { - return BoundFunc2, FuncInfo >( - param1); - } -}; - -template -struct MethodSig2 { - template - Func3, FuncInfo > - GetFunc() { - return Func3, - FuncInfo >(); - } - - template - BoundFunc3, FuncInfo > - GetFunc(typename remove_constptr::type param1) { - return BoundFunc3, - FuncInfo >(param1); - } -}; - -template -struct MethodSig3 { - template - Func4, FuncInfo > - GetFunc() { - return Func4, - FuncInfo >(); - } - - template - BoundFunc4, - FuncInfo > - GetFunc(typename remove_constptr::type param1) { - return BoundFunc4, - FuncInfo >(param1); - } -}; - -template -struct MethodSig4 { - template - Func5, - FuncInfo > - GetFunc() { - return Func5, - FuncInfo >(); - } - - template - BoundFunc5, - FuncInfo > - GetFunc(typename remove_constptr::type param1) { - return BoundFunc5, FuncInfo >( - param1); - } -}; - -template -inline MethodSig0 MatchFunc(R (C::*f)()) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return MethodSig0(); -} - -template -inline MethodSig1 MatchFunc(R (C::*f)(P1)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return MethodSig1(); -} - -template -inline MethodSig2 MatchFunc(R (C::*f)(P1, P2)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return MethodSig2(); -} - -template -inline MethodSig3 MatchFunc(R (C::*f)(P1, P2, P3)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return MethodSig3(); -} - -template -inline MethodSig4 MatchFunc(R (C::*f)(P1, P2, P3, P4)) { - UPB_UNUSED(f); /* Only used for template parameter deduction. */ - return MethodSig4(); -} - -/* MaybeWrapReturn ************************************************************/ - -/* Template class that attempts to wrap the return value of the function so it - * matches the expected type. There are two main adjustments it may make: - * - * 1. If the function returns void, make it return the expected type and with - * a value that always indicates success. - * 2. If the function returns bool, make it return the expected type with a - * value that indicates success or failure. - * - * The "expected type" for return is: - * 1. void* for start handlers. If the closure parameter has a different type - * we will cast it to void* for the return in the success case. - * 2. size_t for string buffer handlers. - * 3. bool for everything else. */ - -/* Template parameters are FuncN type and desired return type. */ -template -struct MaybeWrapReturn; - -/* If the return type matches, return the given function unwrapped. */ -template -struct MaybeWrapReturn { - typedef F Func; -}; - -/* Function wrapper that munges the return value from void to (bool)true. */ -template -bool ReturnTrue2(P1 p1, P2 p2) { - F(p1, p2); - return true; -} - -template -bool ReturnTrue3(P1 p1, P2 p2, P3 p3) { - F(p1, p2, p3); - return true; -} - -/* Function wrapper that munges the return value from void to (void*)arg1 */ -template -void *ReturnClosure2(P1 p1, P2 p2) { - F(p1, p2); - return p1; -} - -template -void *ReturnClosure3(P1 p1, P2 p2, P3 p3) { - F(p1, p2, p3); - return p1; -} - -/* Function wrapper that munges the return value from R to void*. */ -template -void *CastReturnToVoidPtr2(P1 p1, P2 p2) { - return F(p1, p2); -} - -template -void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { - return F(p1, p2, p3); -} - -/* Function wrapper that munges the return value from bool to void*. */ -template -void *ReturnClosureOrBreak2(P1 p1, P2 p2) { - return F(p1, p2) ? p1 : UPB_BREAK; -} - -template -void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) { - return F(p1, p2, p3) ? p1 : UPB_BREAK; -} - -/* For the string callback, which takes five params, returns the size param. */ -template -size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4, - const upb_bufhandle *p5) { - F(p1, p2, p3, p4, p5); - return p4; -} - -/* For the string callback, which takes five params, returns the size param or - * zero. */ -template -size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4, - const upb_bufhandle *p5) { - return F(p1, p2, p3, p4, p5) ? p4 : 0; -} - -/* If we have a function returning void but want a function returning bool, wrap - * it in a function that returns true. */ -template -struct MaybeWrapReturn, bool> { - typedef Func2, I> Func; -}; - -template -struct MaybeWrapReturn, bool> { - typedef Func3, I> Func; -}; - -/* If our function returns void but we want one returning void*, wrap it in a - * function that returns the first argument. */ -template -struct MaybeWrapReturn, void *> { - typedef Func2, I> Func; -}; - -template -struct MaybeWrapReturn, void *> { - typedef Func3, I> Func; -}; - -/* If our function returns R* but we want one returning void*, wrap it in a - * function that casts to void*. */ -template -struct MaybeWrapReturn, void *, - typename disable_if_same::Type> { - typedef Func2, I> Func; -}; - -template -struct MaybeWrapReturn, void *, - typename disable_if_same::Type> { - typedef Func3, I> - Func; -}; - -/* If our function returns bool but we want one returning void*, wrap it in a - * function that returns either the first param or UPB_BREAK. */ -template -struct MaybeWrapReturn, void *> { - typedef Func2, I> Func; -}; - -template -struct MaybeWrapReturn, void *> { - typedef Func3, I> - Func; -}; - -/* If our function returns void but we want one returning size_t, wrap it in a - * function that returns the size argument. */ -template -struct MaybeWrapReturn< - Func5, - size_t> { - typedef Func5, I> Func; -}; - -/* If our function returns bool but we want one returning size_t, wrap it in a - * function that returns either 0 or the buf size. */ -template -struct MaybeWrapReturn< - Func5, - size_t> { - typedef Func5, I> Func; -}; - -/* ConvertParams **************************************************************/ - -/* Template class that converts the function parameters if necessary, and - * ignores the HandlerData parameter if appropriate. - * - * Template parameter is the are FuncN function type. */ -template -struct ConvertParams; - -/* Function that discards the handler data parameter. */ -template -R IgnoreHandlerData2(void *p1, const void *hd) { - UPB_UNUSED(hd); - return F(static_cast(p1)); -} - -template -R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) { - UPB_UNUSED(hd); - return F(static_cast(p1), p2); -} - -template -R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { - UPB_UNUSED(hd); - return F(static_cast(p1), p2, p3); -} - -template -R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) { - UPB_UNUSED(hd); - return F(static_cast(p1), p2, p3, p4); -} - -template -R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2, - size_t p3, const upb_bufhandle *handle) { - UPB_UNUSED(hd); - UPB_UNUSED(handle); - return F(static_cast(p1), p2, p3); -} - -/* Function that casts the handler data parameter. */ -template -R CastHandlerData2(void *c, const void *hd) { - return F(static_cast(c), static_cast(hd)); -} - -template -R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { - return F(static_cast(c), static_cast(hd), p3); -} - -template -R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) { - return F(static_cast(c), static_cast(hd), p3, p4, p5); -} - -template -R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3, - size_t p4, const upb_bufhandle *handle) { - UPB_UNUSED(handle); - return F(static_cast(c), static_cast(hd), p3, p4); -} - -/* For unbound functions, ignore the handler data. */ -template -struct ConvertParams, T> { - typedef Func2, I> Func; -}; - -template -struct ConvertParams, - R2 (*)(P1_2, P2_2, P3_2)> { - typedef Func3, I> Func; -}; - -/* For StringBuffer only; this ignores both the handler data and the - * upb_bufhandle. */ -template -struct ConvertParams, T> { - typedef Func5, - I> Func; -}; - -template -struct ConvertParams, T> { - typedef Func5, I> Func; -}; - -/* For bound functions, cast the handler data. */ -template -struct ConvertParams, T> { - typedef Func2, I> - Func; -}; - -template -struct ConvertParams, - R2 (*)(P1_2, P2_2, P3_2)> { - typedef Func3, I> Func; -}; - -/* For StringBuffer only; this ignores the upb_bufhandle. */ -template -struct ConvertParams, T> { - typedef Func5, I> - Func; -}; - -template -struct ConvertParams, T> { - typedef Func5, I> Func; -}; - -/* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is - * variant C type. */ -#define TYPE_METHODS(utype, ltype, ctype, vtype) \ - template <> \ - struct CanonicalType { \ - typedef ctype Type; \ - }; \ - template <> \ - inline bool HandlersPtr::SetValueHandler( \ - FieldDefPtr f, const HandlersPtr::utype##Handler &handler) { \ - handler.AddCleanup(ptr()); \ - return upb_handlers_set##ltype(ptr(), f.ptr(), handler.handler(), \ - &handler.attr()); \ - } - -TYPE_METHODS(Double, double, double, double) -TYPE_METHODS(Float, float, float, float) -TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T) -TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T) -TYPE_METHODS(Int64, int64, int64_t, UPB_INT64_T) -TYPE_METHODS(Int32, int32, int32_t, UPB_INT32_T) -TYPE_METHODS(Bool, bool, bool, bool) - -#ifdef UPB_TWO_32BIT_TYPES -TYPE_METHODS(Int32, int32, int32_t, UPB_INT32ALT_T) -TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T) -#endif - -#ifdef UPB_TWO_64BIT_TYPES -TYPE_METHODS(Int64, int64, int64_t, UPB_INT64ALT_T) -TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T) -#endif -#undef TYPE_METHODS - -template <> struct CanonicalType { - typedef Status* Type; -}; - -template struct ReturnOf; - -template -struct ReturnOf { - typedef R Return; -}; - -template -struct ReturnOf { - typedef R Return; -}; - -template -struct ReturnOf { - typedef R Return; -}; - -template -struct ReturnOf { - typedef R Return; -}; - - -template -template -inline Handler::Handler(F func) - : registered_(false), - cleanup_data_(func.GetData()), - cleanup_func_(func.GetCleanup()) { - attr_.handler_data = func.GetData(); - typedef typename ReturnOf::Return Return; - typedef typename ConvertParams::Func ConvertedParamsFunc; - typedef typename MaybeWrapReturn::Func - ReturnWrappedFunc; - handler_ = ReturnWrappedFunc().Call; - - /* Set attributes based on what templates can statically tell us about the - * user's function. */ - - /* If the original function returns void, then we know that we wrapped it to - * always return ok. */ - bool always_ok = is_same::value; - attr_.alwaysok = always_ok; - - /* Closure parameter and return type. */ - attr_.closure_type = UniquePtrForType(); - - /* We use the closure type (from the first parameter) if the return type is - * void or bool, since these are the two cases we wrap to return the closure's - * type anyway. - * - * This is all nonsense for non START* handlers, but it doesn't matter because - * in that case the value will be ignored. */ - typedef typename FirstUnlessVoidOrBool::value - EffectiveReturn; - attr_.return_closure_type = UniquePtrForType(); -} - -template -inline void Handler::AddCleanup(upb_handlers* h) const { - UPB_ASSERT(!registered_); - registered_ = true; - if (cleanup_func_) { - bool ok = upb_handlers_addcleanup(h, cleanup_data_, cleanup_func_); - UPB_ASSERT(ok); - } -} - -} /* namespace upb */ - -#endif /* __cplusplus */ - - -#undef UPB_TWO_32BIT_TYPES -#undef UPB_TWO_64BIT_TYPES -#undef UPB_INT32_T -#undef UPB_UINT32_T -#undef UPB_INT32ALT_T -#undef UPB_UINT32ALT_T -#undef UPB_INT64_T -#undef UPB_UINT64_T -#undef UPB_INT64ALT_T -#undef UPB_UINT64ALT_T - - -#endif /* UPB_HANDLERS_INL_H_ */ - -#endif /* UPB_HANDLERS_H */ -/* -** upb::Sink (upb_sink) -** upb::BytesSink (upb_bytessink) -** -** A upb_sink is an object that binds a upb_handlers object to some runtime -** state. It is the object that can actually receive data via the upb_handlers -** interface. -** -** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or -** thread-safe. You can create as many of them as you want, but each one may -** only be used in a single thread at a time. -** -** If we compare with class-based OOP, a you can think of a upb_def as an -** abstract base class, a upb_handlers as a concrete derived class, and a -** upb_sink as an object (class instance). -*/ - -#ifndef UPB_SINK_H -#define UPB_SINK_H - - - -#ifdef __cplusplus -namespace upb { -class BytesSink; -class Sink; -} -#endif - -/* upb_sink *******************************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - const upb_handlers *handlers; - void *closure; -} upb_sink; - -#define PUTVAL(type, ctype) \ - UPB_INLINE bool upb_sink_put##type(upb_sink s, upb_selector_t sel, \ - ctype val) { \ - typedef upb_##type##_handlerfunc functype; \ - functype *func; \ - const void *hd; \ - if (!s.handlers) return true; \ - func = (functype *)upb_handlers_gethandler(s.handlers, sel, &hd); \ - if (!func) return true; \ - return func(s.closure, hd, val); \ - } - -PUTVAL(int32, int32_t) -PUTVAL(int64, int64_t) -PUTVAL(uint32, uint32_t) -PUTVAL(uint64, uint64_t) -PUTVAL(float, float) -PUTVAL(double, double) -PUTVAL(bool, bool) -#undef PUTVAL - -UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) { - s->handlers = h; - s->closure = c; -} - -UPB_INLINE size_t upb_sink_putstring(upb_sink s, upb_selector_t sel, - const char *buf, size_t n, - const upb_bufhandle *handle) { - typedef upb_string_handlerfunc func; - func *handler; - const void *hd; - if (!s.handlers) return n; - handler = (func *)upb_handlers_gethandler(s.handlers, sel, &hd); - - if (!handler) return n; - return handler(s.closure, hd, buf, n, handle); -} - -UPB_INLINE bool upb_sink_putunknown(upb_sink s, const char *buf, size_t n) { - typedef upb_unknown_handlerfunc func; - func *handler; - const void *hd; - if (!s.handlers) return true; - handler = - (func *)upb_handlers_gethandler(s.handlers, UPB_UNKNOWN_SELECTOR, &hd); - - if (!handler) return n; - return handler(s.closure, hd, buf, n); -} - -UPB_INLINE bool upb_sink_startmsg(upb_sink s) { - typedef upb_startmsg_handlerfunc func; - func *startmsg; - const void *hd; - if (!s.handlers) return true; - startmsg = - (func *)upb_handlers_gethandler(s.handlers, UPB_STARTMSG_SELECTOR, &hd); - - if (!startmsg) return true; - return startmsg(s.closure, hd); -} - -UPB_INLINE bool upb_sink_endmsg(upb_sink s, upb_status *status) { - typedef upb_endmsg_handlerfunc func; - func *endmsg; - const void *hd; - if (!s.handlers) return true; - endmsg = - (func *)upb_handlers_gethandler(s.handlers, UPB_ENDMSG_SELECTOR, &hd); - - if (!endmsg) return true; - return endmsg(s.closure, hd, status); -} - -UPB_INLINE bool upb_sink_startseq(upb_sink s, upb_selector_t sel, - upb_sink *sub) { - typedef upb_startfield_handlerfunc func; - func *startseq; - const void *hd; - sub->closure = s.closure; - sub->handlers = s.handlers; - if (!s.handlers) return true; - startseq = (func*)upb_handlers_gethandler(s.handlers, sel, &hd); - - if (!startseq) return true; - sub->closure = startseq(s.closure, hd); - return sub->closure ? true : false; -} - -UPB_INLINE bool upb_sink_endseq(upb_sink s, upb_selector_t sel) { - typedef upb_endfield_handlerfunc func; - func *endseq; - const void *hd; - if (!s.handlers) return true; - endseq = (func*)upb_handlers_gethandler(s.handlers, sel, &hd); - - if (!endseq) return true; - return endseq(s.closure, hd); -} - -UPB_INLINE bool upb_sink_startstr(upb_sink s, upb_selector_t sel, - size_t size_hint, upb_sink *sub) { - typedef upb_startstr_handlerfunc func; - func *startstr; - const void *hd; - sub->closure = s.closure; - sub->handlers = s.handlers; - if (!s.handlers) return true; - startstr = (func*)upb_handlers_gethandler(s.handlers, sel, &hd); - - if (!startstr) return true; - sub->closure = startstr(s.closure, hd, size_hint); - return sub->closure ? true : false; -} - -UPB_INLINE bool upb_sink_endstr(upb_sink s, upb_selector_t sel) { - typedef upb_endfield_handlerfunc func; - func *endstr; - const void *hd; - if (!s.handlers) return true; - endstr = (func*)upb_handlers_gethandler(s.handlers, sel, &hd); - - if (!endstr) return true; - return endstr(s.closure, hd); -} - -UPB_INLINE bool upb_sink_startsubmsg(upb_sink s, upb_selector_t sel, - upb_sink *sub) { - typedef upb_startfield_handlerfunc func; - func *startsubmsg; - const void *hd; - sub->closure = s.closure; - if (!s.handlers) { - sub->handlers = NULL; - return true; - } - sub->handlers = upb_handlers_getsubhandlers_sel(s.handlers, sel); - startsubmsg = (func*)upb_handlers_gethandler(s.handlers, sel, &hd); - - if (!startsubmsg) return true; - sub->closure = startsubmsg(s.closure, hd); - return sub->closure ? true : false; -} - -UPB_INLINE bool upb_sink_endsubmsg(upb_sink s, upb_sink sub, - upb_selector_t sel) { - typedef upb_endfield_handlerfunc func; - func *endsubmsg; - const void *hd; - if (!s.handlers) return true; - endsubmsg = (func*)upb_handlers_gethandler(s.handlers, sel, &hd); - - if (!endsubmsg) return true; - return endsubmsg(sub.closure, hd); -} - -#ifdef __cplusplus -} /* extern "C" */ - -/* A upb::Sink is an object that binds a upb::Handlers object to some runtime - * state. It represents an endpoint to which data can be sent. - * - * TODO(haberman): right now all of these functions take selectors. Should they - * take selectorbase instead? - * - * ie. instead of calling: - * sink->StartString(FOO_FIELD_START_STRING, ...) - * a selector base would let you say: - * sink->StartString(FOO_FIELD, ...) - * - * This would make call sites a little nicer and require emitting fewer selector - * definitions in .h files. - * - * But the current scheme has the benefit that you can retrieve a function - * pointer for any handler with handlers->GetHandler(selector), without having - * to have a separate GetHandler() function for each handler type. The JIT - * compiler uses this. To accommodate we'd have to expose a separate - * GetHandler() for every handler type. - * - * Also to ponder: selectors right now are independent of a specific Handlers - * instance. In other words, they allocate a number to every possible handler - * that *could* be registered, without knowing anything about what handlers - * *are* registered. That means that using selectors as table offsets prohibits - * us from compacting the handler table at Freeze() time. If the table is very - * sparse, this could be wasteful. - * - * Having another selector-like thing that is specific to a Handlers instance - * would allow this compacting, but then it would be impossible to write code - * ahead-of-time that can be bound to any Handlers instance at runtime. For - * example, a .proto file parser written as straight C will not know what - * Handlers it will be bound to, so when it calls sink->StartString() what - * selector will it pass? It needs a selector like we have today, that is - * independent of any particular upb::Handlers. - * - * Is there a way then to allow Handlers table compaction? */ -class upb::Sink { - public: - /* Constructor with no initialization; must be Reset() before use. */ - Sink() {} - - Sink(const Sink&) = default; - Sink& operator=(const Sink&) = default; - - Sink(const upb_sink& sink) : sink_(sink) {} - Sink &operator=(const upb_sink &sink) { - sink_ = sink; - return *this; - } - - upb_sink sink() { return sink_; } - - /* Constructs a new sink for the given frozen handlers and closure. - * - * TODO: once the Handlers know the expected closure type, verify that T - * matches it. */ - template Sink(const upb_handlers* handlers, T* closure) { - Reset(handlers, closure); - } - - upb_sink* ptr() { return &sink_; } - - /* Resets the value of the sink. */ - template void Reset(const upb_handlers* handlers, T* closure) { - upb_sink_reset(&sink_, handlers, closure); - } - - /* Returns the top-level object that is bound to this sink. - * - * TODO: once the Handlers know the expected closure type, verify that T - * matches it. */ - template T* GetObject() const { - return static_cast(sink_.closure); - } - - /* Functions for pushing data into the sink. - * - * These return false if processing should stop (either due to error or just - * to suspend). - * - * These may not be called from within one of the same sink's handlers (in - * other words, handlers are not re-entrant). */ - - /* Should be called at the start and end of every message; both the top-level - * message and submessages. This means that submessages should use the - * following sequence: - * sink->StartSubMessage(startsubmsg_selector); - * sink->StartMessage(); - * // ... - * sink->EndMessage(&status); - * sink->EndSubMessage(endsubmsg_selector); */ - bool StartMessage() { return upb_sink_startmsg(sink_); } - bool EndMessage(upb_status *status) { - return upb_sink_endmsg(sink_, status); - } - - /* Putting of individual values. These work for both repeated and - * non-repeated fields, but for repeated fields you must wrap them in - * calls to StartSequence()/EndSequence(). */ - bool PutInt32(HandlersPtr::Selector s, int32_t val) { - return upb_sink_putint32(sink_, s, val); - } - - bool PutInt64(HandlersPtr::Selector s, int64_t val) { - return upb_sink_putint64(sink_, s, val); - } - - bool PutUInt32(HandlersPtr::Selector s, uint32_t val) { - return upb_sink_putuint32(sink_, s, val); - } - - bool PutUInt64(HandlersPtr::Selector s, uint64_t val) { - return upb_sink_putuint64(sink_, s, val); - } - - bool PutFloat(HandlersPtr::Selector s, float val) { - return upb_sink_putfloat(sink_, s, val); - } - - bool PutDouble(HandlersPtr::Selector s, double val) { - return upb_sink_putdouble(sink_, s, val); - } - - bool PutBool(HandlersPtr::Selector s, bool val) { - return upb_sink_putbool(sink_, s, val); - } - - /* Putting of string/bytes values. Each string can consist of zero or more - * non-contiguous buffers of data. - * - * For StartString(), the function will write a sink for the string to "sub." - * The sub-sink must be used for any/all PutStringBuffer() calls. */ - bool StartString(HandlersPtr::Selector s, size_t size_hint, Sink* sub) { - upb_sink sub_c; - bool ret = upb_sink_startstr(sink_, s, size_hint, &sub_c); - *sub = sub_c; - return ret; - } - - size_t PutStringBuffer(HandlersPtr::Selector s, const char *buf, size_t len, - const upb_bufhandle *handle) { - return upb_sink_putstring(sink_, s, buf, len, handle); - } - - bool EndString(HandlersPtr::Selector s) { - return upb_sink_endstr(sink_, s); - } - - /* For submessage fields. - * - * For StartSubMessage(), the function will write a sink for the string to - * "sub." The sub-sink must be used for any/all handlers called within the - * submessage. */ - bool StartSubMessage(HandlersPtr::Selector s, Sink* sub) { - upb_sink sub_c; - bool ret = upb_sink_startsubmsg(sink_, s, &sub_c); - *sub = sub_c; - return ret; - } - - bool EndSubMessage(HandlersPtr::Selector s, Sink sub) { - return upb_sink_endsubmsg(sink_, sub.sink_, s); - } - - /* For repeated fields of any type, the sequence of values must be wrapped in - * these calls. - * - * For StartSequence(), the function will write a sink for the string to - * "sub." The sub-sink must be used for any/all handlers called within the - * sequence. */ - bool StartSequence(HandlersPtr::Selector s, Sink* sub) { - upb_sink sub_c; - bool ret = upb_sink_startseq(sink_, s, &sub_c); - *sub = sub_c; - return ret; - } - - bool EndSequence(HandlersPtr::Selector s) { - return upb_sink_endseq(sink_, s); - } - - /* Copy and assign specifically allowed. - * We don't even bother making these members private because so many - * functions need them and this is mainly just a dumb data container anyway. - */ - - private: - upb_sink sink_; -}; - -#endif /* __cplusplus */ - -/* upb_bytessink **************************************************************/ - -typedef struct { - const upb_byteshandler *handler; - void *closure; -} upb_bytessink ; - -UPB_INLINE void upb_bytessink_reset(upb_bytessink* s, const upb_byteshandler *h, - void *closure) { - s->handler = h; - s->closure = closure; -} - -UPB_INLINE bool upb_bytessink_start(upb_bytessink s, size_t size_hint, - void **subc) { - typedef upb_startstr_handlerfunc func; - func *start; - *subc = s.closure; - if (!s.handler) return true; - start = (func *)s.handler->table[UPB_STARTSTR_SELECTOR].func; - - if (!start) return true; - *subc = start(s.closure, - s.handler->table[UPB_STARTSTR_SELECTOR].attr.handler_data, - size_hint); - return *subc != NULL; -} - -UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink s, void *subc, - const char *buf, size_t size, - const upb_bufhandle* handle) { - typedef upb_string_handlerfunc func; - func *putbuf; - if (!s.handler) return true; - putbuf = (func *)s.handler->table[UPB_STRING_SELECTOR].func; - - if (!putbuf) return true; - return putbuf(subc, s.handler->table[UPB_STRING_SELECTOR].attr.handler_data, - buf, size, handle); -} - -UPB_INLINE bool upb_bytessink_end(upb_bytessink s) { - typedef upb_endfield_handlerfunc func; - func *end; - if (!s.handler) return true; - end = (func *)s.handler->table[UPB_ENDSTR_SELECTOR].func; - - if (!end) return true; - return end(s.closure, - s.handler->table[UPB_ENDSTR_SELECTOR].attr.handler_data); -} - -#ifdef __cplusplus - -class upb::BytesSink { - public: - BytesSink() {} - - BytesSink(const BytesSink&) = default; - BytesSink& operator=(const BytesSink&) = default; - - BytesSink(const upb_bytessink& sink) : sink_(sink) {} - BytesSink &operator=(const upb_bytessink &sink) { - sink_ = sink; - return *this; - } - - upb_bytessink sink() { return sink_; } - - /* Constructs a new sink for the given frozen handlers and closure. - * - * TODO(haberman): once the Handlers know the expected closure type, verify - * that T matches it. */ - template BytesSink(const upb_byteshandler* handler, T* closure) { - upb_bytessink_reset(sink_, handler, closure); - } - - /* Resets the value of the sink. */ - template void Reset(const upb_byteshandler* handler, T* closure) { - upb_bytessink_reset(&sink_, handler, closure); - } - - bool Start(size_t size_hint, void **subc) { - return upb_bytessink_start(sink_, size_hint, subc); - } - - size_t PutBuffer(void *subc, const char *buf, size_t len, - const upb_bufhandle *handle) { - return upb_bytessink_putbuf(sink_, subc, buf, len, handle); - } - - bool End() { - return upb_bytessink_end(sink_); - } - - private: - upb_bytessink sink_; -}; - -#endif /* __cplusplus */ - -/* upb_bufsrc *****************************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink sink); - -#ifdef __cplusplus -} /* extern "C" */ - -namespace upb { -template bool PutBuffer(const T& str, BytesSink sink) { - return upb_bufsrc_putbuf(str.data(), str.size(), sink.sink()); -} -} - -#endif /* __cplusplus */ - - -#endif -/* -** Internal-only definitions for the decoder. -*/ - -#ifndef UPB_DECODER_INT_H_ -#define UPB_DECODER_INT_H_ - -/* -** upb::pb::Decoder -** -** A high performance, streaming, resumable decoder for the binary protobuf -** format. -** -** This interface works the same regardless of what decoder backend is being -** used. A client of this class does not need to know whether decoding is using -** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder. By default, -** it will always use the fastest available decoder. However, you can call -** set_allow_jit(false) to disable any JIT decoder that might be available. -** This is primarily useful for testing purposes. -*/ - -#ifndef UPB_DECODER_H_ -#define UPB_DECODER_H_ - - -#ifdef __cplusplus -namespace upb { -namespace pb { -class CodeCache; -class DecoderPtr; -class DecoderMethodPtr; -class DecoderMethodOptions; -} /* namespace pb */ -} /* namespace upb */ -#endif - -/* The maximum number of bytes we are required to buffer internally between - * calls to the decoder. The value is 14: a 5 byte unknown tag plus ten-byte - * varint, less one because we are buffering an incomplete value. - * - * Should only be used by unit tests. */ -#define UPB_DECODER_MAX_RESIDUAL_BYTES 14 - -/* upb_pbdecodermethod ********************************************************/ - -struct upb_pbdecodermethod; -typedef struct upb_pbdecodermethod upb_pbdecodermethod; - -#ifdef __cplusplus -extern "C" { -#endif - -const upb_handlers *upb_pbdecodermethod_desthandlers( - const upb_pbdecodermethod *m); -const upb_byteshandler *upb_pbdecodermethod_inputhandler( - const upb_pbdecodermethod *m); -bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m); - -#ifdef __cplusplus -} /* extern "C" */ - -/* Represents the code to parse a protobuf according to a destination - * Handlers. */ -class upb::pb::DecoderMethodPtr { - public: - DecoderMethodPtr() : ptr_(nullptr) {} - DecoderMethodPtr(const upb_pbdecodermethod* ptr) : ptr_(ptr) {} - - const upb_pbdecodermethod* ptr() { return ptr_; } - - /* The destination handlers that are statically bound to this method. - * This method is only capable of outputting to a sink that uses these - * handlers. */ - const Handlers *dest_handlers() const { - return upb_pbdecodermethod_desthandlers(ptr_); - } - - /* The input handlers for this decoder method. */ - const BytesHandler* input_handler() const { - return upb_pbdecodermethod_inputhandler(ptr_); - } - - /* Whether this method is native. */ - bool is_native() const { - return upb_pbdecodermethod_isnative(ptr_); - } - - private: - const upb_pbdecodermethod* ptr_; -}; - -#endif - -/* upb_pbdecoder **************************************************************/ - -/* Preallocation hint: decoder won't allocate more bytes than this when first - * constructed. This hint may be an overestimate for some build configurations. - * But if the decoder library is upgraded without recompiling the application, - * it may be an underestimate. */ -#define UPB_PB_DECODER_SIZE 4416 - -struct upb_pbdecoder; -typedef struct upb_pbdecoder upb_pbdecoder; - -#ifdef __cplusplus -extern "C" { -#endif - -upb_pbdecoder *upb_pbdecoder_create(upb_arena *arena, - const upb_pbdecodermethod *method, - upb_sink output, upb_status *status); -const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d); -upb_bytessink upb_pbdecoder_input(upb_pbdecoder *d); -uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d); -size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d); -bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max); -void upb_pbdecoder_reset(upb_pbdecoder *d); - -#ifdef __cplusplus -} /* extern "C" */ - -/* A Decoder receives binary protobuf data on its input sink and pushes the - * decoded data to its output sink. */ -class upb::pb::DecoderPtr { - public: - DecoderPtr() : ptr_(nullptr) {} - DecoderPtr(upb_pbdecoder* ptr) : ptr_(ptr) {} - - upb_pbdecoder* ptr() { return ptr_; } - - /* Constructs a decoder instance for the given method, which must outlive this - * decoder. Any errors during parsing will be set on the given status, which - * must also outlive this decoder. - * - * The sink must match the given method. */ - static DecoderPtr Create(Arena *arena, DecoderMethodPtr method, - upb::Sink output, Status *status) { - return DecoderPtr(upb_pbdecoder_create(arena->ptr(), method.ptr(), - output.sink(), status->ptr())); - } - - /* Returns the DecoderMethod this decoder is parsing from. */ - const DecoderMethodPtr method() const { - return DecoderMethodPtr(upb_pbdecoder_method(ptr_)); - } - - /* The sink on which this decoder receives input. */ - BytesSink input() { return BytesSink(upb_pbdecoder_input(ptr())); } - - /* Returns number of bytes successfully parsed. - * - * This can be useful for determining the stream position where an error - * occurred. - * - * This value may not be up-to-date when called from inside a parsing - * callback. */ - uint64_t BytesParsed() { return upb_pbdecoder_bytesparsed(ptr()); } - - /* Gets/sets the parsing nexting limit. If the total number of nested - * submessages and repeated fields hits this limit, parsing will fail. This - * is a resource limit that controls the amount of memory used by the parsing - * stack. - * - * Setting the limit will fail if the parser is currently suspended at a depth - * greater than this, or if memory allocation of the stack fails. */ - size_t max_nesting() { return upb_pbdecoder_maxnesting(ptr()); } - bool set_max_nesting(size_t max) { return upb_pbdecoder_maxnesting(ptr()); } - - void Reset() { upb_pbdecoder_reset(ptr()); } - - static const size_t kSize = UPB_PB_DECODER_SIZE; - - private: - upb_pbdecoder *ptr_; -}; - -#endif /* __cplusplus */ - -/* upb_pbcodecache ************************************************************/ - -/* Lazily builds and caches decoder methods that will push data to the given - * handlers. The destination handlercache must outlive this object. */ - -struct upb_pbcodecache; -typedef struct upb_pbcodecache upb_pbcodecache; - -#ifdef __cplusplus -extern "C" { -#endif - -upb_pbcodecache *upb_pbcodecache_new(upb_handlercache *dest); -void upb_pbcodecache_free(upb_pbcodecache *c); -bool upb_pbcodecache_allowjit(const upb_pbcodecache *c); -void upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow); -void upb_pbcodecache_setlazy(upb_pbcodecache *c, bool lazy); -const upb_pbdecodermethod *upb_pbcodecache_get(upb_pbcodecache *c, - const upb_msgdef *md); - -#ifdef __cplusplus -} /* extern "C" */ - -/* A class for caching protobuf processing code, whether bytecode for the - * interpreted decoder or machine code for the JIT. - * - * This class is not thread-safe. */ -class upb::pb::CodeCache { - public: - CodeCache(upb::HandlerCache *dest) - : ptr_(upb_pbcodecache_new(dest->ptr()), upb_pbcodecache_free) {} - CodeCache(CodeCache&&) = default; - CodeCache& operator=(CodeCache&&) = default; - - upb_pbcodecache* ptr() { return ptr_.get(); } - const upb_pbcodecache* ptr() const { return ptr_.get(); } - - /* Whether the cache is allowed to generate machine code. Defaults to true. - * There is no real reason to turn it off except for testing or if you are - * having a specific problem with the JIT. - * - * Note that allow_jit = true does not *guarantee* that the code will be JIT - * compiled. If this platform is not supported or the JIT was not compiled - * in, the code may still be interpreted. */ - bool allow_jit() const { return upb_pbcodecache_allowjit(ptr()); } - - /* This may only be called when the object is first constructed, and prior to - * any code generation. */ - void set_allow_jit(bool allow) { upb_pbcodecache_setallowjit(ptr(), allow); } - - /* Should the decoder push submessages to lazy handlers for fields that have - * them? The caller should set this iff the lazy handlers expect data that is - * in protobuf binary format and the caller wishes to lazy parse it. */ - void set_lazy(bool lazy) { upb_pbcodecache_setlazy(ptr(), lazy); } - - /* Returns a DecoderMethod that can push data to the given handlers. - * If a suitable method already exists, it will be returned from the cache. */ - const DecoderMethodPtr Get(MessageDefPtr md) { - return DecoderMethodPtr(upb_pbcodecache_get(ptr(), md.ptr())); - } - - private: - std::unique_ptr ptr_; -}; - -#endif /* __cplusplus */ - -#endif /* UPB_DECODER_H_ */ - - -/* Opcode definitions. The canonical meaning of each opcode is its - * implementation in the interpreter (the JIT is written to match this). - * - * All instructions have the opcode in the low byte. - * Instruction format for most instructions is: - * - * +-------------------+--------+ - * | arg (24) | op (8) | - * +-------------------+--------+ - * - * Exceptions are indicated below. A few opcodes are multi-word. */ -typedef enum { - /* Opcodes 1-8, 13, 15-18 parse their respective descriptor types. - * Arg for all of these is the upb selector for this field. */ -#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type - T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32), - T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64), -#undef T - OP_STARTMSG = 9, /* No arg. */ - OP_ENDMSG = 10, /* No arg. */ - OP_STARTSEQ = 11, - OP_ENDSEQ = 12, - OP_STARTSUBMSG = 14, - OP_ENDSUBMSG = 19, - OP_STARTSTR = 20, - OP_STRING = 21, - OP_ENDSTR = 22, - - OP_PUSHTAGDELIM = 23, /* No arg. */ - OP_PUSHLENDELIM = 24, /* No arg. */ - OP_POP = 25, /* No arg. */ - OP_SETDELIM = 26, /* No arg. */ - OP_SETBIGGROUPNUM = 27, /* two words: - * | unused (24) | opc (8) | - * | groupnum (32) | */ - OP_CHECKDELIM = 28, - OP_CALL = 29, - OP_RET = 30, - OP_BRANCH = 31, - - /* Different opcodes depending on how many bytes expected. */ - OP_TAG1 = 32, /* | match tag (16) | jump target (8) | opc (8) | */ - OP_TAG2 = 33, /* | match tag (16) | jump target (8) | opc (8) | */ - OP_TAGN = 34, /* three words: */ - /* | unused (16) | jump target(8) | opc (8) | */ - /* | match tag 1 (32) | */ - /* | match tag 2 (32) | */ - - OP_SETDISPATCH = 35, /* N words: */ - /* | unused (24) | opc | */ - /* | upb_inttable* (32 or 64) | */ - - OP_DISPATCH = 36, /* No arg. */ - - OP_HALT = 37 /* No arg. */ -} opcode; - -#define OP_MAX OP_HALT - -UPB_INLINE opcode getop(uint32_t instr) { return (opcode)(instr & 0xff); } - -struct upb_pbcodecache { - upb_arena *arena; - upb_handlercache *dest; - bool allow_jit; - bool lazy; - - /* Map of upb_msgdef -> mgroup. */ - upb_inttable groups; -}; - -/* Method group; represents a set of decoder methods that had their code - * emitted together. Immutable once created. */ -typedef struct { - /* Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. Owned by us. - * - * Ideally this would be on pbcodecache (if we were actually caching code). - * Right now we don't actually cache anything, which is wasteful. */ - upb_inttable methods; - - /* The bytecode for our methods, if any exists. Owned by us. */ - uint32_t *bytecode; - uint32_t *bytecode_end; -} mgroup; - -/* The maximum that any submessages can be nested. Matches proto2's limit. - * This specifies the size of the decoder's statically-sized array and therefore - * setting it high will cause the upb::pb::Decoder object to be larger. - * - * If necessary we can add a runtime-settable property to Decoder that allow - * this to be larger than the compile-time setting, but this would add - * complexity, particularly since we would have to decide how/if to give users - * the ability to set a custom memory allocation function. */ -#define UPB_DECODER_MAX_NESTING 64 - -/* Internal-only struct used by the decoder. */ -typedef struct { - /* Space optimization note: we store two pointers here that the JIT - * doesn't need at all; the upb_handlers* inside the sink and - * the dispatch table pointer. We can optimze so that the JIT uses - * smaller stack frames than the interpreter. The only thing we need - * to guarantee is that the fallback routines can find end_ofs. */ - upb_sink sink; - - /* The absolute stream offset of the end-of-frame delimiter. - * Non-delimited frames (groups and non-packed repeated fields) reuse the - * delimiter of their parent, even though the frame may not end there. - * - * NOTE: the JIT stores a slightly different value here for non-top frames. - * It stores the value relative to the end of the enclosed message. But the - * top frame is still stored the same way, which is important for ensuring - * that calls from the JIT into C work correctly. */ - uint64_t end_ofs; - const uint32_t *base; - - /* 0 indicates a length-delimited field. - * A positive number indicates a known group. - * A negative number indicates an unknown group. */ - int32_t groupnum; - upb_inttable *dispatch; /* Not used by the JIT. */ -} upb_pbdecoder_frame; - -struct upb_pbdecodermethod { - /* While compiling, the base is relative in "ofs", after compiling it is - * absolute in "ptr". */ - union { - uint32_t ofs; /* PC offset of method. */ - void *ptr; /* Pointer to bytecode or machine code for this method. */ - } code_base; - - /* The decoder method group to which this method belongs. */ - const mgroup *group; - - /* Whether this method is native code or bytecode. */ - bool is_native_; - - /* The handler one calls to invoke this method. */ - upb_byteshandler input_handler_; - - /* The destination handlers this method is bound to. We own a ref. */ - const upb_handlers *dest_handlers_; - - /* Dispatch table -- used by both bytecode decoder and JIT when encountering a - * field number that wasn't the one we were expecting to see. See - * decoder.int.h for the layout of this table. */ - upb_inttable dispatch; -}; - -struct upb_pbdecoder { - upb_arena *arena; - - /* Our input sink. */ - upb_bytessink input_; - - /* The decoder method we are parsing with (owned). */ - const upb_pbdecodermethod *method_; - - size_t call_len; - const uint32_t *pc, *last; - - /* Current input buffer and its stream offset. */ - const char *buf, *ptr, *end, *checkpoint; - - /* End of the delimited region, relative to ptr, NULL if not in this buf. */ - const char *delim_end; - - /* End of the delimited region, relative to ptr, end if not in this buf. */ - const char *data_end; - - /* Overall stream offset of "buf." */ - uint64_t bufstart_ofs; - - /* Buffer for residual bytes not parsed from the previous buffer. */ - char residual[UPB_DECODER_MAX_RESIDUAL_BYTES]; - char *residual_end; - - /* Bytes of data that should be discarded from the input beore we start - * parsing again. We set this when we internally determine that we can - * safely skip the next N bytes, but this region extends past the current - * user buffer. */ - size_t skip; - - /* Stores the user buffer passed to our decode function. */ - const char *buf_param; - size_t size_param; - const upb_bufhandle *handle; - - /* Our internal stack. */ - upb_pbdecoder_frame *stack, *top, *limit; - const uint32_t **callstack; - size_t stack_size; - - upb_status *status; -}; - -/* Decoder entry points; used as handlers. */ -void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint); -size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, - size_t size, const upb_bufhandle *handle); -bool upb_pbdecoder_end(void *closure, const void *handler_data); - -/* Decoder-internal functions that the JIT calls to handle fallback paths. */ -int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, - size_t size, const upb_bufhandle *handle); -size_t upb_pbdecoder_suspend(upb_pbdecoder *d); -int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum, - uint8_t wire_type); -int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected); -int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64); -int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32); -int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64); -void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg); - -/* Error messages that are shared between the bytecode and JIT decoders. */ -extern const char *kPbDecoderStackOverflow; -extern const char *kPbDecoderSubmessageTooLong; - -/* Access to decoderplan members needed by the decoder. */ -const char *upb_pbdecoder_getopname(unsigned int op); - -/* A special label that means "do field dispatch for this message and branch to - * wherever that takes you." */ -#define LABEL_DISPATCH 0 - -/* A special slot in the dispatch table that stores the epilogue (ENDMSG and/or - * RET) for branching to when we find an appropriate ENDGROUP tag. */ -#define DISPATCH_ENDMSG 0 - -/* It's important to use this invalid wire type instead of 0 (which is a valid - * wire type). */ -#define NO_WIRE_TYPE 0xff - -/* The dispatch table layout is: - * [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ] - * - * If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup - * (UPB_MAX_FIELDNUMBER + fieldnum) and jump there. - * - * We need two wire types because of packed/non-packed compatibility. A - * primitive repeated field can use either wire type and be valid. While we - * could key the table on fieldnum+wiretype, the table would be 8x sparser. - * - * Storing two wire types in the primary value allows us to quickly rule out - * the second wire type without needing to do a separate lookup (this case is - * less common than an unknown field). */ -UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1, - uint8_t wt2) { - return (ofs << 16) | (wt2 << 8) | wt1; -} - -UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs, - uint8_t *wt1, uint8_t *wt2) { - *wt1 = (uint8_t)dispatch; - *wt2 = (uint8_t)(dispatch >> 8); - *ofs = dispatch >> 16; -} - -/* All of the functions in decoder.c that return int32_t return values according - * to the following scheme: - * 1. negative values indicate a return code from the following list. - * 2. positive values indicate that error or end of buffer was hit, and - * that the decode function should immediately return the given value - * (the decoder state has already been suspended and is ready to be - * resumed). */ -#define DECODE_OK -1 -#define DECODE_MISMATCH -2 /* Used only from checktag_slow(). */ -#define DECODE_ENDGROUP -3 /* Used only from checkunknown(). */ - -#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; } - - -#endif /* UPB_DECODER_INT_H_ */ -/* -** A number of routines for varint manipulation (we keep them all around to -** have multiple approaches available for benchmarking). -*/ - -#ifndef UPB_VARINT_DECODER_H_ -#define UPB_VARINT_DECODER_H_ - -#include -#include -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -#define UPB_MAX_WIRE_TYPE 5 - -/* The maximum number of bytes that it takes to encode a 64-bit varint. */ -#define UPB_PB_VARINT_MAX_LEN 10 - -/* Array of the "native" (ie. non-packed-repeated) wire type for the given a - * descriptor type (upb_descriptortype_t). */ -extern const uint8_t upb_pb_native_wire_types[]; - -UPB_INLINE uint64_t byteswap64(uint64_t val) { - uint64_t byte = 0xff; - return (val & (byte << 56) >> 56) - | (val & (byte << 48) >> 40) - | (val & (byte << 40) >> 24) - | (val & (byte << 32) >> 8) - | (val & (byte << 24) << 8) - | (val & (byte << 16) << 24) - | (val & (byte << 8) << 40) - | (val & (byte << 0) << 56); -} - -/* Zig-zag encoding/decoding **************************************************/ - -UPB_INLINE int32_t upb_zzdec_32(uint64_t _n) { - uint32_t n = (uint32_t)_n; - return (n >> 1) ^ -(int32_t)(n & 1); -} -UPB_INLINE int64_t upb_zzdec_64(uint64_t n) { - return (n >> 1) ^ -(int64_t)(n & 1); -} -UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { - return ((uint32_t)n << 1) ^ (n >> 31); -} -UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { - return ((uint64_t)n << 1) ^ (n >> 63); -} - -/* Decoding *******************************************************************/ - -/* All decoding functions return this struct by value. */ -typedef struct { - const char *p; /* NULL if the varint was unterminated. */ - uint64_t val; -} upb_decoderet; - -UPB_INLINE upb_decoderet upb_decoderet_make(const char *p, uint64_t val) { - upb_decoderet ret; - ret.p = p; - ret.val = val; - return ret; -} - -upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r); -upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r); - -/* Template for a function that checks the first two bytes with branching - * and dispatches 2-10 bytes with a separate function. Note that this may read - * up to 10 bytes, so it must not be used unless there are at least ten bytes - * left in the buffer! */ -#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \ -UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \ - uint8_t *p = (uint8_t*)_p; \ - upb_decoderet r; \ - if ((*p & 0x80) == 0) { \ - /* Common case: one-byte varint. */ \ - return upb_decoderet_make(_p + 1, *p & 0x7fU); \ - } \ - r = upb_decoderet_make(_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)); \ - if ((*(p + 1) & 0x80) == 0) { \ - /* Two-byte varint. */ \ - return r; \ - } \ - /* Longer varint, fallback to out-of-line function. */ \ - return decode_max8_function(r); \ -} - -UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32) -UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64) -#undef UPB_VARINT_DECODER_CHECK2 - -/* Our canonical functions for decoding varints, based on the currently - * favored best-performing implementations. */ -UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) { - if (sizeof(long) == 8) - return upb_vdecode_check2_branch64(p); - else - return upb_vdecode_check2_branch32(p); -} - - -/* Encoding *******************************************************************/ - -UPB_INLINE int upb_value_size(uint64_t val) { -#ifdef __GNUC__ - int high_bit = 63 - __builtin_clzll(val); /* 0-based, undef if val == 0. */ -#else - int high_bit = 0; - uint64_t tmp = val; - while(tmp >>= 1) high_bit++; -#endif - return val == 0 ? 1 : high_bit / 8 + 1; -} - -/* Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN - * bytes long), returning how many bytes were used. - * - * TODO: benchmark and optimize if necessary. */ -UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) { - size_t i; - if (val == 0) { buf[0] = 0; return 1; } - i = 0; - while (val) { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val) byte |= 0x80U; - buf[i++] = byte; - } - return i; -} - -UPB_INLINE size_t upb_varint_size(uint64_t val) { - char buf[UPB_PB_VARINT_MAX_LEN]; - return upb_vencode64(val, buf); -} - -/* Encodes a 32-bit varint, *not* sign-extended. */ -UPB_INLINE uint64_t upb_vencode32(uint32_t val) { - char buf[UPB_PB_VARINT_MAX_LEN]; - size_t bytes = upb_vencode64(val, buf); - uint64_t ret = 0; - UPB_ASSERT(bytes <= 5); - memcpy(&ret, buf, bytes); -#ifdef UPB_BIG_ENDIAN - ret = byteswap64(ret); -#endif - UPB_ASSERT(ret <= 0xffffffffffU); - return ret; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif /* UPB_VARINT_DECODER_H_ */ -/* -** upb::pb::Encoder (upb_pb_encoder) -** -** Implements a set of upb_handlers that write protobuf data to the binary wire -** format. -** -** This encoder implementation does not have any access to any out-of-band or -** precomputed lengths for submessages, so it must buffer submessages internally -** before it can emit the first byte. -*/ - -#ifndef UPB_ENCODER_H_ -#define UPB_ENCODER_H_ - - -#ifdef __cplusplus -namespace upb { -namespace pb { -class EncoderPtr; -} /* namespace pb */ -} /* namespace upb */ -#endif - -#define UPB_PBENCODER_MAX_NESTING 100 - -/* upb_pb_encoder *************************************************************/ - -/* Preallocation hint: decoder won't allocate more bytes than this when first - * constructed. This hint may be an overestimate for some build configurations. - * But if the decoder library is upgraded without recompiling the application, - * it may be an underestimate. */ -#define UPB_PB_ENCODER_SIZE 784 - -struct upb_pb_encoder; -typedef struct upb_pb_encoder upb_pb_encoder; - -#ifdef __cplusplus -extern "C" { -#endif - -upb_sink upb_pb_encoder_input(upb_pb_encoder *p); -upb_pb_encoder* upb_pb_encoder_create(upb_arena* a, const upb_handlers* h, - upb_bytessink output); - -/* Lazily builds and caches handlers that will push encoded data to a bytessink. - * Any msgdef objects used with this object must outlive it. */ -upb_handlercache *upb_pb_encoder_newcache(void); - -#ifdef __cplusplus -} /* extern "C" { */ - -class upb::pb::EncoderPtr { - public: - EncoderPtr(upb_pb_encoder* ptr) : ptr_(ptr) {} - - upb_pb_encoder* ptr() { return ptr_; } - - /* Creates a new encoder in the given environment. The Handlers must have - * come from NewHandlers() below. */ - static EncoderPtr Create(Arena* arena, const Handlers* handlers, - BytesSink output) { - return EncoderPtr( - upb_pb_encoder_create(arena->ptr(), handlers, output.sink())); - } - - /* The input to the encoder. */ - upb::Sink input() { return upb_pb_encoder_input(ptr()); } - - /* Creates a new set of handlers for this MessageDef. */ - static HandlerCache NewCache() { - return HandlerCache(upb_pb_encoder_newcache()); - } - - static const size_t kSize = UPB_PB_ENCODER_SIZE; - - private: - upb_pb_encoder* ptr_; -}; - -#endif /* __cplusplus */ - -#endif /* UPB_ENCODER_H_ */ -/* -** upb::pb::TextPrinter (upb_textprinter) -** -** Handlers for writing to protobuf text format. -*/ - -#ifndef UPB_TEXT_H_ -#define UPB_TEXT_H_ - - -#ifdef __cplusplus -namespace upb { -namespace pb { -class TextPrinterPtr; -} /* namespace pb */ -} /* namespace upb */ -#endif - -/* upb_textprinter ************************************************************/ - -struct upb_textprinter; -typedef struct upb_textprinter upb_textprinter; - -#ifdef __cplusplus -extern "C" { -#endif - -/* C API. */ -upb_textprinter *upb_textprinter_create(upb_arena *arena, const upb_handlers *h, - upb_bytessink output); -void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line); -upb_sink upb_textprinter_input(upb_textprinter *p); -upb_handlercache *upb_textprinter_newcache(void); - -#ifdef __cplusplus -} /* extern "C" */ - -class upb::pb::TextPrinterPtr { - public: - TextPrinterPtr(upb_textprinter* ptr) : ptr_(ptr) {} - - /* The given handlers must have come from NewHandlers(). It must outlive the - * TextPrinter. */ - static TextPrinterPtr Create(Arena *arena, upb::HandlersPtr *handlers, - BytesSink output) { - return TextPrinterPtr( - upb_textprinter_create(arena->ptr(), handlers->ptr(), output.sink())); - } - - void SetSingleLineMode(bool single_line) { - upb_textprinter_setsingleline(ptr_, single_line); - } - - Sink input() { return upb_textprinter_input(ptr_); } - - /* If handler caching becomes a requirement we can add a code cache as in - * decoder.h */ - static HandlerCache NewCache() { - return HandlerCache(upb_textprinter_newcache()); - } - - private: - upb_textprinter* ptr_; -}; - -#endif - -#endif /* UPB_TEXT_H_ */ -/* -** upb::json::Parser (upb_json_parser) -** -** Parses JSON according to a specific schema. -** Support for parsing arbitrary JSON (schema-less) will be added later. -*/ - -#ifndef UPB_JSON_PARSER_H_ -#define UPB_JSON_PARSER_H_ - - -#ifdef __cplusplus -namespace upb { -namespace json { -class CodeCache; -class ParserPtr; -class ParserMethodPtr; -} /* namespace json */ -} /* namespace upb */ -#endif - -/* upb_json_parsermethod ******************************************************/ - -struct upb_json_parsermethod; -typedef struct upb_json_parsermethod upb_json_parsermethod; - -#ifdef __cplusplus -extern "C" { -#endif - -const upb_byteshandler* upb_json_parsermethod_inputhandler( - const upb_json_parsermethod* m); - -#ifdef __cplusplus -} /* extern "C" */ - -class upb::json::ParserMethodPtr { - public: - ParserMethodPtr() : ptr_(nullptr) {} - ParserMethodPtr(const upb_json_parsermethod* ptr) : ptr_(ptr) {} - - const upb_json_parsermethod* ptr() const { return ptr_; } - - const BytesHandler* input_handler() const { - return upb_json_parsermethod_inputhandler(ptr()); - } - - private: - const upb_json_parsermethod* ptr_; -}; - -#endif /* __cplusplus */ - -/* upb_json_parser ************************************************************/ - -/* Preallocation hint: parser won't allocate more bytes than this when first - * constructed. This hint may be an overestimate for some build configurations. - * But if the parser library is upgraded without recompiling the application, - * it may be an underestimate. */ -#define UPB_JSON_PARSER_SIZE 5712 - -struct upb_json_parser; -typedef struct upb_json_parser upb_json_parser; - -#ifdef __cplusplus -extern "C" { -#endif - -upb_json_parser* upb_json_parser_create(upb_arena* a, - const upb_json_parsermethod* m, - const upb_symtab* symtab, - upb_sink output, - upb_status *status, - bool ignore_json_unknown); -upb_bytessink upb_json_parser_input(upb_json_parser* p); - -#ifdef __cplusplus -} /* extern "C" */ - -/* Parses an incoming BytesStream, pushing the results to the destination - * sink. */ -class upb::json::ParserPtr { - public: - ParserPtr(upb_json_parser* ptr) : ptr_(ptr) {} - - static ParserPtr Create(Arena* arena, ParserMethodPtr method, - SymbolTable* symtab, Sink output, Status* status, - bool ignore_json_unknown) { - upb_symtab* symtab_ptr = symtab ? symtab->ptr() : nullptr; - return ParserPtr(upb_json_parser_create( - arena->ptr(), method.ptr(), symtab_ptr, output.sink(), status->ptr(), - ignore_json_unknown)); - } - - BytesSink input() { return upb_json_parser_input(ptr_); } - - private: - upb_json_parser* ptr_; -}; - -#endif /* __cplusplus */ - -/* upb_json_codecache *********************************************************/ - -/* Lazily builds and caches decoder methods that will push data to the given - * handlers. The upb_symtab object(s) must outlive this object. */ - -struct upb_json_codecache; -typedef struct upb_json_codecache upb_json_codecache; - -#ifdef __cplusplus -extern "C" { -#endif - -upb_json_codecache *upb_json_codecache_new(void); -void upb_json_codecache_free(upb_json_codecache *cache); -const upb_json_parsermethod* upb_json_codecache_get(upb_json_codecache* cache, - const upb_msgdef* md); - -#ifdef __cplusplus -} /* extern "C" */ - -class upb::json::CodeCache { - public: - CodeCache() : ptr_(upb_json_codecache_new(), upb_json_codecache_free) {} - - /* Returns a DecoderMethod that can push data to the given handlers. - * If a suitable method already exists, it will be returned from the cache. */ - ParserMethodPtr Get(MessageDefPtr md) { - return upb_json_codecache_get(ptr_.get(), md.ptr()); - } - - private: - std::unique_ptr ptr_; -}; - -#endif - -#endif /* UPB_JSON_PARSER_H_ */ -/* -** upb::json::Printer -** -** Handlers that emit JSON according to a specific protobuf schema. -*/ - -#ifndef UPB_JSON_TYPED_PRINTER_H_ -#define UPB_JSON_TYPED_PRINTER_H_ - - -#ifdef __cplusplus -namespace upb { -namespace json { -class PrinterPtr; -} /* namespace json */ -} /* namespace upb */ -#endif - -/* upb_json_printer ***********************************************************/ - -#define UPB_JSON_PRINTER_SIZE 192 - -struct upb_json_printer; -typedef struct upb_json_printer upb_json_printer; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Native C API. */ -upb_json_printer *upb_json_printer_create(upb_arena *a, const upb_handlers *h, - upb_bytessink output); -upb_sink upb_json_printer_input(upb_json_printer *p); -const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md, - bool preserve_fieldnames, - const void *owner); - -/* Lazily builds and caches handlers that will push encoded data to a bytessink. - * Any msgdef objects used with this object must outlive it. */ -upb_handlercache *upb_json_printer_newcache(bool preserve_proto_fieldnames); - -#ifdef __cplusplus -} /* extern "C" */ - -/* Prints an incoming stream of data to a BytesSink in JSON format. */ -class upb::json::PrinterPtr { - public: - PrinterPtr(upb_json_printer* ptr) : ptr_(ptr) {} - - static PrinterPtr Create(Arena *arena, const upb::Handlers *handlers, - BytesSink output) { - return PrinterPtr( - upb_json_printer_create(arena->ptr(), handlers, output.sink())); - } - - /* The input to the printer. */ - Sink input() { return upb_json_printer_input(ptr_); } - - static const size_t kSize = UPB_JSON_PRINTER_SIZE; - - static HandlerCache NewCache(bool preserve_proto_fieldnames) { - return upb_json_printer_newcache(preserve_proto_fieldnames); - } - - private: - upb_json_printer* ptr_; -}; - -#endif /* __cplusplus */ - -#endif /* UPB_JSON_TYPED_PRINTER_H_ */ -/* See port_def.inc. This should #undef all macros #defined there. */ - -#undef UPB_MAPTYPE_STRING -#undef UPB_SIZE -#undef UPB_PTR_AT -#undef UPB_READ_ONEOF -#undef UPB_WRITE_ONEOF -#undef UPB_INLINE -#undef UPB_ALIGN_UP -#undef UPB_ALIGN_DOWN -#undef UPB_ALIGN_MALLOC -#undef UPB_ALIGN_OF -#undef UPB_FORCEINLINE -#undef UPB_NOINLINE -#undef UPB_NORETURN -#undef UPB_MAX -#undef UPB_MIN -#undef UPB_UNUSED -#undef UPB_ASSUME -#undef UPB_ASSERT -#undef UPB_ASSERT_DEBUGVAR -#undef UPB_UNREACHABLE -#undef UPB_INFINITY -#undef UPB_MSVC_VSNPRINTF -#undef _upb_snprintf -#undef _upb_vsnprintf -#undef _upb_va_copy diff --git a/php/ext/google/protobuf/utf8.c b/php/ext/google/protobuf/utf8.c deleted file mode 100644 index 2752a08b0593..000000000000 --- a/php/ext/google/protobuf/utf8.c +++ /dev/null @@ -1,68 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#include -#include - -#include "utf8.h" - -static const uint8_t utf8_offset[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -bool is_structurally_valid_utf8(const char* buf, int len) { - int i, j; - uint8_t offset; - - i = 0; - while (i < len) { - offset = utf8_offset[(uint8_t)buf[i]]; - if (offset == 0 || i + offset > len) { - return false; - } - for (j = i + 1; j < i + offset; j++) { - if ((buf[j] & 0xc0) != 0x80) { - return false; - } - } - i += offset; - } - return i == len; -} diff --git a/php/ext/google/protobuf/utf8.h b/php/ext/google/protobuf/utf8.h deleted file mode 100644 index 28b8d874a8b5..000000000000 --- a/php/ext/google/protobuf/utf8.h +++ /dev/null @@ -1,36 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#ifndef GOOGLE_PROTOBUF_UTF8_H_ -#define GOOGLE_PROTOBUF_UTF8_H_ - -bool is_structurally_valid_utf8(const char* buf, int len); - -#endif // GOOGLE_PROTOBUF_UTF8_H_ diff --git a/php/ext/google/protobuf2/array.c b/php/ext/google/protobuf2/array.c deleted file mode 100644 index 571d3e41cdee..000000000000 --- a/php/ext/google/protobuf2/array.c +++ /dev/null @@ -1,602 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#include "array.h" - -#include -#include - -#include - -// This is not self-contained: it must be after other Zend includes. -#include - -#include "arena.h" -#include "convert.h" -#include "def.h" -#include "php-upb.h" -#include "protobuf.h" - -static void RepeatedFieldIter_make(zval *val, zval *repeated_field); - -// ----------------------------------------------------------------------------- -// RepeatedField -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - zval arena; - upb_array *array; - upb_fieldtype_t type; - const Descriptor* desc; // When values are messages. -} RepeatedField; - -zend_class_entry *RepeatedField_class_entry; -static zend_object_handlers RepeatedField_object_handlers; - -// PHP Object Handlers ///////////////////////////////////////////////////////// - -/** - * RepeatedField_create() - * - * PHP class entry function to allocate and initialize a new RepeatedField - * object. - */ -static zend_object* RepeatedField_create(zend_class_entry *class_type) { - RepeatedField *intern = emalloc(sizeof(RepeatedField)); - zend_object_std_init(&intern->std, class_type); - intern->std.handlers = &RepeatedField_object_handlers; - Arena_Init(&intern->arena); - intern->array = NULL; - intern->desc = NULL; - // Skip object_properties_init(), we don't allow derived classes. - return &intern->std; -} - -/** - * RepeatedField_dtor() - * - * Object handler to destroy a RepeatedField. This releases all resources - * associated with the message. Note that it is possible to access a destroyed - * object from PHP in rare cases. - */ -static void RepeatedField_destructor(zend_object* obj) { - RepeatedField* intern = (RepeatedField*)obj; - ObjCache_Delete(intern->array); - zval_ptr_dtor(&intern->arena); - zend_object_std_dtor(&intern->std); -} - -static HashTable *RepeatedField_GetProperties(zval *object TSRMLS_DC) { - return NULL; // We do not have a properties table. -} - -static zval *RepeatedField_GetPropertyPtrPtr(zval *object, zval *member, - int type, void **cache_slot) { - return NULL; // We don't offer direct references to our properties. -} - -// C Functions from array.h //////////////////////////////////////////////////// - -// These are documented in the header file. - -void RepeatedField_GetPhpWrapper(zval *val, upb_array *arr, - const upb_fielddef *f, zval *arena) { - if (!arr) { - ZVAL_NULL(val); - return; - } - - if (!ObjCache_Get(arr, val)) { - RepeatedField *intern = emalloc(sizeof(RepeatedField)); - zend_object_std_init(&intern->std, RepeatedField_class_entry); - intern->std.handlers = &RepeatedField_object_handlers; - ZVAL_COPY(&intern->arena, arena); - intern->array = arr; - intern->type = upb_fielddef_type(f); - intern->desc = Descriptor_GetFromFieldDef(f); - // Skip object_properties_init(), we don't allow derived classes. - ObjCache_Add(intern->array, &intern->std); - ZVAL_OBJ(val, &intern->std); - } -} - -upb_array *RepeatedField_GetUpbArray(zval *val, const upb_fielddef *f, - upb_arena *arena) { - if (Z_ISREF_P(val)) { - ZVAL_DEREF(val); - } - - if (Z_TYPE_P(val) == IS_ARRAY) { - // Auto-construct, eg. [1, 2, 3] -> upb_array([1, 2, 3]). - upb_array *arr = upb_array_new(arena, upb_fielddef_type(f)); - HashTable *table = HASH_OF(val); - HashPosition pos; - upb_fieldtype_t type = upb_fielddef_type(f); - const Descriptor *desc = Descriptor_GetFromFieldDef(f); - - zend_hash_internal_pointer_reset_ex(table, &pos); - - while (true) { - zval *zv = zend_hash_get_current_data_ex(table, &pos); - upb_msgval val; - - if (!zv) return arr; - - if (!Convert_PhpToUpbAutoWrap(zv, &val, type, desc, arena)) { - return NULL; - } - - upb_array_append(arr, val, arena); - zend_hash_move_forward_ex(table, &pos); - } - } else if (Z_TYPE_P(val) == IS_OBJECT && - Z_OBJCE_P(val) == RepeatedField_class_entry) { - // Unwrap existing RepeatedField object to get the upb_array* inside. - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(val); - const Descriptor *desc = Descriptor_GetFromFieldDef(f); - - if (intern->type != upb_fielddef_type(f) || intern->desc != desc) { - php_error_docref(NULL, E_USER_ERROR, - "Wrong type for this repeated field."); - } - - upb_arena_fuse(arena, Arena_Get(&intern->arena)); - return intern->array; - } else { - php_error_docref(NULL, E_USER_ERROR, "Must be a repeated field"); - return NULL; - } -} - -// RepeatedField PHP methods /////////////////////////////////////////////////// - -/** - * RepeatedField::__construct() - * - * Constructs an instance of RepeatedField. - * @param long Type of the stored element. - * @param string Message/Enum class. - */ -PHP_METHOD(RepeatedField, __construct) { - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); - upb_arena *arena = Arena_Get(&intern->arena); - zend_long type; - zend_class_entry* klass = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|C", &type, &klass) != SUCCESS) { - return; - } - - intern->type = pbphp_dtype_to_type(type); - intern->desc = Descriptor_GetFromClassEntry(klass); - - if (intern->type == UPB_TYPE_MESSAGE && klass == NULL) { - php_error_docref(NULL, E_USER_ERROR, - "Message/enum type must have concrete class."); - return; - } - - intern->array = upb_array_new(arena, intern->type); - ObjCache_Add(intern->array, &intern->std); -} - -/** - * RepeatedField::append() - * - * Append element to the end of the repeated field. - * @param object The element to be added. - */ -PHP_METHOD(RepeatedField, append) { - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); - upb_arena *arena = Arena_Get(&intern->arena); - zval *php_val; - upb_msgval msgval; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &php_val) != SUCCESS || - !Convert_PhpToUpb(php_val, &msgval, intern->type, intern->desc, arena)) { - return; - } - - upb_array_append(intern->array, msgval, arena); -} - -/** - * RepeatedField::offsetExists() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * isset($arr[$idx]); - * empty($arr[$idx]); - * - * @param long The index to be checked. - * @return bool True if the element at the given index exists. - */ -PHP_METHOD(RepeatedField, offsetExists) { - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); - zend_long index; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) { - return; - } - - RETURN_BOOL(index >= 0 && index < upb_array_size(intern->array)); -} - -/** - * RepeatedField::offsetGet() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * $x = $arr[$idx]; - * - * @param long The index of the element to be fetched. - * @return object The stored element at given index. - * @exception Invalid type for index. - * @exception Non-existing index. - */ -PHP_METHOD(RepeatedField, offsetGet) { - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); - zend_long index; - upb_msgval msgval; - zval ret; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) == FAILURE) { - return; - } - - if (index < 0 || index >= upb_array_size(intern->array)) { - zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); - return; - } - - msgval = upb_array_get(intern->array, index); - Convert_UpbToPhp(msgval, &ret, intern->type, intern->desc, &intern->arena); - RETURN_ZVAL(&ret, 0, 1); -} - -/** - * RepeatedField::offsetSet() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * $arr[$idx] = $x; - * $arr []= $x; // Append - * - * @param long The index of the element to be assigned. - * @param object The element to be assigned. - * @exception Invalid type for index. - * @exception Non-existing index. - * @exception Incorrect type of the element. - */ -PHP_METHOD(RepeatedField, offsetSet) { - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); - upb_arena *arena = Arena_Get(&intern->arena); - size_t size = upb_array_size(intern->array); - zval *offset, *val; - int64_t index; - upb_msgval msgval; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &offset, &val) != SUCCESS) { - return; - } - - if (Z_TYPE_P(offset) == IS_NULL) { - index = size; - } else if (!Convert_PhpToInt64(offset, &index)) { - return; - } - - if (!Convert_PhpToUpb(val, &msgval, intern->type, intern->desc, arena)) { - return; - } - - if (index > size) { - zend_error(E_USER_ERROR, "Element at index %ld doesn't exist.\n", index); - } else if (index == size) { - upb_array_append(intern->array, msgval, Arena_Get(&intern->arena)); - } else { - upb_array_set(intern->array, index, msgval); - } -} - -/** - * RepeatedField::offsetUnset() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * unset($arr[$idx]); - * - * @param long The index of the element to be removed. - * @exception Invalid type for index. - * @exception The element to be removed is not at the end of the RepeatedField. - */ -PHP_METHOD(RepeatedField, offsetUnset) { - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); - zend_long index; - zend_long size = upb_array_size(intern->array); - - // Only the element at the end of the array can be removed. - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &index) != SUCCESS) { - return; - } - - if (size == 0 || index != size - 1) { - php_error_docref(NULL, E_USER_ERROR, "Cannot remove element at %ld.\n", - index); - return; - } - - upb_array_resize(intern->array, size - 1, Arena_Get(&intern->arena)); -} - -/** - * RepeatedField::count() - * - * Implements the Countable interface. Invoked when PHP code calls: - * - * $len = count($arr); - * Return the number of stored elements. - * This will also be called for: count($arr) - * @return long The number of stored elements. - */ -PHP_METHOD(RepeatedField, count) { - RepeatedField *intern = (RepeatedField*)Z_OBJ_P(getThis()); - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - RETURN_LONG(upb_array_size(intern->array)); -} - -/** - * RepeatedField::getIterator() - * - * Implements the IteratorAggregate interface. Invoked when PHP code calls: - * - * foreach ($arr) {} - * - * @return object Beginning iterator. - */ -PHP_METHOD(RepeatedField, getIterator) { - zval ret; - RepeatedFieldIter_make(&ret, getThis()); - RETURN_ZVAL(&ret, 0, 1); -} - -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) - ZEND_ARG_INFO(0, index) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, newval) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_void, 0) -ZEND_END_ARG_INFO() - -static zend_function_entry repeated_field_methods[] = { - PHP_ME(RepeatedField, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, append, NULL, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, count, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedField, getIterator, arginfo_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// PHP RepeatedFieldIter -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - zval repeated_field; - zend_long position; -} RepeatedFieldIter; - -zend_class_entry *RepeatedFieldIter_class_entry; -static zend_object_handlers repeated_field_iter_object_handlers; - -/** - * RepeatedFieldIter_create() - * - * PHP class entry function to allocate and initialize a new RepeatedFieldIter - * object. - */ -zend_object* RepeatedFieldIter_create(zend_class_entry *class_type) { - RepeatedFieldIter *intern = emalloc(sizeof(RepeatedFieldIter)); - zend_object_std_init(&intern->std, class_type); - intern->std.handlers = &repeated_field_iter_object_handlers; - ZVAL_NULL(&intern->repeated_field); - intern->position = 0; - // Skip object_properties_init(), we don't allow derived classes. - return &intern->std; -} - -/** - * RepeatedFieldIter_dtor() - * - * Object handler to destroy a RepeatedFieldIter. This releases all resources - * associated with the message. Note that it is possible to access a destroyed - * object from PHP in rare cases. - */ -static void RepeatedFieldIter_dtor(zend_object* obj) { - RepeatedFieldIter* intern = (RepeatedFieldIter*)obj; - zval_ptr_dtor(&intern->repeated_field); - zend_object_std_dtor(&intern->std); -} - -/** - * RepeatedFieldIter_make() - * - * C function to create a RepeatedFieldIter. - */ -static void RepeatedFieldIter_make(zval *val, zval *repeated_field) { - RepeatedFieldIter *iter; - ZVAL_OBJ(val, RepeatedFieldIter_class_entry->create_object( - RepeatedFieldIter_class_entry)); - iter = (RepeatedFieldIter*)Z_OBJ_P(val); - ZVAL_COPY(&iter->repeated_field, repeated_field); -} - -/* - * When a user writes: - * - * foreach($arr as $key => $val) {} - * - * PHP's iterator protocol is: - * - * $iter = $arr->getIterator(); - * for ($iter->rewind(); $iter->valid(); $iter->next()) { - * $key = $iter->key(); - * $val = $iter->current(); - * } - */ - -/** - * RepeatedFieldIter::rewind() - * - * Implements the Iterator interface. Sets the iterator to the first element. - */ -PHP_METHOD(RepeatedFieldIter, rewind) { - RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); - intern->position = 0; -} - -/** - * RepeatedFieldIter::current() - * - * Implements the Iterator interface. Returns the current value. - */ -PHP_METHOD(RepeatedFieldIter, current) { - RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); - RepeatedField *field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field); - upb_array *array = field->array; - zend_long index = intern->position; - upb_msgval msgval; - zval ret; - - if (index < 0 || index >= upb_array_size(array)) { - zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index); - } - - msgval = upb_array_get(array, index); - - Convert_UpbToPhp(msgval, &ret, field->type, field->desc, &field->arena); - RETURN_ZVAL(&ret, 0, 1); -} - -/** - * RepeatedFieldIter::key() - * - * Implements the Iterator interface. Returns the current key. - */ -PHP_METHOD(RepeatedFieldIter, key) { - RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); - RETURN_LONG(intern->position); -} - -/** - * RepeatedFieldIter::next() - * - * Implements the Iterator interface. Advances to the next element. - */ -PHP_METHOD(RepeatedFieldIter, next) { - RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); - ++intern->position; -} - -/** - * RepeatedFieldIter::valid() - * - * Implements the Iterator interface. Returns true if this is a valid element. - */ -PHP_METHOD(RepeatedFieldIter, valid) { - RepeatedFieldIter *intern = (RepeatedFieldIter*)Z_OBJ_P(getThis()); - RepeatedField *field = (RepeatedField*)Z_OBJ_P(&intern->repeated_field); - RETURN_BOOL(intern->position < upb_array_size(field->array)); -} - -static zend_function_entry repeated_field_iter_methods[] = { - PHP_ME(RepeatedFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(RepeatedFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// Module init. -// ----------------------------------------------------------------------------- - -/** - * Array_ModuleInit() - * - * Called when the C extension is loaded to register all types. - */ -void Array_ModuleInit() { - zend_class_entry tmp_ce; - zend_object_handlers *h; - - // RepeatedField. - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedField", - repeated_field_methods); - - RepeatedField_class_entry = zend_register_internal_class(&tmp_ce); - zend_class_implements(RepeatedField_class_entry, 3, spl_ce_ArrayAccess, - zend_ce_aggregate, spl_ce_Countable); - RepeatedField_class_entry->ce_flags |= ZEND_ACC_FINAL; - RepeatedField_class_entry->create_object = RepeatedField_create; - - h = &RepeatedField_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - h->dtor_obj = RepeatedField_destructor; - h->get_properties = RepeatedField_GetProperties; - h->get_property_ptr_ptr = RepeatedField_GetPropertyPtrPtr; - - // RepeatedFieldIter - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\RepeatedFieldIter", - repeated_field_iter_methods); - - RepeatedFieldIter_class_entry = zend_register_internal_class(&tmp_ce); - zend_class_implements(RepeatedFieldIter_class_entry, 1, zend_ce_iterator); - RepeatedFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL; - RepeatedFieldIter_class_entry->create_object = RepeatedFieldIter_create; - - h = &repeated_field_iter_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - h->dtor_obj = RepeatedFieldIter_dtor; -} diff --git a/php/ext/google/protobuf2/config.m4 b/php/ext/google/protobuf2/config.m4 deleted file mode 100644 index 3fdcb00480d4..000000000000 --- a/php/ext/google/protobuf2/config.m4 +++ /dev/null @@ -1,10 +0,0 @@ -PHP_ARG_ENABLE(protobuf, whether to enable Protobuf extension, [ --enable-protobuf Enable Protobuf extension]) - -if test "$PHP_PROTOBUF" != "no"; then - - PHP_NEW_EXTENSION( - protobuf, - arena.c array.c bundled_php.c convert.c def.c map.c message.c names.c php-upb.c protobuf.c, - $ext_shared) - -fi diff --git a/php/ext/google/protobuf2/def.c b/php/ext/google/protobuf2/def.c deleted file mode 100644 index c76134d86baa..000000000000 --- a/php/ext/google/protobuf2/def.c +++ /dev/null @@ -1,1085 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#include "def.h" - -#include - -// This is not self-contained: it must be after other Zend includes. -#include - -#include "names.h" -#include "php-upb.h" -#include "protobuf.h" - -static void CheckUpbStatus(const upb_status* status, const char* msg) { - if (!upb_ok(status)) { - zend_error(E_ERROR, "%s: %s\n", msg, upb_status_errmsg(status)); - } -} - -static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f); - -// We use this for objects that should not be created directly from PHP. -static zend_object *CreateHandler_ReturnNull(zend_class_entry *class_type) { - return NULL; // Nobody should call this. -} - - -// ----------------------------------------------------------------------------- -// EnumValueDescriptor -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - const char *name; - int32_t number; -} EnumValueDescriptor; - -zend_class_entry *EnumValueDescriptor_class_entry; -static zend_object_handlers EnumValueDescriptor_object_handlers; - -/* - * EnumValueDescriptor_Make() - * - * Function to create an EnumValueDescriptor object from C. - */ -static void EnumValueDescriptor_Make(zval *val, const char *name, - int32_t number) { - EnumValueDescriptor *intern = emalloc(sizeof(EnumValueDescriptor)); - zend_object_std_init(&intern->std, EnumValueDescriptor_class_entry); - intern->std.handlers = &EnumValueDescriptor_object_handlers; - intern->name = name; - intern->number = number; - // Skip object_properties_init(), we don't allow derived classes. - ZVAL_OBJ(val, &intern->std); -} - -/* - * EnumValueDescriptor::getName() - * - * Returns the name for this enum value. - */ -PHP_METHOD(EnumValueDescriptor, getName) { - EnumValueDescriptor *intern = (EnumValueDescriptor*)Z_OBJ_P(getThis()); - RETURN_STRING(intern->name); -} - -/* - * EnumValueDescriptor::getNumber() - * - * Returns the number for this enum value. - */ -PHP_METHOD(EnumValueDescriptor, getNumber) { - EnumValueDescriptor *intern = (EnumValueDescriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(intern->number); -} - -static zend_function_entry EnumValueDescriptor_methods[] = { - PHP_ME(EnumValueDescriptor, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumValueDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// EnumDescriptor -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - const upb_enumdef *enumdef; -} EnumDescriptor; - -zend_class_entry *EnumDescriptor_class_entry; -static zend_object_handlers EnumDescriptor_object_handlers; - -void EnumDescriptor_FromClassEntry(zval *val, zend_class_entry *ce) { - // To differentiate enums from classes, we pointer-tag the class entry. - void* key = (void*)((uintptr_t)ce | 1); - PBPHP_ASSERT(key != ce); - - if (ce == NULL) { - ZVAL_NULL(val); - return; - } - - if (!ObjCache_Get(key, val)) { - const upb_enumdef *e = NameMap_GetEnum(ce); - if (!e) { - ZVAL_NULL(val); - return; - } - EnumDescriptor* ret = emalloc(sizeof(EnumDescriptor)); - zend_object_std_init(&ret->std, EnumDescriptor_class_entry); - ret->std.handlers = &EnumDescriptor_object_handlers; - ret->enumdef = e; - ObjCache_Add(key, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - - ZVAL_OBJ(val, &ret->std); - } -} - -void EnumDescriptor_FromEnumDef(zval *val, const upb_enumdef *m) { - if (!m) { - ZVAL_NULL(val); - } else { - char *classname = - GetPhpClassname(upb_enumdef_file(m), upb_enumdef_fullname(m)); - zend_string *str = zend_string_init(classname, strlen(classname), 0); - zend_class_entry *ce = zend_lookup_class(str); // May autoload the class. - - zend_string_release (str); - - if (!ce) { - zend_error(E_ERROR, "Couldn't load generated class %s", classname); - } - - free(classname); - EnumDescriptor_FromClassEntry(val, ce); - } -} - -/* - * EnumDescriptor::getValue() - * - * Returns an EnumValueDescriptor for this index. Note: we are not looking - * up by numeric enum value, but by the index in the list of enum values. - */ -PHP_METHOD(EnumDescriptor, getValue) { - EnumDescriptor *intern = (EnumDescriptor*)Z_OBJ_P(getThis()); - zend_long index; - zval ret; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { - zend_error(E_USER_ERROR, "Expect integer for index.\n"); - return; - } - - int field_num = upb_enumdef_numvals(intern->enumdef); - if (index < 0 || index >= field_num) { - zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); - return; - } - - upb_enum_iter iter; - int i; - for(upb_enum_begin(&iter, intern->enumdef), i = 0; - !upb_enum_done(&iter) && i < index; - upb_enum_next(&iter), i++); - - EnumValueDescriptor_Make(&ret, upb_enum_iter_name(&iter), - upb_enum_iter_number(&iter)); - RETURN_ZVAL(&ret, 0, 1); -} - -/* - * EnumDescriptor::getValueCount() - * - * Returns the number of values in this enum. - */ -PHP_METHOD(EnumDescriptor, getValueCount) { - EnumDescriptor *intern = (EnumDescriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(upb_enumdef_numvals(intern->enumdef)); -} - -/* - * EnumDescriptor::getPublicDescriptor() - * - * Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not - * have two separate EnumDescriptor classes. We use a single class for both - * the public and private descriptor. - */ -PHP_METHOD(EnumDescriptor, getPublicDescriptor) { - RETURN_ZVAL(getThis(), 1, 0); -} - -static zend_function_entry EnumDescriptor_methods[] = { - PHP_ME(EnumDescriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumDescriptor, getValueCount, NULL, ZEND_ACC_PUBLIC) - PHP_ME(EnumDescriptor, getValue, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// Oneof -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - const upb_oneofdef *oneofdef; -} OneofDescriptor; - -zend_class_entry *OneofDescriptor_class_entry; -static zend_object_handlers OneofDescriptor_object_handlers; - -static void OneofDescriptor_FromOneofDef(zval *val, const upb_oneofdef *o) { - if (o == NULL) { - ZVAL_NULL(val); - return; - } - - if (!ObjCache_Get(o, val)) { - OneofDescriptor* ret = emalloc(sizeof(OneofDescriptor)); - zend_object_std_init(&ret->std, OneofDescriptor_class_entry); - ret->std.handlers = &OneofDescriptor_object_handlers; - ret->oneofdef = o; - ObjCache_Add(o, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - - ZVAL_OBJ(val, &ret->std); - } -} - -/* - * OneofDescriptor::getName() - * - * Returns the name of this oneof. - */ -PHP_METHOD(OneofDescriptor, getName) { - OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis()); - RETURN_STRING(upb_oneofdef_name(intern->oneofdef)); -} - -/* - * OneofDescriptor::getField() - * - * Returns a field from this oneof. The given index must be in the range - * [0, getFieldCount() - 1]. - */ -PHP_METHOD(OneofDescriptor, getField) { - OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis()); - zend_long index; - zval ret; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { - zend_error(E_USER_ERROR, "Expect integer for index.\n"); - return; - } - - int field_num = upb_oneofdef_numfields(intern->oneofdef); - if (index < 0 || index >= field_num) { - zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); - return; - } - - upb_oneof_iter iter; - int i; - for(upb_oneof_begin(&iter, intern->oneofdef), i = 0; - !upb_oneof_done(&iter) && i < index; - upb_oneof_next(&iter), i++); - const upb_fielddef *field = upb_oneof_iter_field(&iter); - - FieldDescriptor_FromFieldDef(&ret, field); - RETURN_ZVAL(&ret, 1, 0); -} - -/* - * OneofDescriptor::getFieldCount() - * - * Returns the number of fields in this oneof. - */ -PHP_METHOD(OneofDescriptor, getFieldCount) { - OneofDescriptor *intern = (OneofDescriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(upb_oneofdef_numfields(intern->oneofdef)); -} - -static zend_function_entry OneofDescriptor_methods[] = { - PHP_ME(OneofDescriptor, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(OneofDescriptor, getField, NULL, ZEND_ACC_PUBLIC) - PHP_ME(OneofDescriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// FieldDescriptor -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - const upb_fielddef *fielddef; -} FieldDescriptor; - -zend_class_entry *FieldDescriptor_class_entry; -static zend_object_handlers FieldDescriptor_object_handlers; - -static void FieldDescriptor_FromFieldDef(zval *val, const upb_fielddef *f) { - if (f == NULL) { - ZVAL_NULL(val); - return; - } - - if (!ObjCache_Get(f, val)) { - FieldDescriptor* ret = emalloc(sizeof(FieldDescriptor)); - zend_object_std_init(&ret->std, FieldDescriptor_class_entry); - ret->std.handlers = &FieldDescriptor_object_handlers; - ret->fielddef = f; - ObjCache_Add(f, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - - ZVAL_OBJ(val, &ret->std); - } -} - -upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) { - switch (type) { -#define CASE(descriptor_type, type) \ - case UPB_DESCRIPTOR_TYPE_##descriptor_type: \ - return UPB_TYPE_##type; - - CASE(FLOAT, FLOAT); - CASE(DOUBLE, DOUBLE); - CASE(BOOL, BOOL); - CASE(STRING, STRING); - CASE(BYTES, BYTES); - CASE(MESSAGE, MESSAGE); - CASE(GROUP, MESSAGE); - CASE(ENUM, ENUM); - CASE(INT32, INT32); - CASE(INT64, INT64); - CASE(UINT32, UINT32); - CASE(UINT64, UINT64); - CASE(SINT32, INT32); - CASE(SINT64, INT64); - CASE(FIXED32, UINT32); - CASE(FIXED64, UINT64); - CASE(SFIXED32, INT32); - CASE(SFIXED64, INT64); - -#undef CONVERT - - } - - zend_error(E_ERROR, "Unknown field type."); - return 0; -} - -/* - * FieldDescriptor::getName() - * - * Returns the name of this field. - */ -PHP_METHOD(FieldDescriptor, getName) { - FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); - RETURN_STRING(upb_fielddef_name(intern->fielddef)); -} - -/* - * FieldDescriptor::getNumber() - * - * Returns the number of this field. - */ -PHP_METHOD(FieldDescriptor, getNumber) { - FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(upb_fielddef_number(intern->fielddef)); -} - -/* - * FieldDescriptor::getLabel() - * - * Returns the label of this field as an integer. - */ -PHP_METHOD(FieldDescriptor, getLabel) { - FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(upb_fielddef_label(intern->fielddef)); -} - -/* - * FieldDescriptor::getType() - * - * Returns the type of this field as an integer. - */ -PHP_METHOD(FieldDescriptor, getType) { - FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(upb_fielddef_descriptortype(intern->fielddef)); -} - -/* - * FieldDescriptor::isMap() - * - * Returns true if this field is a map. - */ -PHP_METHOD(FieldDescriptor, isMap) { - FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); - RETURN_BOOL(upb_fielddef_ismap(intern->fielddef)); -} - -/* - * FieldDescriptor::getEnumType() - * - * Returns the EnumDescriptor for this field, which must be an enum. - */ -PHP_METHOD(FieldDescriptor, getEnumType) { - FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); - const upb_enumdef *e = upb_fielddef_enumsubdef(intern->fielddef); - zval ret; - - if (!e) { - zend_throw_exception_ex(NULL, 0, - "Cannot get enum type for non-enum field '%s'", - upb_fielddef_name(intern->fielddef)); - return; - } - - EnumDescriptor_FromEnumDef(&ret, e); - RETURN_ZVAL(&ret, 1, 0); -} - -/* - * FieldDescriptor::getMessageType() - * - * Returns the Descriptor for this field, which must be a message. - */ -PHP_METHOD(FieldDescriptor, getMessageType) { - FieldDescriptor *intern = (FieldDescriptor*)Z_OBJ_P(getThis()); - Descriptor* desc = Descriptor_GetFromFieldDef(intern->fielddef); - zval ret; - - if (!desc) { - zend_throw_exception_ex( - NULL, 0, "Cannot get message type for non-message field '%s'", - upb_fielddef_name(intern->fielddef)); - return; - } - - ZVAL_OBJ(&ret, &desc->std); - RETURN_ZVAL(&ret, 1, 0); -} - -static zend_function_entry FieldDescriptor_methods[] = { - PHP_ME(FieldDescriptor, getName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getNumber, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getLabel, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getType, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, isMap, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getEnumType, NULL, ZEND_ACC_PUBLIC) - PHP_ME(FieldDescriptor, getMessageType, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// Descriptor -// ----------------------------------------------------------------------------- - -zend_class_entry *Descriptor_class_entry; -static zend_object_handlers Descriptor_object_handlers; - -static void Descriptor_destructor(zend_object* obj) { - // We don't really need to do anything here, we don't allow this to be - // collected before the end of the request. -} - -// C Functions from def.h ////////////////////////////////////////////////////// - -// These are documented in the header file. - -void Descriptor_FromClassEntry(zval *val, zend_class_entry *ce) { - if (ce == NULL) { - ZVAL_NULL(val); - return; - } - - if (!ObjCache_Get(ce, val)) { - const upb_msgdef *msgdef = NameMap_GetMessage(ce); - if (!msgdef) { - ZVAL_NULL(val); - return; - } - Descriptor* ret = emalloc(sizeof(Descriptor)); - zend_object_std_init(&ret->std, Descriptor_class_entry); - ret->std.handlers = &Descriptor_object_handlers; - ret->class_entry = ce; - ret->msgdef = msgdef; - ObjCache_Add(ce, &ret->std); - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - - ZVAL_OBJ(val, &ret->std); - } -} - -Descriptor* Descriptor_GetFromClassEntry(zend_class_entry *ce) { - zval desc; - Descriptor_FromClassEntry(&desc, ce); - if (Z_TYPE_P(&desc) == IS_NULL) { - return NULL; - } else { - return (Descriptor*)Z_OBJ_P(&desc); - } -} - -Descriptor* Descriptor_GetFromMessageDef(const upb_msgdef *m) { - if (m) { - if (upb_msgdef_mapentry(m)) { - // A bit of a hack, since map entries don't have classes. - Descriptor* ret = emalloc(sizeof(Descriptor)); - zend_object_std_init(&ret->std, Descriptor_class_entry); - ret->std.handlers = &Descriptor_object_handlers; - ret->class_entry = NULL; - ret->msgdef = m; - - // Prevent this from ever being collected (within a request). - GC_ADDREF(&ret->std); - - return ret; - } - - char *classname = - GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m)); - zend_string *str = zend_string_init(classname, strlen(classname), 0); - zend_class_entry *ce = zend_lookup_class(str); // May autoload the class. - - zend_string_release (str); - - if (!ce) { - zend_error(E_ERROR, "Couldn't load generated class %s", classname); - } - - free(classname); - return Descriptor_GetFromClassEntry(ce); - } else { - return NULL; - } -} - -Descriptor* Descriptor_GetFromFieldDef(const upb_fielddef *f) { - return Descriptor_GetFromMessageDef(upb_fielddef_msgsubdef(f)); -} - -/* - * Descriptor::getPublicDescriptor() - * - * Returns this EnumDescriptor. Unlike the pure-PHP descriptor, we do not - * have two separate EnumDescriptor classes. We use a single class for both - * the public and private descriptor. - */ -PHP_METHOD(Descriptor, getPublicDescriptor) { - RETURN_ZVAL(getThis(), 1, 0); -} - -/* - * Descriptor::getFullName() - * - * Returns the full name for this message type. - */ -PHP_METHOD(Descriptor, getFullName) { - Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); - RETURN_STRING(upb_msgdef_fullname(intern->msgdef)); -} - -/* - * Descriptor::getField() - * - * Returns a FieldDescriptor for the given index, which must be in the range - * [0, getFieldCount()-1]. - */ -PHP_METHOD(Descriptor, getField) { - Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); - int count = upb_msgdef_numfields(intern->msgdef); - zval ret; - zend_long index; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { - zend_error(E_USER_ERROR, "Expect integer for index.\n"); - return; - } - - if (index < 0 || index >= count) { - zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); - return; - } - - upb_msg_field_iter iter; - int i; - for(upb_msg_field_begin(&iter, intern->msgdef), i = 0; - !upb_msg_field_done(&iter) && i < index; - upb_msg_field_next(&iter), i++); - const upb_fielddef *field = upb_msg_iter_field(&iter); - - FieldDescriptor_FromFieldDef(&ret, field); - RETURN_ZVAL(&ret, 1, 0); -} - -/* - * Descriptor::getFieldCount() - * - * Returns the number of fields in this message. - */ -PHP_METHOD(Descriptor, getFieldCount) { - Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(upb_msgdef_numfields(intern->msgdef)); -} - -/* - * Descriptor::getOneofDecl() - * - * Returns a OneofDescriptor for the given index, which must be in the range - * [0, getOneofDeclCount()]. - */ -PHP_METHOD(Descriptor, getOneofDecl) { - Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); - zend_long index; - zval ret; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) == - FAILURE) { - zend_error(E_USER_ERROR, "Expect integer for index.\n"); - return; - } - - int field_num = upb_msgdef_numoneofs(intern->msgdef); - if (index < 0 || index >= field_num) { - zend_error(E_USER_ERROR, "Cannot get element at %ld.\n", index); - return; - } - - upb_msg_oneof_iter iter; - int i; - for(upb_msg_oneof_begin(&iter, intern->msgdef), i = 0; - !upb_msg_oneof_done(&iter) && i < index; - upb_msg_oneof_next(&iter), i++); - const upb_oneofdef *oneof = upb_msg_iter_oneof(&iter); - - OneofDescriptor_FromOneofDef(&ret, oneof); - RETURN_ZVAL(&ret, 1, 0); -} - -/* - * Descriptor::getOneofDeclCount() - * - * Returns the number of oneofs in this message. - */ -PHP_METHOD(Descriptor, getOneofDeclCount) { - Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); - RETURN_LONG(upb_msgdef_numoneofs(intern->msgdef)); -} - -/* - * Descriptor::getClass() - * - * Returns the name of the PHP class for this message. - */ -PHP_METHOD(Descriptor, getClass) { - Descriptor *intern = (Descriptor*)Z_OBJ_P(getThis()); - const char* classname = ZSTR_VAL(intern->class_entry->name); - RETURN_STRING(classname); -} - - -static zend_function_entry Descriptor_methods[] = { - PHP_ME(Descriptor, getClass, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getFullName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getField, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getFieldCount, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getOneofDecl, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getOneofDeclCount, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Descriptor, getPublicDescriptor, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// DescriptorPool -// ----------------------------------------------------------------------------- - -typedef struct DescriptorPool { - zend_object std; - upb_symtab *symtab; -} DescriptorPool; - -zend_class_entry *DescriptorPool_class_entry; -static zend_object_handlers DescriptorPool_object_handlers; - -static DescriptorPool *GetPool(const zval* this_ptr) { - return (DescriptorPool*)Z_OBJ_P(this_ptr); -} - -/** - * Object handler to create an DescriptorPool. - */ -static zend_object* DescriptorPool_create(zend_class_entry *class_type) { - DescriptorPool *intern = emalloc(sizeof(DescriptorPool)); - zend_object_std_init(&intern->std, class_type); - intern->std.handlers = &DescriptorPool_object_handlers; - intern->symtab = upb_symtab_new(); - // Skip object_properties_init(), we don't allow derived classes. - return &intern->std; -} - -/** - * Object handler to free an DescriptorPool. - */ -static void DescriptorPool_destructor(zend_object* obj) { - DescriptorPool* intern = (DescriptorPool*)obj; - if (intern->symtab) { - upb_symtab_free(intern->symtab); - } - intern->symtab = NULL; - zend_object_std_dtor(&intern->std); -} - -void DescriptorPool_CreateWithSymbolTable(zval *zv, upb_symtab *symtab) { - ZVAL_OBJ(zv, DescriptorPool_create(DescriptorPool_class_entry)); - - if (symtab) { - DescriptorPool *intern = GetPool(zv); - upb_symtab_free(intern->symtab); - intern->symtab = symtab; - } -} - -upb_symtab *DescriptorPool_Steal(zval *zv) { - DescriptorPool *intern = GetPool(zv); - upb_symtab *ret = intern->symtab; - intern->symtab = NULL; - return ret; -} - -upb_symtab *DescriptorPool_GetSymbolTable() { - DescriptorPool *intern = GetPool(get_generated_pool()); - return intern->symtab; -} - -/* - * DescriptorPool::getGeneratedPool() - * - * Returns the generated DescriptorPool. - */ -PHP_METHOD(DescriptorPool, getGeneratedPool) { - zval ret; - ZVAL_COPY(&ret, get_generated_pool()); - RETURN_ZVAL(&ret, 0, 1); -} - -/* - * DescriptorPool::getDescriptorByClassName() - * - * Returns a Descriptor object for the given PHP class name. - */ -PHP_METHOD(DescriptorPool, getDescriptorByClassName) { - char *classname = NULL; - zend_long classname_len; - zend_class_entry *ce; - zend_string *str; - zval ret; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname, - &classname_len) == FAILURE) { - return; - } - - str = zend_string_init(classname, strlen(classname), 0); - ce = zend_lookup_class(str); // May autoload the class. - zend_string_release (str); - - if (!ce) { - RETURN_NULL(); - } - - Descriptor_FromClassEntry(&ret, ce); - RETURN_ZVAL(&ret, 1, 0); -} - -/* - * DescriptorPool::getEnumDescriptorByClassName() - * - * Returns a EnumDescriptor object for the given PHP class name. - */ -PHP_METHOD(DescriptorPool, getEnumDescriptorByClassName) { - char *classname = NULL; - zend_long classname_len; - zend_class_entry *ce; - zend_string *str; - zval ret; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &classname, - &classname_len) == FAILURE) { - return; - } - - str = zend_string_init(classname, strlen(classname), 0); - ce = zend_lookup_class(str); // May autoload the class. - zend_string_release (str); - - if (!ce) { - RETURN_NULL(); - } - - EnumDescriptor_FromClassEntry(&ret, ce); - RETURN_ZVAL(&ret, 1, 0); -} - -/* - * DescriptorPool::getEnumDescriptorByProtoName() - * - * Returns a Descriptor object for the given protobuf message name. - */ -PHP_METHOD(DescriptorPool, getDescriptorByProtoName) { - DescriptorPool *intern = GetPool(getThis()); - char *protoname = NULL; - zend_long protoname_len; - const upb_msgdef *m; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &protoname, - &protoname_len) == FAILURE) { - return; - } - - if (*protoname == '.') protoname++; - - m = upb_symtab_lookupmsg(intern->symtab, protoname); - - if (m) { - zval ret; - ZVAL_OBJ(&ret, &Descriptor_GetFromMessageDef(m)->std); - RETURN_ZVAL(&ret, 1, 0); - } else { - RETURN_NULL(); - } -} - -/* - * depends_on_descriptor() - * - * Returns true if this FileDescriptorProto depends on descriptor.proto. - */ -bool depends_on_descriptor(const google_protobuf_FileDescriptorProto* file) { - const upb_strview *deps; - upb_strview name = upb_strview_makez("google/protobuf/descriptor.proto"); - size_t i, n; - - deps = google_protobuf_FileDescriptorProto_dependency(file, &n); - for (i = 0; i < n; i++) { - if (upb_strview_eql(deps[i], name)) { - return true; - } - } - - return false; -} - -/* - * add_name_mappings() - * - * Adds the messages and enums in this file to the NameMap. - */ -static void add_name_mappings(const upb_filedef *file) { - size_t i; - for (i = 0; i < upb_filedef_msgcount(file); i++) { - NameMap_AddMessage(upb_filedef_msg(file, i)); - } - - for (i = 0; i < upb_filedef_enumcount(file); i++) { - NameMap_AddEnum(upb_filedef_enum(file, i)); - } -} - -/* - * add_name_mappings() - * - * Adds the given descriptor data to this DescriptorPool. - */ -static void add_descriptor(DescriptorPool *pool, const char *data, - int data_len, upb_arena *arena) { - size_t i, n; - google_protobuf_FileDescriptorSet *set; - const google_protobuf_FileDescriptorProto* const* files; - - set = google_protobuf_FileDescriptorSet_parse(data, data_len, arena); - - if (!set) { - zend_error(E_ERROR, "Failed to parse binary descriptor\n"); - return; - } - - files = google_protobuf_FileDescriptorSet_file(set, &n); - - for (i = 0; i < n; i++) { - const google_protobuf_FileDescriptorProto* file = files[i]; - upb_strview name = google_protobuf_FileDescriptorProto_name(file); - upb_status status; - const upb_filedef *file_def; - upb_status_clear(&status); - - if (upb_symtab_lookupfile2(pool->symtab, name.data, name.size)) { - // Already added. - continue; - } - - // The PHP code generator currently special-cases descriptor.proto. It - // doesn't add it as a dependency even if the proto file actually does - // depend on it. - if (depends_on_descriptor(file)) { - google_protobuf_FileDescriptorProto_getmsgdef(pool->symtab); - } - - file_def = upb_symtab_addfile(pool->symtab, file, &status); - CheckUpbStatus(&status, "Unable to load descriptor"); - add_name_mappings(file_def); - } -} - -/* - * DescriptorPool::internalAddGeneratedFile() - * - * Adds the given descriptor data to this DescriptorPool. - */ -PHP_METHOD(DescriptorPool, internalAddGeneratedFile) { - DescriptorPool *intern = GetPool(getThis()); - char *data = NULL; - zend_long data_len; - zend_bool use_nested_submsg = false; - upb_arena *arena; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len, - &use_nested_submsg) != SUCCESS) { - return; - } - - arena = upb_arena_new(); - add_descriptor(intern, data, data_len, arena); - upb_arena_free(arena); -} - -static zend_function_entry DescriptorPool_methods[] = { - PHP_ME(DescriptorPool, getGeneratedPool, NULL, - ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) - PHP_ME(DescriptorPool, getDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(DescriptorPool, getDescriptorByProtoName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(DescriptorPool, getEnumDescriptorByClassName, NULL, ZEND_ACC_PUBLIC) - PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// GPBType -// ----------------------------------------------------------------------------- - -zend_class_entry* gpb_type_type; - -static zend_function_entry gpb_type_methods[] = { - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// Module Init -// ----------------------------------------------------------------------------- - -void Def_ModuleInit() { - zend_class_entry tmp_ce; - zend_object_handlers *h; - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\OneofDescriptor", - OneofDescriptor_methods); - OneofDescriptor_class_entry = zend_register_internal_class(&tmp_ce); - OneofDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; - OneofDescriptor_class_entry->create_object = CreateHandler_ReturnNull; - h = &OneofDescriptor_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumValueDescriptor", - EnumValueDescriptor_methods); - EnumValueDescriptor_class_entry = zend_register_internal_class(&tmp_ce); - EnumValueDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; - EnumValueDescriptor_class_entry->create_object = CreateHandler_ReturnNull; - h = &EnumValueDescriptor_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\EnumDescriptor", - EnumDescriptor_methods); - EnumDescriptor_class_entry = zend_register_internal_class(&tmp_ce); - EnumDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; - EnumDescriptor_class_entry->create_object = CreateHandler_ReturnNull; - h = &EnumDescriptor_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Descriptor", - Descriptor_methods); - - Descriptor_class_entry = zend_register_internal_class(&tmp_ce); - Descriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; - Descriptor_class_entry->create_object = CreateHandler_ReturnNull; - h = &Descriptor_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - h->dtor_obj = Descriptor_destructor; - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\FieldDescriptor", - FieldDescriptor_methods); - FieldDescriptor_class_entry = zend_register_internal_class(&tmp_ce); - FieldDescriptor_class_entry->ce_flags |= ZEND_ACC_FINAL; - FieldDescriptor_class_entry->create_object = CreateHandler_ReturnNull; - h = &FieldDescriptor_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\DescriptorPool", - DescriptorPool_methods); - DescriptorPool_class_entry = zend_register_internal_class(&tmp_ce); - DescriptorPool_class_entry->ce_flags |= ZEND_ACC_FINAL; - DescriptorPool_class_entry->create_object = DescriptorPool_create; - h = &DescriptorPool_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - h->dtor_obj = DescriptorPool_destructor; - - // GPBType. -#define STR(str) (str), strlen(str) - zend_class_entry class_type; - INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\GPBType", - gpb_type_methods); - gpb_type_type = zend_register_internal_class(&class_type); - zend_declare_class_constant_long(gpb_type_type, STR("DOUBLE"), 1); - zend_declare_class_constant_long(gpb_type_type, STR("FLOAT"), 2); - zend_declare_class_constant_long(gpb_type_type, STR("INT64"), 3); - zend_declare_class_constant_long(gpb_type_type, STR("UINT64"), 4); - zend_declare_class_constant_long(gpb_type_type, STR("INT32"), 5); - zend_declare_class_constant_long(gpb_type_type, STR("FIXED64"), 6); - zend_declare_class_constant_long(gpb_type_type, STR("FIXED32"), 7); - zend_declare_class_constant_long(gpb_type_type, STR("BOOL"), 8); - zend_declare_class_constant_long(gpb_type_type, STR("STRING"), 9); - zend_declare_class_constant_long(gpb_type_type, STR("GROUP"), 10); - zend_declare_class_constant_long(gpb_type_type, STR("MESSAGE"), 11); - zend_declare_class_constant_long(gpb_type_type, STR("BYTES"), 12); - zend_declare_class_constant_long(gpb_type_type, STR("UINT32"), 13); - zend_declare_class_constant_long(gpb_type_type, STR("ENUM"), 14); - zend_declare_class_constant_long(gpb_type_type, STR("SFIXED32"), 15); - zend_declare_class_constant_long(gpb_type_type, STR("SFIXED64"), 16); - zend_declare_class_constant_long(gpb_type_type, STR("SINT32"), 17); - zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18); -#undef STR -} diff --git a/php/ext/google/protobuf2/map.c b/php/ext/google/protobuf2/map.c deleted file mode 100644 index 0217c6491e59..000000000000 --- a/php/ext/google/protobuf2/map.c +++ /dev/null @@ -1,590 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#include "map.h" - -#include -#include - -#include - -#include "arena.h" -#include "convert.h" -#include "php-upb.h" -#include "protobuf.h" - -static void MapFieldIter_make(zval *val, zval *map_field); - -// ----------------------------------------------------------------------------- -// MapField -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - zval arena; - upb_map *map; - upb_fieldtype_t key_type; - upb_fieldtype_t val_type; - const Descriptor* desc; // When values are messages. -} MapField; - -zend_class_entry *MapField_class_entry; -static zend_object_handlers MapField_object_handlers; - -// PHP Object Handlers ///////////////////////////////////////////////////////// - -/** - * MapField_create() - * - * PHP class entry function to allocate and initialize a new MapField - * object. - */ -static zend_object* MapField_create(zend_class_entry *class_type) { - MapField *intern = emalloc(sizeof(MapField)); - zend_object_std_init(&intern->std, class_type); - intern->std.handlers = &MapField_object_handlers; - Arena_Init(&intern->arena); - intern->map = NULL; - // Skip object_properties_init(), we don't allow derived classes. - return &intern->std; -} - -/** - * MapField_dtor() - * - * Object handler to destroy a MapField. This releases all resources - * associated with the message. Note that it is possible to access a destroyed - * object from PHP in rare cases. - */ -static void MapField_destructor(zend_object* obj) { - MapField* intern = (MapField*)obj; - ObjCache_Delete(intern->map); - zval_ptr_dtor(&intern->arena); - zend_object_std_dtor(&intern->std); -} - -static zval *Map_GetPropertyPtrPtr(zval *object, zval *member, int type, - void **cache_slot) { - return NULL; // We don't offer direct references to our properties. -} - -static HashTable *map_get_properties(zval *object TSRMLS_DC) { - return NULL; // We do not have a properties table. -} - -// C Functions from map.h ////////////////////////////////////////////////////// - -// These are documented in the header file. - -void MapField_GetPhpWrapper(zval *val, upb_map *map, const upb_fielddef *f, - zval *arena) { - if (!map) { - ZVAL_NULL(val); - return; - } - - if (!ObjCache_Get(map, val)) { - const upb_msgdef *ent = upb_fielddef_msgsubdef(f); - const upb_fielddef *key_f = upb_msgdef_itof(ent, 1); - const upb_fielddef *val_f = upb_msgdef_itof(ent, 2); - MapField *intern = emalloc(sizeof(MapField)); - zend_object_std_init(&intern->std, MapField_class_entry); - intern->std.handlers = &MapField_object_handlers; - ZVAL_COPY(&intern->arena, arena); - intern->map = map; - intern->key_type = upb_fielddef_type(key_f); - intern->val_type = upb_fielddef_type(val_f); - intern->desc = Descriptor_GetFromFieldDef(val_f); - // Skip object_properties_init(), we don't allow derived classes. - ObjCache_Add(intern->map, &intern->std); - ZVAL_OBJ(val, &intern->std); - } -} - -upb_map *MapField_GetUpbMap(zval *val, const upb_fielddef *f, upb_arena *arena) { - const upb_msgdef *ent = upb_fielddef_msgsubdef(f); - const upb_fielddef *key_f = upb_msgdef_itof(ent, 1); - const upb_fielddef *val_f = upb_msgdef_itof(ent, 2); - upb_fieldtype_t key_type = upb_fielddef_type(key_f); - upb_fieldtype_t val_type = upb_fielddef_type(val_f); - const Descriptor *desc = Descriptor_GetFromFieldDef(val_f); - - if (Z_ISREF_P(val)) { - ZVAL_DEREF(val); - } - - if (Z_TYPE_P(val) == IS_ARRAY) { - upb_map *map = upb_map_new(arena, key_type, val_type); - HashTable *table = HASH_OF(val); - HashPosition pos; - - zend_hash_internal_pointer_reset_ex(table, &pos); - - while (true) { - zval php_key; - zval *php_val; - upb_msgval upb_key; - upb_msgval upb_val; - - zend_hash_get_current_key_zval_ex(table, &php_key, &pos); - php_val = zend_hash_get_current_data_ex(table, &pos); - - if (!php_val) return map; - - if (!Convert_PhpToUpb(&php_key, &upb_key, key_type, NULL, arena) || - !Convert_PhpToUpbAutoWrap(php_val, &upb_val, val_type, desc, arena)) { - return NULL; - } - - upb_map_set(map, upb_key, upb_val, arena); - zend_hash_move_forward_ex(table, &pos); - zval_dtor(&php_key); - } - } else if (Z_TYPE_P(val) == IS_OBJECT && - Z_OBJCE_P(val) == MapField_class_entry) { - MapField *intern = (MapField*)Z_OBJ_P(val); - - if (intern->key_type != key_type || intern->val_type != val_type || - intern->desc != desc) { - php_error_docref(NULL, E_USER_ERROR, "Wrong type for this map field."); - return NULL; - } - - upb_arena_fuse(arena, Arena_Get(&intern->arena)); - return intern->map; - } else { - php_error_docref(NULL, E_USER_ERROR, "Must be a map"); - return NULL; - } -} - -// MapField PHP methods //////////////////////////////////////////////////////// - -/** - * MapField::__construct() - * - * Constructs an instance of MapField. - * @param long Key type. - * @param long Value type. - * @param string Message/Enum class (message/enum value types only). - */ -PHP_METHOD(MapField, __construct) { - MapField *intern = (MapField*)Z_OBJ_P(getThis()); - upb_arena *arena = Arena_Get(&intern->arena); - zend_long key_type, val_type; - zend_class_entry* klass = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|C", &key_type, &val_type, - &klass) != SUCCESS) { - return; - } - - intern->key_type = pbphp_dtype_to_type(key_type); - intern->val_type = pbphp_dtype_to_type(val_type); - intern->desc = Descriptor_GetFromClassEntry(klass); - - // Check that the key type is an allowed type. - switch (intern->key_type) { - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - case UPB_TYPE_BOOL: - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - // These are OK. - break; - default: - zend_error(E_USER_ERROR, "Invalid key type for map."); - } - - if (intern->val_type == UPB_TYPE_MESSAGE && klass == NULL) { - php_error_docref(NULL, E_USER_ERROR, - "Message/enum type must have concrete class."); - return; - } - - intern->map = upb_map_new(arena, intern->key_type, intern->val_type); - ObjCache_Add(intern->map, &intern->std); -} - -/** - * MapField::offsetExists() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * isset($map[$idx]); - * empty($map[$idx]); - * - * @param long The index to be checked. - * @return bool True if the element at the given index exists. - */ -PHP_METHOD(MapField, offsetExists) { - MapField *intern = (MapField*)Z_OBJ_P(getThis()); - zval *key; - upb_msgval upb_key; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS || - !Convert_PhpToUpb(key, &upb_key, intern->key_type, intern->desc, NULL)) { - return; - } - - RETURN_BOOL(upb_map_get(intern->map, upb_key, NULL)); -} - -/** - * MapField::offsetGet() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * $x = $map[$idx]; - * - * @param long The index of the element to be fetched. - * @return object The stored element at given index. - * @exception Invalid type for index. - * @exception Non-existing index. - */ -PHP_METHOD(MapField, offsetGet) { - MapField *intern = (MapField*)Z_OBJ_P(getThis()); - zval *key; - zval ret; - upb_msgval upb_key, upb_val; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS || - !Convert_PhpToUpb(key, &upb_key, intern->key_type, intern->desc, NULL)) { - return; - } - - if (!upb_map_get(intern->map, upb_key, &upb_val)) { - zend_error(E_USER_ERROR, "Given key doesn't exist."); - return; - } - - Convert_UpbToPhp(upb_val, &ret, intern->val_type, intern->desc, &intern->arena); - RETURN_ZVAL(&ret, 0, 1); -} - -/** - * MapField::offsetSet() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * $map[$idx] = $x; - * - * @param long The index of the element to be assigned. - * @param object The element to be assigned. - * @exception Invalid type for index. - * @exception Non-existing index. - * @exception Incorrect type of the element. - */ -PHP_METHOD(MapField, offsetSet) { - MapField *intern = (MapField*)Z_OBJ_P(getThis()); - upb_arena *arena = Arena_Get(&intern->arena); - zval *key, *val; - upb_msgval upb_key, upb_val; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &key, &val) != SUCCESS || - !Convert_PhpToUpb(key, &upb_key, intern->key_type, NULL, NULL) || - !Convert_PhpToUpb(val, &upb_val, intern->val_type, intern->desc, arena)) { - return; - } - - upb_map_set(intern->map, upb_key, upb_val, arena); -} - -/** - * MapField::offsetUnset() - * - * Implements the ArrayAccess interface. Invoked when PHP code calls: - * - * unset($map[$idx]); - * - * @param long The index of the element to be removed. - * @exception Invalid type for index. - * @exception The element to be removed is not at the end of the MapField. - */ -PHP_METHOD(MapField, offsetUnset) { - MapField *intern = (MapField*)Z_OBJ_P(getThis()); - zval *key; - upb_msgval upb_key; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &key) != SUCCESS || - !Convert_PhpToUpb(key, &upb_key, intern->key_type, NULL, NULL)) { - return; - } - - upb_map_delete(intern->map, upb_key); -} - -/** - * MapField::count() - * - * Implements the Countable interface. Invoked when PHP code calls: - * - * $len = count($map); - * Return the number of stored elements. - * This will also be called for: count($map) - * @return long The number of stored elements. - */ -PHP_METHOD(MapField, count) { - MapField *intern = (MapField*)Z_OBJ_P(getThis()); - - if (zend_parse_parameters_none() == FAILURE) { - return; - } - - RETURN_LONG(upb_map_size(intern->map)); -} - -/** - * MapField::getIterator() - * - * Implements the IteratorAggregate interface. Invoked when PHP code calls: - * - * foreach ($arr) {} - * - * @return object Beginning iterator. - */ -PHP_METHOD(MapField, getIterator) { - zval ret; - MapFieldIter_make(&ret, getThis()); - RETURN_ZVAL(&ret, 0, 1); -} - -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetGet, 0, 0, 1) - ZEND_ARG_INFO(0, index) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_offsetSet, 0, 0, 2) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, newval) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_void, 0) -ZEND_END_ARG_INFO() - -static zend_function_entry MapField_methods[] = { - PHP_ME(MapField, __construct, NULL, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetExists, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetGet, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) - PHP_ME(MapField, count, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(MapField, getIterator, arginfo_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// MapFieldIter -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - zval map_field; - size_t position; -} MapFieldIter; - -zend_class_entry *MapFieldIter_class_entry; -static zend_object_handlers MapFieldIter_object_handlers; - -/** - * MapFieldIter_create() - * - * PHP class entry function to allocate and initialize a new MapFieldIter - * object. - */ -zend_object* MapFieldIter_create(zend_class_entry *class_type) { - MapFieldIter *intern = emalloc(sizeof(MapFieldIter)); - zend_object_std_init(&intern->std, class_type); - intern->std.handlers = &MapFieldIter_object_handlers; - ZVAL_NULL(&intern->map_field); - intern->position = 0; - // Skip object_properties_init(), we don't allow derived classes. - return &intern->std; -} - -/** - * MapFieldIter_dtor() - * - * Object handler to destroy a MapFieldIter. This releases all resources - * associated with the message. Note that it is possible to access a destroyed - * object from PHP in rare cases. - */ -static void map_field_iter_dtor(zend_object* obj) { - MapFieldIter* intern = (MapFieldIter*)obj; - zval_ptr_dtor(&intern->map_field); - zend_object_std_dtor(&intern->std); -} - -/** - * MapFieldIter_make() - * - * Function to create a MapFieldIter directly from C. - */ -static void MapFieldIter_make(zval *val, zval *map_field) { - MapFieldIter *iter; - ZVAL_OBJ(val, - MapFieldIter_class_entry->create_object(MapFieldIter_class_entry)); - iter = (MapFieldIter*)Z_OBJ_P(val); - ZVAL_COPY(&iter->map_field, map_field); -} - -// ----------------------------------------------------------------------------- -// PHP MapFieldIter Methods -// ----------------------------------------------------------------------------- - -/* - * When a user writes: - * - * foreach($arr as $key => $val) {} - * - * PHP translates this into: - * - * $iter = $arr->getIterator(); - * for ($iter->rewind(); $iter->valid(); $iter->next()) { - * $key = $iter->key(); - * $val = $iter->current(); - * } - */ - -/** - * MapFieldIter::rewind() - * - * Implements the Iterator interface. Sets the iterator to the first element. - */ -PHP_METHOD(MapFieldIter, rewind) { - MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); - MapField *map_field = (MapField*)Z_OBJ_P(&intern->map_field); - intern->position = UPB_MAP_BEGIN; - upb_mapiter_next(map_field->map, &intern->position); -} - -/** - * MapFieldIter::current() - * - * Implements the Iterator interface. Returns the current value. - */ -PHP_METHOD(MapFieldIter, current) { - MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); - MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); - upb_msgval upb_val = upb_mapiter_value(field->map, intern->position); - zval ret; - Convert_UpbToPhp(upb_val, &ret, field->val_type, field->desc, &field->arena); - RETURN_ZVAL(&ret, 0, 1); -} - -/** - * MapFieldIter::key() - * - * Implements the Iterator interface. Returns the current key. - */ -PHP_METHOD(MapFieldIter, key) { - MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); - MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); - upb_msgval upb_key = upb_mapiter_key(field->map, intern->position); - zval ret; - Convert_UpbToPhp(upb_key, &ret, field->key_type, NULL, NULL); - RETURN_ZVAL(&ret, 0, 1); -} - -/** - * MapFieldIter::next() - * - * Implements the Iterator interface. Advances to the next element. - */ -PHP_METHOD(MapFieldIter, next) { - MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); - MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); - upb_mapiter_next(field->map, &intern->position); -} - -/** - * MapFieldIter::valid() - * - * Implements the Iterator interface. Returns true if this is a valid element. - */ -PHP_METHOD(MapFieldIter, valid) { - MapFieldIter *intern = (MapFieldIter*)Z_OBJ_P(getThis()); - MapField *field = (MapField*)Z_OBJ_P(&intern->map_field); - bool done = upb_mapiter_done(field->map, intern->position); - RETURN_BOOL(!done); -} - -static zend_function_entry map_field_iter_methods[] = { - PHP_ME(MapFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(MapFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(MapFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(MapFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC) - PHP_ME(MapFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC) - ZEND_FE_END -}; - -// ----------------------------------------------------------------------------- -// Module init. -// ----------------------------------------------------------------------------- - -/** - * Map_ModuleInit() - * - * Called when the C extension is loaded to register all types. - */ - -void Map_ModuleInit() { - zend_class_entry tmp_ce; - zend_object_handlers *h; - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\MapField", - MapField_methods); - - MapField_class_entry = zend_register_internal_class(&tmp_ce); - zend_class_implements(MapField_class_entry, 3, spl_ce_ArrayAccess, - zend_ce_aggregate, spl_ce_Countable); - MapField_class_entry->ce_flags |= ZEND_ACC_FINAL; - MapField_class_entry->create_object = MapField_create; - - h = &MapField_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - h->dtor_obj = MapField_destructor; - h->get_properties = map_get_properties; - h->get_property_ptr_ptr = Map_GetPropertyPtrPtr; - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\MapFieldIter", - map_field_iter_methods); - - MapFieldIter_class_entry = zend_register_internal_class(&tmp_ce); - zend_class_implements(MapFieldIter_class_entry, 1, zend_ce_iterator); - MapFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL; - MapFieldIter_class_entry->ce_flags |= ZEND_ACC_FINAL; - MapFieldIter_class_entry->create_object = MapFieldIter_create; - - h = &MapFieldIter_object_handlers; - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - h->dtor_obj = map_field_iter_dtor; -} diff --git a/php/ext/google/protobuf2/message.c b/php/ext/google/protobuf2/message.c deleted file mode 100644 index 20dd37a76e05..000000000000 --- a/php/ext/google/protobuf2/message.c +++ /dev/null @@ -1,841 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2014 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#include "message.h" - -#include -#include -#include - -// This is not self-contained: it must be after other Zend includes. -#include - -#include "arena.h" -#include "array.h" -#include "convert.h" -#include "def.h" -#include "map.h" -#include "php-upb.h" -#include "protobuf.h" - -// ----------------------------------------------------------------------------- -// Message -// ----------------------------------------------------------------------------- - -typedef struct { - zend_object std; - zval arena; - const Descriptor* desc; - upb_msg *msg; -} Message; - -zend_class_entry *message_ce; -static zend_object_handlers message_object_handlers; - -// PHP Object Handlers ///////////////////////////////////////////////////////// - -/** - * Message_create() - * - * PHP class entry function to allocate and initialize a new Message object. - */ -static zend_object* Message_create(zend_class_entry *class_type) { - Message *intern = emalloc(sizeof(Message)); - // XXX(haberman): verify whether we actually want to take this route. - class_type->default_properties_count = 0; - zend_object_std_init(&intern->std, class_type); - intern->std.handlers = &message_object_handlers; - Arena_Init(&intern->arena); - return &intern->std; -} - -/** - * Message_dtor() - * - * Object handler to destroy a Message. This releases all resources associated - * with the message. Note that it is possible to access a destroyed object from - * PHP in rare cases. - */ -static void Message_dtor(zend_object* obj) { - Message* intern = (Message*)obj; - ObjCache_Delete(intern->msg); - zval_dtor(&intern->arena); - zend_object_std_dtor(&intern->std); -} - -/** - * get_field() - * - * Helper function to look up a field given a member name (as a string). - */ -static const upb_fielddef *get_field(Message *msg, zval *member) { - const upb_msgdef *m = msg->desc->msgdef; - const upb_fielddef *f = - upb_msgdef_ntof(m, Z_STRVAL_P(member), Z_STRLEN_P(member)); - - if (!f) { - zend_throw_exception_ex(NULL, 0, "No such property %s.", - ZSTR_VAL(msg->desc->class_entry->name)); - } - - return f; -} - -/** - * Message_read_property() - * - * Object handler for reading a property in PHP. Called when PHP code does: - * - * $x = $message->foobar; - * - * Note that all properties of generated messages are private, so this should - * only be possible to invoke from generated code, which has accessors like: - * - * public function getOptionalInt32() - * { - * return $this->optional_int32; - * } - * - * We lookup the field and return the scalar, RepeatedField, or MapField for - * this field. - */ -static zval *Message_read_property(zval *obj, zval *member, int type, - void **cache_slot, zval *rv) { - Message* intern = (Message*)Z_OBJ_P(obj); - const upb_fielddef *f = get_field(intern, member); - upb_arena *arena = Arena_Get(&intern->arena); - - if (!f) return NULL; - - if (upb_fielddef_ismap(f)) { - upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena); - MapField_GetPhpWrapper(rv, msgval.map, f, &intern->arena); - } else if (upb_fielddef_isseq(f)) { - upb_mutmsgval msgval = upb_msg_mutable(intern->msg, f, arena); - RepeatedField_GetPhpWrapper(rv, msgval.array, f, &intern->arena); - } else { - upb_msgval msgval = upb_msg_get(intern->msg, f); - const Descriptor *subdesc = Descriptor_GetFromFieldDef(f); - Convert_UpbToPhp(msgval, rv, upb_fielddef_type(f), subdesc, &intern->arena); - } - - return rv; -} - -/** - * Message_write_property() - * - * Object handler for writing a property in PHP. Called when PHP code does: - * - * $message->foobar = $x; - * - * Note that all properties of generated messages are private, so this should - * only be possible to invoke from generated code, which has accessors like: - * - * public function setOptionalInt32($var) - * { - * GPBUtil::checkInt32($var); - * $this->optional_int32 = $var; - * - * return $this; - * } - * - * The C extension version of checkInt32() doesn't actually check anything, so - * we perform all checking and conversion in this function. - */ -static void Message_write_property(zval *obj, zval *member, zval *val, - void **cache_slot) { - Message* intern = (Message*)Z_OBJ_P(obj); - const upb_fielddef *f = get_field(intern, member); - upb_arena *arena = Arena_Get(&intern->arena); - upb_msgval msgval; - - if (!f) return; - - if (upb_fielddef_ismap(f)) { - msgval.map_val = MapField_GetUpbMap(val, f, arena); - if (!msgval.map_val) return; - } else if (upb_fielddef_isseq(f)) { - msgval.array_val = RepeatedField_GetUpbArray(val, f, arena); - if (!msgval.array_val) return; - } else { - upb_fieldtype_t type = upb_fielddef_type(f); - const Descriptor *subdesc = Descriptor_GetFromFieldDef(f); - bool ok = Convert_PhpToUpb(val, &msgval, type, subdesc, arena); - if (!ok) return; - } - - upb_msg_set(intern->msg, f, msgval, arena); -} - -/** - * Message_get_property_ptr_ptr() - * - * Object handler for the get_property_ptr_ptr event in PHP. This returns a - * reference to our internal properties. We don't support this, so we return - * NULL. - */ -static zval *Message_get_property_ptr_ptr(zval *object, zval *member, int type, - void **cache_slot) { - return NULL; // We do not have a properties table. -} - -/** - * Message_get_properties() - * - * Object handler for the get_properties event in PHP. This returns a HashTable - * of our internal properties. We don't support this, so we return NULL. - */ -static HashTable* Message_get_properties(zval* object TSRMLS_DC) { - return NULL; // We don't offer direct references to our properties. -} - -// C Functions from message.h. ///////////////////////////////////////////////// - -// These are documented in the header file. - -void Message_GetPhpWrapper(zval *val, const Descriptor *desc, upb_msg *msg, - zval *arena) { - if (!msg) { - ZVAL_NULL(val); - return; - } - - if (!ObjCache_Get(msg, val)) { - Message *intern = emalloc(sizeof(Message)); - // XXX(haberman): verify whether we actually want to take this route. - desc->class_entry->default_properties_count = 0; - zend_object_std_init(&intern->std, desc->class_entry); - intern->std.handlers = &message_object_handlers; - ZVAL_COPY(&intern->arena, arena); - intern->desc = desc; - intern->msg = msg; - ZVAL_OBJ(val, &intern->std); - ObjCache_Add(intern->msg, &intern->std); - } -} - -bool Message_GetUpbMessage(zval *val, const Descriptor *desc, upb_arena *arena, - upb_msg **msg) { - PBPHP_ASSERT(desc); - - if (Z_ISREF_P(val)) { - ZVAL_DEREF(val); - } - - if (Z_TYPE_P(val) == IS_NULL) { - *msg = NULL; - return true; - } - - if (Z_TYPE_P(val) == IS_OBJECT && - instanceof_function(Z_OBJCE_P(val), desc->class_entry)) { - Message *intern = (Message*)Z_OBJ_P(val); - upb_arena_fuse(arena, Arena_Get(&intern->arena)); - *msg = intern->msg; - return true; - } else { - zend_throw_exception_ex(NULL, 0, "Given value is not an instance of %s.", - ZSTR_VAL(desc->class_entry->name)); - return false; - } -} - -// Message PHP methods ///////////////////////////////////////////////////////// - -/** - * Message_InitFromPhp() - * - * Helper method to handle the initialization of a message from a PHP value, eg. - * - * $m = new TestMessage([ - * 'optional_int32' => -42, - * 'optional_bool' => true, - * 'optional_string' => 'a', - * 'optional_enum' => TestEnum::ONE, - * 'optional_message' => new Sub([ - * 'a' => 33 - * ]), - * 'repeated_int32' => [-42, -52], - * 'repeated_enum' => [TestEnum::ZERO, TestEnum::ONE], - * 'repeated_message' => [new Sub(['a' => 34]), - * new Sub(['a' => 35])], - * 'map_int32_int32' => [-62 => -62], - * 'map_int32_enum' => [1 => TestEnum::ONE], - * 'map_int32_message' => [1 => new Sub(['a' => 36])], - * ]); - * - * The initializer must be an array. - */ -bool Message_InitFromPhp(upb_msg *msg, const upb_msgdef *m, zval *init, - upb_arena *arena) { - HashTable* table = HASH_OF(init); - HashPosition pos; - - if (Z_ISREF_P(init)) { - ZVAL_DEREF(init); - } - - if (Z_TYPE_P(init) != IS_ARRAY) { - zend_throw_exception_ex(NULL, 0, - "Initializer for a message %s must be an array.", - upb_msgdef_fullname(m)); - return false; - } - - zend_hash_internal_pointer_reset_ex(table, &pos); - - while (true) { // Iterate over key/value pairs. - zval key; - zval *val; - const upb_fielddef *f; - upb_msgval msgval; - - zend_hash_get_current_key_zval_ex(table, &key, &pos); - val = zend_hash_get_current_data_ex(table, &pos); - - if (!val) return true; // Finished iteration. - - if (Z_ISREF_P(val)) { - ZVAL_DEREF(val); - } - - f = upb_msgdef_ntof(m, Z_STRVAL_P(&key), Z_STRLEN_P(&key)); - - if (!f) { - zend_throw_exception_ex(NULL, 0, - "No such field %s", Z_STRVAL_P(&key)); - return false; - } - - if (upb_fielddef_ismap(f)) { - msgval.map_val = MapField_GetUpbMap(val, f, arena); - if (!msgval.map_val) return false; - } else if (upb_fielddef_isseq(f)) { - msgval.array_val = RepeatedField_GetUpbArray(val, f, arena); - if (!msgval.array_val) return false; - } else { - const Descriptor *desc = Descriptor_GetFromFieldDef(f); - upb_fieldtype_t type = upb_fielddef_type(f); - if (!Convert_PhpToUpbAutoWrap(val, &msgval, type, desc, arena)) { - return false; - } - } - - upb_msg_set(msg, f, msgval, arena); - zend_hash_move_forward_ex(table, &pos); - zval_dtor(&key); - } -} - -/** - * Message::__construct() - * - * Constructor for Message. - * @param array Map of initial values ['k' = val] - */ -PHP_METHOD(Message, __construct) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - const Descriptor* desc = Descriptor_GetFromClassEntry(Z_OBJCE_P(getThis())); - const upb_msgdef *msgdef = desc->msgdef; - upb_arena *arena = Arena_Get(&intern->arena); - zval *init_arr = NULL; - - intern->desc = desc; - intern->msg = upb_msg_new(msgdef, arena); - ObjCache_Add(intern->msg, &intern->std); - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &init_arr) == FAILURE) { - return; - } - - if (init_arr) { - Message_InitFromPhp(intern->msg, desc->msgdef, init_arr, arena); - } -} - -/** - * Message::discardUnknownFields() - * - * Discards any unknown fields for this message or any submessages. - */ -PHP_METHOD(Message, discardUnknownFields) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - upb_msg_discardunknown(intern->msg, intern->desc->msgdef, 64); -} - -/** - * Message::clear() - * - * Clears all fields of this message. - */ -PHP_METHOD(Message, clear) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - upb_msg_clear(intern->msg, intern->desc->msgdef); -} - -/** - * Message::mergeFrom() - * - * Merges from the given message, which must be of the same class as us. - * @param object Message to merge from. - */ -PHP_METHOD(Message, mergeFrom) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - Message* from; - upb_arena *arena = Arena_Get(&intern->arena); - const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef); - zval* value; - char *pb; - size_t size; - bool ok; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &value, - intern->desc->class_entry) == FAILURE) { - return; - } - - from = (Message*)Z_OBJ_P(value); - - // Should be guaranteed since we passed the class type to - // zend_parse_parameters(). - PBPHP_ASSERT(from->desc == intern->desc); - - // TODO(haberman): use a temp arena for this once we can make upb_decode() - // copy strings. - pb = upb_encode(from->msg, l, arena, &size); - - if (!pb) { - zend_throw_exception_ex(NULL, 0, "Max nesting exceeded"); - return; - } - - ok = upb_decode(pb, size, intern->msg, l, arena); - PBPHP_ASSERT(ok); -} - -/** - * Message::mergeFromString() - * - * Merges from the given string. - * @param string Binary protobuf data to merge. - */ -PHP_METHOD(Message, mergeFromString) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - char *data = NULL; - char *data_copy = NULL; - zend_long data_len; - const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef); - upb_arena *arena = Arena_Get(&intern->arena); - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data, &data_len) == - FAILURE) { - return; - } - - // TODO(haberman): avoid this copy when we can make the decoder copy. - data_copy = upb_arena_malloc(arena, data_len); - memcpy(data_copy, data, data_len); - - if (!upb_decode(data_copy, data_len, intern->msg, l, arena)) { - zend_throw_exception_ex(NULL, 0, "Error occurred during parsing"); - return; - } -} - -/** - * Message::serializeToString() - * - * Serializes this message instance to protobuf data. - * @return string Serialized protobuf data. - */ -PHP_METHOD(Message, serializeToString) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - const upb_msglayout *l = upb_msgdef_layout(intern->desc->msgdef); - upb_arena *tmp_arena = upb_arena_new(); - char *data; - size_t size; - - data = upb_encode(intern->msg, l, tmp_arena, &size); - - if (!data) { - zend_throw_exception_ex(NULL, 0, "Error occurred during serialization"); - upb_arena_free(tmp_arena); - return; - } - - RETVAL_STRINGL(data, size); - upb_arena_free(tmp_arena); -} - -/** - * Message::mergeFromJsonString() - * - * Merges the JSON data parsed from the given string. - * @param string Serialized JSON data. - */ -PHP_METHOD(Message, mergeFromJsonString) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - char *data = NULL; - char *data_copy = NULL; - zend_long data_len; - upb_arena *arena = Arena_Get(&intern->arena); - upb_status status; - zend_bool ignore_json_unknown = false; - int options = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|b", &data, &data_len, - &ignore_json_unknown) == FAILURE) { - return; - } - - // TODO(haberman): avoid this copy when we can make the decoder copy. - data_copy = upb_arena_malloc(arena, data_len + 1); - memcpy(data_copy, data, data_len); - data_copy[data_len] = '\0'; - - if (ignore_json_unknown) { - options |= UPB_JSONDEC_IGNOREUNKNOWN; - } - - upb_status_clear(&status); - if (!upb_json_decode(data_copy, data_len, intern->msg, intern->desc->msgdef, - DescriptorPool_GetSymbolTable(), options, arena, - &status)) { - zend_throw_exception_ex(NULL, 0, "Error occurred during parsing: %s", - upb_status_errmsg(&status)); - return; - } -} - -/** - * Message::serializeToJsonString() - * - * Serializes this object to JSON. - * @return string Serialized JSON data. - */ -PHP_METHOD(Message, serializeToJsonString) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - size_t size; - int options = 0; - char buf[1024]; - zend_bool preserve_proto_fieldnames = false; - upb_status status; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", - &preserve_proto_fieldnames) == FAILURE) { - return; - } - - if (preserve_proto_fieldnames) { - options |= UPB_JSONENC_PROTONAMES; - } - - upb_status_clear(&status); - size = upb_json_encode(intern->msg, intern->desc->msgdef, - DescriptorPool_GetSymbolTable(), options, buf, - sizeof(buf), &status); - - if (!upb_ok(&status)) { - zend_throw_exception_ex(NULL, 0, - "Error occurred during JSON serialization: %s", - upb_status_errmsg(&status)); - return; - } - - if (size >= sizeof(buf)) { - char *buf2 = malloc(size + 1); - upb_json_encode(intern->msg, intern->desc->msgdef, - DescriptorPool_GetSymbolTable(), options, buf2, size + 1, - &status); - RETVAL_STRINGL(buf2, size); - free(buf2); - } else { - RETVAL_STRINGL(buf, size); - } -} - -/** - * Message::readWrapperValue() - * - * Returns an unboxed value for the given field. This is called from generated - * methods for wrapper fields, eg. - * - * public function getDoubleValueUnwrapped() - * { - * return $this->readWrapperValue("double_value"); - * } - * - * @return Unwrapped field value or null. - */ -PHP_METHOD(Message, readWrapperValue) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - char* member; - const upb_fielddef *f; - zend_long size; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &member, &size) == FAILURE) { - return; - } - - f = upb_msgdef_ntof(intern->desc->msgdef, member, size); - - if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) { - zend_throw_exception_ex(NULL, 0, "Message %s has no field %s", - upb_msgdef_fullname(intern->desc->msgdef), member); - return; - } - - if (upb_msg_has(intern->msg, f)) { - const upb_msg *wrapper = upb_msg_get(intern->msg, f).msg_val; - const upb_msgdef *m = upb_fielddef_msgsubdef(f); - const upb_fielddef *val_f = upb_msgdef_itof(m, 1); - const upb_fieldtype_t val_type = upb_fielddef_type(val_f); - upb_msgval msgval = upb_msg_get(wrapper, val_f); - zval ret; - Convert_UpbToPhp(msgval, &ret, val_type, NULL, &intern->arena); - RETURN_ZVAL(&ret, 1, 0); - } else { - RETURN_NULL(); - } -} - -/** - * Message::writeWrapperValue() - * - * Sets the given wrapper field to the given unboxed value. This is called from - * generated methods for wrapper fields, eg. - * - * - * public function setDoubleValueUnwrapped($var) - * { - * $this->writeWrapperValue("double_value", $var); - * return $this; - * } - * - * @param Unwrapped field value or null. - */ -PHP_METHOD(Message, writeWrapperValue) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - upb_arena *arena = Arena_Get(&intern->arena); - char* member; - const upb_fielddef *f; - upb_msgval msgval; - zend_long size; - zval* val; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &member, &size, &val) == - FAILURE) { - return; - } - - f = upb_msgdef_ntof(intern->desc->msgdef, member, size); - - if (!f || !upb_msgdef_iswrapper(upb_fielddef_msgsubdef(f))) { - zend_throw_exception_ex(NULL, 0, "Message %s has no field %s", - upb_msgdef_fullname(intern->desc->msgdef), member); - return; - } - - if (Z_ISREF_P(val)) { - ZVAL_DEREF(val); - } - - if (Z_TYPE_P(val) == IS_NULL) { - upb_msg_clearfield(intern->msg, f); - } else { - const upb_msgdef *m = upb_fielddef_msgsubdef(f); - const upb_fielddef *val_f = upb_msgdef_itof(m, 1); - upb_fieldtype_t val_type = upb_fielddef_type(val_f); - upb_msg *wrapper; - - if (!Convert_PhpToUpb(val, &msgval, val_type, NULL, arena)) { - return; // Error is already set. - } - - wrapper = upb_msg_mutable(intern->msg, f, arena).msg; - upb_msg_set(wrapper, val_f, msgval, arena); - } -} - -/** - * Message::whichOneof() - * - * Given a oneof name, returns the name of the field that is set for this oneof, - * or otherwise the empty string. - * - * @return string The field name in this oneof that is currently set. - */ -PHP_METHOD(Message, whichOneof) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - const upb_oneofdef* oneof; - const upb_fielddef* field; - char* name; - zend_long len; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &len) == FAILURE) { - return; - } - - oneof = upb_msgdef_ntoo(intern->desc->msgdef, name, len); - - if (!oneof) { - zend_throw_exception_ex(NULL, 0, "Message %s has no oneof %s", - upb_msgdef_fullname(intern->desc->msgdef), name); - return; - } - - field = upb_msg_whichoneof(intern->msg, oneof); - RETURN_STRING(field ? upb_fielddef_name(field) : ""); -} - -/** - * Message::readOneof() - * - * Returns the contents of the given oneof field, given a field number. Called - * from generated code methods such as: - * - * public function getDoubleValueOneof() - * { - * return $this->readOneof(10); - * } - * - * @return object The oneof's field value. - */ -PHP_METHOD(Message, readOneof) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - zend_long field_num; - const upb_fielddef* f; - zval ret; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &field_num) == FAILURE) { - return; - } - - f = upb_msgdef_itof(intern->desc->msgdef, field_num); - - if (!f || !upb_fielddef_realcontainingoneof(f)) { - php_error_docref(NULL, E_USER_ERROR, - "Internal error, no such oneof field %d\n", - (int)field_num); - } - - { - upb_msgval msgval = upb_msg_get(intern->msg, f); - const Descriptor *subdesc = Descriptor_GetFromFieldDef(f); - Convert_UpbToPhp(msgval, &ret, upb_fielddef_type(f), subdesc, - &intern->arena); - } - - RETURN_ZVAL(&ret, 1, 0); -} - -/** - * Message::writeOneof() - * - * Sets the contents of the given oneof field, given a field number. Called - * from generated code methods such as: - * - * public function setDoubleValueOneof($var) - * { - * GPBUtil::checkMessage($var, \Google\Protobuf\DoubleValue::class); - * $this->writeOneof(10, $var); - * - * return $this; - * } - * - * The C extension version of GPBUtil::check*() does nothing, so we perform - * all type checking and conversion here. - * - * @param integer The field number we are setting. - * @param object The field value we want to set. - */ -PHP_METHOD(Message, writeOneof) { - Message* intern = (Message*)Z_OBJ_P(getThis()); - zend_long field_num; - const upb_fielddef* f; - upb_arena *arena = Arena_Get(&intern->arena); - upb_msgval msgval; - zval* val; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &field_num, &val) == - FAILURE) { - return; - } - - f = upb_msgdef_itof(intern->desc->msgdef, field_num); - - if (!Convert_PhpToUpb(val, &msgval, upb_fielddef_type(f), - Descriptor_GetFromFieldDef(f), arena)) { - return; - } - - upb_msg_set(intern->msg, f, msgval, arena); -} - -static zend_function_entry Message_methods[] = { - PHP_ME(Message, clear, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, discardUnknownFields, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, serializeToString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, mergeFromString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, serializeToJsonString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, mergeFromJsonString, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, mergeFrom, NULL, ZEND_ACC_PUBLIC) - PHP_ME(Message, readWrapperValue, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, writeWrapperValue, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, readOneof, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, writeOneof, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, whichOneof, NULL, ZEND_ACC_PROTECTED) - PHP_ME(Message, __construct, NULL, ZEND_ACC_PROTECTED) - ZEND_FE_END -}; - -/** - * Message_ModuleInit() - * - * Called when the C extension is loaded to register all types. - */ -void Message_ModuleInit() { - zend_class_entry tmp_ce; - zend_object_handlers *h = &message_object_handlers; - - INIT_CLASS_ENTRY(tmp_ce, "Google\\Protobuf\\Internal\\Message", - Message_methods); - - message_ce = zend_register_internal_class(&tmp_ce); - message_ce->create_object = Message_create; - - memcpy(h, &std_object_handlers, sizeof(zend_object_handlers)); - h->dtor_obj = Message_dtor; - h->read_property = Message_read_property; - h->write_property = Message_write_property; - h->get_properties = Message_get_properties; - h->get_property_ptr_ptr = Message_get_property_ptr_ptr; -} diff --git a/php/ext/google/protobuf2/protobuf.c b/php/ext/google/protobuf2/protobuf.c deleted file mode 100644 index 15c8f9bd72e9..000000000000 --- a/php/ext/google/protobuf2/protobuf.c +++ /dev/null @@ -1,349 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#include "protobuf.h" - -#include -#include - -#include "arena.h" -#include "array.h" -#include "bundled_php.h" -#include "convert.h" -#include "def.h" -#include "map.h" -#include "message.h" -#include "names.h" - -// ----------------------------------------------------------------------------- -// Module "globals" -// ----------------------------------------------------------------------------- - -// Despite the name, module "globals" are really thread-locals: -// * PROTOBUF_G(var) accesses the thread-local variable for 'var'. Either: -// * PROTOBUF_G(var) -> protobuf_globals.var (Non-ZTS / non-thread-safe) -// * PROTOBUF_G(var) -> (ZTS / thread-safe builds) - -#define PROTOBUF_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(protobuf, v) - -ZEND_BEGIN_MODULE_GLOBALS(protobuf) - // Set by the user to make the descriptor pool persist between requests. - zend_bool keep_descriptor_pool_after_request; - - // Currently we make the generated pool a "global", which means that if a user - // does explicitly create threads within their request, the other threads will - // get different results from DescriptorPool::getGeneratedPool(). We require - // that all descriptors are loaded from the main thread. - zval generated_pool; - - // A upb_symtab that we are saving for the next request so that we don't have - // to rebuild it from scratch. When keep_descriptor_pool_after_request==true, - // we steal the upb_symtab from the global DescriptorPool object just before - // destroying it. - upb_symtab *saved_symtab; - - // Object cache (see interface in protobuf.h). - HashTable object_cache; - - // Name cache (see interface in protobuf.h). - HashTable name_msg_cache; - HashTable name_enum_cache; -ZEND_END_MODULE_GLOBALS(protobuf) - -ZEND_DECLARE_MODULE_GLOBALS(protobuf) - -const zval *get_generated_pool() { - return &PROTOBUF_G(generated_pool); -} - -// This is a PHP extension (not a Zend extension). What follows is a summary of -// a PHP extension's lifetime and when various handlers are called. -// -// * PHP_GINIT_FUNCTION(protobuf) / PHP_GSHUTDOWN_FUNCTION(protobuf) -// are the constructor/destructor for the globals. The sequence over the -// course of a process lifetime is: -// -// # Process startup -// GINIT(
) -// MINIT -// -// foreach request: -// RINIT -// # Request is processed here. -// RSHUTDOWN -// -// foreach thread: -// GINIT() -// # Code for the thread runs here. -// GSHUTDOWN() -// -// # Process Shutdown -// # -// # These should be running per the docs, but I have not been able to -// # actually get the process-wide shutdown functions to run. -// # -// # MSHUTDOWN -// # GSHUTDOWN(
) -// -// * Threads can be created either explicitly by the user, inside a request, -// or implicitly by the runtime, to process multiple requests concurrently. -// If the latter is being used, then the "foreach thread" block above -// actually looks like this: -// -// foreach thread: -// GINIT() -// # A non-main thread will only receive requests when using a threaded -// # MPM with Apache -// foreach request: -// RINIT -// # Request is processed here. -// RSHUTDOWN -// GSHUTDOWN() -// -// That said, it appears that few people use threads with PHP: -// * The pthread package documented at -// https://www.php.net/manual/en/class.thread.php nas not been released -// since 2016, and the current release fails to compile against any PHP -// newer than 7.0.33. -// * The GitHub master branch supports 7.2+, but this has not been released -// to PECL. -// * Its owner has disavowed it as "broken by design" and "in an untenable -// position for the future": https://github.com/krakjoe/pthreads/issues/929 -// * The only way to use PHP with requests in different threads is to use the -// Apache 2 mod_php with the "worker" MPM. But this is explicitly -// discouraged by the documentation: https://serverfault.com/a/231660 - -static PHP_GSHUTDOWN_FUNCTION(protobuf) { - if (protobuf_globals->saved_symtab) { - upb_symtab_free(protobuf_globals->saved_symtab); - } -} - -static PHP_GINIT_FUNCTION(protobuf) { - ZVAL_NULL(&protobuf_globals->generated_pool); - protobuf_globals->saved_symtab = NULL; -} - -/** - * PHP_RINIT_FUNCTION(protobuf) - * - * This function is run at the beginning of processing each request. - */ -static PHP_RINIT_FUNCTION(protobuf) { - // Create the global generated pool. - // Reuse the symtab (if any) left to us by the last request. - upb_symtab *symtab = PROTOBUF_G(saved_symtab); - DescriptorPool_CreateWithSymbolTable(&PROTOBUF_G(generated_pool), symtab); - - // Set up autoloader for bundled sources. - zend_eval_string("spl_autoload_register('protobuf_internal_loadbundled');", - NULL, "autoload_register.php"); - - zend_hash_init(&PROTOBUF_G(object_cache), 64, NULL, NULL, 0); - zend_hash_init(&PROTOBUF_G(name_msg_cache), 64, NULL, NULL, 0); - zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0); - - return SUCCESS; -} - -/** - * PHP_RSHUTDOWN_FUNCTION(protobuf) - * - * This function is run at the end of processing each request. - */ -static PHP_RSHUTDOWN_FUNCTION(protobuf) { - // Preserve the symtab if requested. - if (PROTOBUF_G(keep_descriptor_pool_after_request)) { - zval *zv = &PROTOBUF_G(generated_pool); - PROTOBUF_G(saved_symtab) = DescriptorPool_Steal(zv); - } - - zval_dtor(&PROTOBUF_G(generated_pool)); - zend_hash_destroy(&PROTOBUF_G(object_cache)); - zend_hash_destroy(&PROTOBUF_G(name_msg_cache)); - zend_hash_destroy(&PROTOBUF_G(name_enum_cache)); - - return SUCCESS; -} - -// ----------------------------------------------------------------------------- -// Bundled PHP sources -// ----------------------------------------------------------------------------- - -// We bundle PHP sources for well-known types into the C extension. There is no -// need to implement these in C. - -static PHP_FUNCTION(protobuf_internal_loadbundled) { - char *name = NULL; - zend_long size; - BundledPhp_File *file; - - if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name, &size) != SUCCESS) { - return; - } - - for (file = bundled_files; file->filename; file++) { - if (strcmp(file->filename, name) == 0) { - zend_eval_string((char*)file->contents, NULL, (char*)file->filename); - return; - } - } -} - -ZEND_BEGIN_ARG_INFO_EX(arginfo_load_bundled_source, 0, 0, 1) - ZEND_ARG_INFO(0, class_name) -ZEND_END_ARG_INFO() - -// ----------------------------------------------------------------------------- -// Object Cache. -// ----------------------------------------------------------------------------- - -void ObjCache_Add(const void *upb_obj, zend_object *php_obj) { - zend_ulong k = (zend_ulong)upb_obj; - zend_hash_index_add_ptr(&PROTOBUF_G(object_cache), k, php_obj); -} - -void ObjCache_Delete(const void *upb_obj) { - if (upb_obj) { - zend_ulong k = (zend_ulong)upb_obj; - int ret = zend_hash_index_del(&PROTOBUF_G(object_cache), k); - PBPHP_ASSERT(ret == SUCCESS); - } -} - -bool ObjCache_Get(const void *upb_obj, zval *val) { - zend_ulong k = (zend_ulong)upb_obj; - zend_object *obj = zend_hash_index_find_ptr(&PROTOBUF_G(object_cache), k); - - if (obj) { - GC_ADDREF(obj); - ZVAL_OBJ(val, obj); - return true; - } else { - ZVAL_NULL(val); - return false; - } -} - -// ----------------------------------------------------------------------------- -// Name Cache. -// ----------------------------------------------------------------------------- - -void NameMap_AddMessage(const upb_msgdef *m) { - char *k = GetPhpClassname(upb_msgdef_file(m), upb_msgdef_fullname(m)); - zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m); - free(k); -} - -void NameMap_AddEnum(const upb_enumdef *e) { - char *k = GetPhpClassname(upb_enumdef_file(e), upb_enumdef_fullname(e)); - zend_hash_str_add_ptr(&PROTOBUF_G(name_enum_cache), k, strlen(k), (void*)e); - free(k); -} - -const upb_msgdef *NameMap_GetMessage(zend_class_entry *ce) { - const upb_msgdef *ret = - zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name); - - if (!ret && ce->create_object) { - zval tmp; - zval zv; - ZVAL_OBJ(&tmp, ce->create_object(ce)); - zend_call_method_with_0_params(&tmp, ce, NULL, "__construct", &zv); - zval_ptr_dtor(&tmp); - zval_ptr_dtor(&zv); - ret = zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name); - } - - return ret; -} - -const upb_enumdef *NameMap_GetEnum(zend_class_entry *ce) { - const upb_enumdef *ret = - zend_hash_find_ptr(&PROTOBUF_G(name_enum_cache), ce->name); - return ret; -} - -// ----------------------------------------------------------------------------- -// Module init. -// ----------------------------------------------------------------------------- - -zend_function_entry protobuf_functions[] = { - PHP_FE(protobuf_internal_loadbundled, arginfo_load_bundled_source) - ZEND_FE_END -}; - -static const zend_module_dep protobuf_deps[] = { - ZEND_MOD_OPTIONAL("date") - ZEND_MOD_END -}; - -PHP_INI_BEGIN() -STD_PHP_INI_ENTRY("protobuf.keep_descriptor_pool_after_request", "0", - PHP_INI_SYSTEM, OnUpdateBool, - keep_descriptor_pool_after_request, zend_protobuf_globals, - protobuf_globals) -PHP_INI_END() - -static PHP_MINIT_FUNCTION(protobuf) { - REGISTER_INI_ENTRIES(); - Arena_ModuleInit(); - Array_ModuleInit(); - Convert_ModuleInit(); - Def_ModuleInit(); - Map_ModuleInit(); - Message_ModuleInit(); - return SUCCESS; -} - -static PHP_MSHUTDOWN_FUNCTION(protobuf) { - return SUCCESS; -} - -zend_module_entry protobuf_module_entry = { - STANDARD_MODULE_HEADER_EX, - NULL, - protobuf_deps, - "protobuf", // extension name - protobuf_functions, // function list - PHP_MINIT(protobuf), // process startup - PHP_MSHUTDOWN(protobuf), // process shutdown - PHP_RINIT(protobuf), // request shutdown - PHP_RSHUTDOWN(protobuf), // request shutdown - NULL, // extension info - "3.13.0", // extension version - PHP_MODULE_GLOBALS(protobuf), // globals descriptor - PHP_GINIT(protobuf), // globals ctor - PHP_GSHUTDOWN(protobuf), // globals dtor - NULL, // post deactivate - STANDARD_MODULE_PROPERTIES_EX -}; - -ZEND_GET_MODULE(protobuf) diff --git a/php/ext/google/protobuf2/protobuf.h b/php/ext/google/protobuf2/protobuf.h deleted file mode 100644 index 6a7afae0619a..000000000000 --- a/php/ext/google/protobuf2/protobuf.h +++ /dev/null @@ -1,89 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// 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. - -#ifndef PHP_PROTOBUF_H_ -#define PHP_PROTOBUF_H_ - -#include -#include - -#include "php-upb.h" - -const zval *get_generated_pool(); - -#if PHP_VERSION_ID < 70300 -#define GC_ADDREF(h) ++GC_REFCOUNT(h) -#define GC_DELREF(h) --GC_REFCOUNT(h) -#endif - -// ptr -> PHP object cache. This is a weak map that caches lazily-created -// wrapper objects around upb types: -// * upb_msg* -> Message -// * upb_array* -> RepeatedField -// * upb_map*, -> MapField -// * upb_msgdef* -> Descriptor -// * upb_enumdef* -> EnumDescriptor -// * zend_class_entry* -> Descriptor -// -// Each wrapped object should add itself to the map when it is constructed, and -// remove itself from the map when it is destroyed. This is how we ensure that -// the map only contains live objects. The map is weak so it does not actually -// take references to the cached objects. -void ObjCache_Add(const void *key, zend_object *php_obj); -void ObjCache_Delete(const void *key); -bool ObjCache_Get(const void *key, zval *val); - -// PHP class name map. This is necessary because the pb_name->php_class_name -// transformation is non-reversible, so when we need to look up a msgdef or -// enumdef by PHP class, we can't turn the class name into a pb_name. -// * php_class_name -> upb_msgdef* -// * php_class_name -> upb_enumdef* -void NameMap_AddMessage(const upb_msgdef *m); -void NameMap_AddEnum(const upb_enumdef *m); -const upb_msgdef *NameMap_GetMessage(zend_class_entry *ce); -const upb_enumdef *NameMap_GetEnum(zend_class_entry *ce); - -// We need our own assert() because PHP takes control of NDEBUG in its headers. -#ifdef PBPHP_ENABLE_ASSERTS -#define PBPHP_ASSERT(x) \ - do { \ - if (!(x)) { \ - fprintf(stderr, "Assertion failure at %s:%d %s", __FILE__, __LINE__, \ - #x); \ - abort(); \ - } \ - } while (false) -#else -#define PBPHP_ASSERT(x) \ - do { \ - } while (false && (x)) -#endif - -#endif // PHP_PROTOBUF_H_ diff --git a/php/tests/compile_extension.sh b/php/tests/compile_extension.sh index 37c6810b66ec..5834249e39be 100755 --- a/php/tests/compile_extension.sh +++ b/php/tests/compile_extension.sh @@ -12,18 +12,9 @@ else CFLAGS="-g -O0 -Wall" fi - pushd ../ext/google/protobuf phpize --clean rm -f configure.in configure.ac +php make-preload.php phpize && ./configure --with-php-config=$(which php-config) CFLAGS="$CFLAGS" && make popd - -if [ $(php -r "echo PHP_VERSION;" | cut -c1) != "5" ]; then - pushd ../ext/google/protobuf2 - phpize --clean - rm -f configure.in configure.ac - php make-preload.php - phpize && ./configure --with-php-config=$(which php-config) CFLAGS="$CFLAGS" && make - popd -fi diff --git a/php/tests/php_implementation_test.php b/php/tests/php_implementation_test.php index 307b749c4930..db3c361caf17 100644 --- a/php/tests/php_implementation_test.php +++ b/php/tests/php_implementation_test.php @@ -538,7 +538,7 @@ public function testArrayConstructorJsonCaseThrowsException() /** * @expectedException Exception - * @expectedExceptionMessage Expect Foo\TestMessage_Sub. + * @expectedExceptionMessage Expect Foo\TestMessage\Sub. */ public function testArraysForMessagesThrowsException() { diff --git a/php/tests/test.sh b/php/tests/test.sh index b1d8d5f995b8..b10b57fd193c 100755 --- a/php/tests/test.sh +++ b/php/tests/test.sh @@ -8,14 +8,9 @@ cd $(dirname $0) ./compile_extension.sh PHP_VERSION=$(php -r "echo PHP_VERSION;") -TEST_NEW_EXTENSION=true # Each version of PHPUnit supports a fairly narrow range of PHP versions. case "$PHP_VERSION" in - 5.*.*) - PHPUNIT=phpunit-5.6.8.phar - TEST_NEW_EXTENSION=false - ;; 7.0.*|7.1.*|7.2.*) # Oddly older than for 5.6. Not sure the reason. PHPUNIT=phpunit-5.6.0.phar @@ -24,7 +19,7 @@ case "$PHP_VERSION" in PHPUNIT=phpunit-8.phar ;; *) - echo "ERROR: Unknown PHP version $PHP_VERSION" + echo "ERROR: Unsupported PHP version $PHP_VERSION" exit 1 ;; esac @@ -39,9 +34,6 @@ do echo "* $t" echo "****************************" php -dextension=../ext/google/protobuf/modules/protobuf.so $PHPUNIT --bootstrap autoload.php $t - if [ "$TEST_NEW_EXTENSION" = "true" ]; then - php -dextension=../ext/google/protobuf2/modules/protobuf.so $PHPUNIT --bootstrap autoload.php $t - fi echo "" done @@ -51,9 +43,6 @@ do echo "* $t persistent" echo "****************************" php -d protobuf.keep_descriptor_pool_after_request=1 -dextension=../ext/google/protobuf/modules/protobuf.so $PHPUNIT --bootstrap autoload.php $t - if [ "$TEST_NEW_EXTENSION" = "true" ]; then - php -d protobuf.keep_descriptor_pool_after_request=1 -dextension=../ext/google/protobuf2/modules/protobuf.so $PHPUNIT --bootstrap autoload.php $t - fi echo "" done @@ -64,10 +53,6 @@ export ZEND_DONT_UNLOAD_MODULES=1 export USE_ZEND_ALLOC=0 valgrind --leak-check=yes php -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php valgrind --leak-check=yes php -d protobuf.keep_descriptor_pool_after_request=1 -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php -if [ "$TEST_NEW_EXTENSION" = "true" ]; then - valgrind --leak-check=yes php -dextension=../ext/google/protobuf2/modules/protobuf.so memory_leak_test.php - valgrind --leak-check=yes php -d protobuf.keep_descriptor_pool_after_request=1 -dextension=../ext/google/protobuf2/modules/protobuf.so memory_leak_test.php -fi # TODO(teboring): Only for debug (phpunit has memory leak which blocks this beging used by # regresssion test.) diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc index c652f15e936c..4a6206a0f274 100644 --- a/src/google/protobuf/compiler/php/php_generator.cc +++ b/src/google/protobuf/compiler/php/php_generator.cc @@ -744,11 +744,11 @@ void GenerateFieldAccessor(const FieldDescriptor* field, bool is_descriptor, } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { printer->Print( "GPBUtil::checkMessage($var, \\^class_name^::class);\n", - "class_name", LegacyFullClassName(field->message_type(), is_descriptor)); + "class_name", FullClassName(field->message_type(), is_descriptor)); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { printer->Print( "GPBUtil::checkEnum($var, \\^class_name^::class);\n", - "class_name", LegacyFullClassName(field->enum_type(), is_descriptor)); + "class_name", FullClassName(field->enum_type(), is_descriptor)); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { printer->Print( "GPBUtil::checkString($var, ^utf8^);\n", @@ -1754,7 +1754,7 @@ void GenerateWrapperFieldSetterDocComment(io::Printer* printer, const FieldDescr printer->Print("/**\n"); printer->Print( " * Sets the field by wrapping a primitive type in a ^message_name^ object.\n\n", - "message_name", LegacyFullClassName(field->message_type(), false)); + "message_name", FullClassName(field->message_type(), false)); GenerateDocCommentBody(printer, field); printer->Print( " * Generated from protobuf field ^def^\n",