Merge remote-tracking branch 'remotes/google/3.3.x' into merge-3.3-to-master
This commit is contained in:
commit
9053033a50
3
.gitignore
vendored
3
.gitignore
vendored
@ -65,6 +65,9 @@ src/js_embed
|
||||
src/protoc
|
||||
src/unittest_proto_middleman
|
||||
|
||||
# vim generated
|
||||
*.swp
|
||||
|
||||
# Generated test scaffolding
|
||||
src/no_warning_test.cc
|
||||
src/no-warning-test
|
||||
|
@ -32,6 +32,7 @@ env:
|
||||
- CONFIG=ruby22
|
||||
- CONFIG=jruby
|
||||
- CONFIG=php5.6_mac
|
||||
- CONFIG=php7.0_mac
|
||||
matrix:
|
||||
exclude:
|
||||
# It's nontrivial to programmatically install a new JDK from the command
|
||||
|
10
BUILD
10
BUILD
@ -206,6 +206,7 @@ RELATIVE_WELL_KNOWN_PROTOS = [
|
||||
"google/protobuf/any.proto",
|
||||
"google/protobuf/api.proto",
|
||||
"google/protobuf/compiler/plugin.proto",
|
||||
"google/protobuf/compiler/profile.proto",
|
||||
"google/protobuf/descriptor.proto",
|
||||
"google/protobuf/duration.proto",
|
||||
"google/protobuf/empty.proto",
|
||||
@ -350,6 +351,7 @@ cc_library(
|
||||
"src/google/protobuf/compiler/php/php_generator.cc",
|
||||
"src/google/protobuf/compiler/plugin.cc",
|
||||
"src/google/protobuf/compiler/plugin.pb.cc",
|
||||
"src/google/protobuf/compiler/profile.pb.cc",
|
||||
"src/google/protobuf/compiler/python/python_generator.cc",
|
||||
"src/google/protobuf/compiler/ruby/ruby_generator.cc",
|
||||
"src/google/protobuf/compiler/subprocess.cc",
|
||||
@ -401,6 +403,9 @@ RELATIVE_TEST_PROTOS = [
|
||||
"google/protobuf/unittest_enormous_descriptor.proto",
|
||||
"google/protobuf/unittest_import.proto",
|
||||
"google/protobuf/unittest_import_public.proto",
|
||||
"google/protobuf/unittest_lazy_dependencies.proto",
|
||||
"google/protobuf/unittest_lazy_dependencies_custom_option.proto",
|
||||
"google/protobuf/unittest_lazy_dependencies_enum.proto",
|
||||
"google/protobuf/unittest_lite_imports_nonlite.proto",
|
||||
"google/protobuf/unittest_mset.proto",
|
||||
"google/protobuf/unittest_mset_wire_format.proto",
|
||||
@ -477,6 +482,7 @@ cc_test(
|
||||
"src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc",
|
||||
"src/google/protobuf/compiler/cpp/cpp_unittest.cc",
|
||||
"src/google/protobuf/compiler/cpp/metadata_test.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_bootstrap_unittest.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc",
|
||||
"src/google/protobuf/compiler/importer_unittest.cc",
|
||||
"src/google/protobuf/compiler/java/java_doc_comment_unittest.cc",
|
||||
@ -543,6 +549,10 @@ cc_test(
|
||||
":test_plugin",
|
||||
] + glob([
|
||||
"src/google/protobuf/**/*",
|
||||
# Files for csharp_bootstrap_unittest.cc.
|
||||
"conformance/**/*",
|
||||
"csharp/src/**/*",
|
||||
"examples/**/*",
|
||||
]),
|
||||
includes = [
|
||||
"src/",
|
||||
|
108
CHANGES.txt
108
CHANGES.txt
@ -1,3 +1,111 @@
|
||||
2017-04-05 version 3.3.0 (C++/Java/Python/PHP/Objective-C/C#/Ruby/JavaScript)
|
||||
Planned Future Changes
|
||||
* There are some changes that are not included in this release but are
|
||||
planned for the near future:
|
||||
- Preserve unknown fields in proto3: please read this doc:
|
||||
|
||||
https://docs.google.com/document/d/1KMRX-G91Aa-Y2FkEaHeeviLRRNblgIahbsk4wA14gRk/view
|
||||
|
||||
for the timeline and follow up this github issue:
|
||||
|
||||
https://github.com/google/protobuf/issues/272
|
||||
|
||||
for discussion.
|
||||
- Make C++ implementation C++11 only: we plan to require C++11 to build
|
||||
protobuf code starting from 3.4.0 or 3.5.0 release. Please join this
|
||||
github issue:
|
||||
|
||||
https://github.com/google/protobuf/issues/2780
|
||||
|
||||
to provide your feedback.
|
||||
|
||||
C++
|
||||
* Fixed map fields serialization of DynamicMessage to correctly serialize
|
||||
both key and value regardless of their presence.
|
||||
* Parser now rejects field number 0 correctly.
|
||||
* New API Message::SpaceUsedLong() that’s equivalent to
|
||||
Message::SpaceUsed() but returns the value in size_t.
|
||||
* JSON support
|
||||
- New flag always_print_enums_as_ints in JsonPrintOptions.
|
||||
- New flag preserve_proto_field_names in JsonPrintOptions. It will instruct
|
||||
the JSON printer to use the original field name declared in the .proto
|
||||
file instead of converting them to lowerCamelCase when printing JSON.
|
||||
- JsonPrintOptions.always_print_primtive_fields now works for oneof message
|
||||
fields.
|
||||
- Fixed a bug that doesn’t allow different fields to set the same json_name
|
||||
value.
|
||||
- Fixed a performance bug that causes excessive memory copy when printing
|
||||
large messages.
|
||||
* Various performance optimizations.
|
||||
|
||||
Java
|
||||
* Map field setters eagerly validate inputs and throw NullPointerExceptions
|
||||
as appropriate.
|
||||
* Added ByteBuffer overloads to the generated parsing methods and the Parser
|
||||
interface.
|
||||
* proto3 enum's getNumber() method now throws on UNRECOGNIZED values.
|
||||
* Output of JsonFormat is now locale independent.
|
||||
|
||||
Python
|
||||
* Added FindServiceByName() in the pure-Python DescriptorPool. This works only
|
||||
for descriptors added with DescriptorPool.Add(). Generated descriptor_pool
|
||||
does not support this yet.
|
||||
* Added a descriptor_pool parameter for parsing Any in text_format.Parse().
|
||||
* descriptor_pool.FindFileContainingSymbol() now is able to find nested
|
||||
extensions.
|
||||
* Extending empty [] to repeated field now sets parent message presence.
|
||||
|
||||
PHP
|
||||
* Added file option php_class_prefix. The prefix will be prepended to all
|
||||
generated classes defined in the file.
|
||||
* When encoding, negative int32 values are sign-extended to int64.
|
||||
* Repeated/Map field setter accepts a regular PHP array. Type checking is
|
||||
done on the array elements.
|
||||
* encode/decode are renamed to serializeToString/mergeFromString.
|
||||
* Added mergeFrom, clear method on Message.
|
||||
* Fixed a bug that oneof accessor didn’t return the field name that is
|
||||
actually set.
|
||||
* C extension now works with php7.
|
||||
* This is the first GA release of PHP. We guarantee that old generated code
|
||||
can always work with new runtime and new generated code.
|
||||
|
||||
Objective-C
|
||||
* Fixed help for GPBTimestamp for dates before the epoch that contain
|
||||
fractional seconds.
|
||||
* Added GPBMessageDropUnknownFieldsRecursively() to remove unknowns from a
|
||||
message and any sub messages.
|
||||
* Addressed a threading race in extension registration/lookup.
|
||||
* Increased the max message parsing depth to 100 to match the other languages.
|
||||
* Removed some use of dispatch_once in favor of atomic compare/set since it
|
||||
needs to be heap based.
|
||||
* Fixes for new Xcode 8.3 warnings.
|
||||
|
||||
C#
|
||||
* Fixed MapField.Values.CopyTo, which would throw an exception unnecessarily
|
||||
if provided exactly the right size of array to copy to.
|
||||
* Fixed enum JSON formatting when multiple names mapped to the same numeric
|
||||
value.
|
||||
* Added JSON formatting option to format enums as integers.
|
||||
* Modified RepeatedField<T> to implement IReadOnlyList<T>.
|
||||
* Introduced the start of custom option handling; it's not as pleasant as it
|
||||
might be, but the information is at least present. We expect to extend code
|
||||
generation to improve this in the future.
|
||||
* Introduced ByteString.FromStream and ByteString.FromStreamAsync to
|
||||
efficiently create a ByteString from a stream.
|
||||
* Added whole-message deprecation, which decorates the class with [Obsolete].
|
||||
|
||||
Ruby
|
||||
* Fixed Message#to_h for messages with map fields.
|
||||
* Fixed memcpy() in binary gems to work for old glibc, without breaking the
|
||||
build for non-glibc libc’s like musl.
|
||||
|
||||
Javascript
|
||||
* Added compatibility tests for version 3.0.0.
|
||||
* Added conformance tests.
|
||||
* Fixed serialization of extensions: we need to emit a value even if it is
|
||||
falsy (like the number 0).
|
||||
* Use closurebuilder.py in favor of calcdeps.py for compiling JavaScript.
|
||||
|
||||
2017-01-23 version 3.2.0 (C++/Java/Python/PHP/Ruby/Objective-C/C#/JavaScript/Lite)
|
||||
General
|
||||
* Added protoc version number to protoc plugin protocol. It can be used by
|
||||
|
@ -247,6 +247,7 @@ java_EXTRA_DIST=
|
||||
java/core/src/main/java/com/google/protobuf/MutabilityOracle.java \
|
||||
java/core/src/main/java/com/google/protobuf/NioByteString.java \
|
||||
java/core/src/main/java/com/google/protobuf/Parser.java \
|
||||
java/core/src/main/java/com/google/protobuf/PrimitiveNonBoxingCollection.java \
|
||||
java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java \
|
||||
java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java \
|
||||
java/core/src/main/java/com/google/protobuf/ProtocolStringList.java \
|
||||
@ -645,6 +646,7 @@ php_EXTRA_DIST= \
|
||||
php/src/Google/Protobuf/Internal/EnumBuilderContext.php \
|
||||
php/src/Google/Protobuf/Internal/GPBUtil.php \
|
||||
php/src/Google/Protobuf/Internal/FieldOptions_CType.php \
|
||||
php/src/Google/Protobuf/Internal/GPBDecodeException.php \
|
||||
php/src/Google/Protobuf/descriptor.php \
|
||||
php/src/GPBMetadata/Google/Protobuf/Internal/Descriptor.php \
|
||||
php/tests/array_test.php \
|
||||
@ -655,6 +657,7 @@ php_EXTRA_DIST= \
|
||||
php/tests/map_field_test.php \
|
||||
php/tests/memory_leak_test.php \
|
||||
php/tests/php_implementation_test.php \
|
||||
php/tests/proto/test_import_descriptor_proto.proto \
|
||||
php/tests/proto/test_include.proto \
|
||||
php/tests/proto/test.proto \
|
||||
php/tests/proto/test_prefix.proto \
|
||||
@ -710,6 +713,7 @@ python_EXTRA_DIST= \
|
||||
python/google/protobuf/internal/packed_field_test.proto \
|
||||
python/google/protobuf/internal/proto_builder_test.py \
|
||||
python/google/protobuf/internal/python_message.py \
|
||||
python/google/protobuf/internal/python_protobuf.cc \
|
||||
python/google/protobuf/internal/reflection_test.py \
|
||||
python/google/protobuf/internal/service_reflection_test.py \
|
||||
python/google/protobuf/internal/symbol_database_test.py \
|
||||
@ -752,13 +756,13 @@ python_EXTRA_DIST= \
|
||||
python/google/protobuf/pyext/message_module.cc \
|
||||
python/google/protobuf/pyext/proto2_api_test.proto \
|
||||
python/google/protobuf/pyext/python.proto \
|
||||
python/google/protobuf/pyext/python_protobuf.h \
|
||||
python/google/protobuf/pyext/repeated_composite_container.cc \
|
||||
python/google/protobuf/pyext/repeated_composite_container.h \
|
||||
python/google/protobuf/pyext/repeated_scalar_container.cc \
|
||||
python/google/protobuf/pyext/repeated_scalar_container.h \
|
||||
python/google/protobuf/pyext/safe_numerics.h \
|
||||
python/google/protobuf/pyext/scoped_pyobject_ptr.h \
|
||||
python/google/protobuf/python_protobuf.h \
|
||||
python/google/protobuf/reflection.py \
|
||||
python/google/protobuf/service.py \
|
||||
python/google/protobuf/service_reflection.py \
|
||||
|
@ -5,7 +5,7 @@
|
||||
# dependent projects use the :git notation to refer to the library.
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'Protobuf'
|
||||
s.version = '3.2.0'
|
||||
s.version = '3.3.0'
|
||||
s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.'
|
||||
s.homepage = 'https://github.com/google/protobuf'
|
||||
s.license = '3-Clause BSD License'
|
||||
|
@ -36,6 +36,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\parser.h" in
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\php\php_generator.h" include\google\protobuf\compiler\php\php_generator.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.h" include\google\protobuf\compiler\plugin.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\plugin.pb.h" include\google\protobuf\compiler\plugin.pb.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\profile.pb.h" include\google\protobuf\compiler\profile.pb.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\python\python_generator.h" include\google\protobuf\compiler\python\python_generator.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\ruby\ruby_generator.h" include\google\protobuf\compiler\ruby\ruby_generator.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\descriptor.h" include\google\protobuf\descriptor.h
|
||||
@ -114,6 +115,7 @@ copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\text_format.h" includ
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\timestamp.pb.h" include\google\protobuf\timestamp.pb.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\type.pb.h" include\google\protobuf\type.pb.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\unknown_field_set.h" include\google\protobuf\unknown_field_set.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\delimited_message_util.h" include\google\protobuf\util\delimited_message_util.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_comparator.h" include\google\protobuf\util\field_comparator.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\field_mask_util.h" include\google\protobuf\util\field_mask_util.h
|
||||
copy "${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\util\json_util.h" include\google\protobuf\util\json_util.h
|
||||
|
@ -88,6 +88,7 @@ set(libprotoc_files
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/php/php_generator.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/plugin.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/plugin.pb.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/profile.pb.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/python/python_generator.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/ruby/ruby_generator.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/subprocess.cc
|
||||
|
@ -43,6 +43,9 @@ set(tests_protos
|
||||
google/protobuf/unittest_empty.proto
|
||||
google/protobuf/unittest_import.proto
|
||||
google/protobuf/unittest_import_public.proto
|
||||
google/protobuf/unittest_lazy_dependencies.proto
|
||||
google/protobuf/unittest_lazy_dependencies_custom_option.proto
|
||||
google/protobuf/unittest_lazy_dependencies_enum.proto
|
||||
google/protobuf/unittest_lite_imports_nonlite.proto
|
||||
google/protobuf/unittest_mset.proto
|
||||
google/protobuf/unittest_mset_wire_format.proto
|
||||
@ -207,7 +210,7 @@ set(lite_test_files
|
||||
${protobuf_source_dir}/src/google/protobuf/lite_unittest.cc
|
||||
)
|
||||
add_executable(lite-test ${lite_test_files} ${common_lite_test_files} ${lite_test_proto_files})
|
||||
target_link_libraries(lite-test libprotobuf-lite)
|
||||
target_link_libraries(lite-test libprotobuf-lite gmock_main)
|
||||
|
||||
set(lite_arena_test_files
|
||||
${protobuf_source_dir}/src/google/protobuf/lite_arena_unittest.cc
|
||||
|
@ -17,7 +17,7 @@ AC_PREREQ(2.59)
|
||||
# In the SVN trunk, the version should always be the next anticipated release
|
||||
# version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed
|
||||
# the size of one file name in the dist tarfile over the 99-char limit.)
|
||||
AC_INIT([Protocol Buffers],[3.2.0],[protobuf@googlegroups.com],[protobuf])
|
||||
AC_INIT([Protocol Buffers],[3.3.0],[protobuf@googlegroups.com],[protobuf])
|
||||
|
||||
AM_MAINTAINER_MODE([enable])
|
||||
|
||||
|
@ -708,6 +708,21 @@ bool ConformanceTestSuite::CheckSetEmpty(const set<string>& set_to_check,
|
||||
}
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::TestIllegalTags() {
|
||||
// field num 0 is illegal
|
||||
string nullfield[] = {
|
||||
"\1DEADBEEF",
|
||||
"\2\1\1",
|
||||
"\3\4",
|
||||
"\5DEAD"
|
||||
};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
string name = "IllegalZeroFieldNum_Case_0";
|
||||
name.back() += i;
|
||||
ExpectParseFailureForProto(nullfield[i], name, REQUIRED);
|
||||
}
|
||||
}
|
||||
|
||||
bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
|
||||
std::string* output) {
|
||||
runner_ = runner;
|
||||
@ -728,6 +743,8 @@ bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
|
||||
TestPrematureEOFForType(static_cast<FieldDescriptor::Type>(i));
|
||||
}
|
||||
|
||||
TestIllegalTags();
|
||||
|
||||
int64 kInt64Min = -9223372036854775808ULL;
|
||||
int64 kInt64Max = 9223372036854775807ULL;
|
||||
uint64 kUint64Max = 18446744073709551615ULL;
|
||||
|
@ -201,6 +201,7 @@ class ConformanceTestSuite {
|
||||
const std::string& test_name,
|
||||
ConformanceLevel level);
|
||||
void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type);
|
||||
void TestIllegalTags();
|
||||
void TestValidDataForType(
|
||||
google::protobuf::FieldDescriptor::Type,
|
||||
std::vector<std::pair<std::string, std::string>> values);
|
||||
|
@ -32,7 +32,6 @@ Recommended.JsonInput.TrailingCommaInAnObject
|
||||
Recommended.JsonInput.TrailingCommaInAnObjectWithNewlines
|
||||
Recommended.JsonInput.TrailingCommaInAnObjectWithSpace
|
||||
Recommended.JsonInput.TrailingCommaInAnObjectWithSpaceCommaSpace
|
||||
Required.ProtobufInput.PrematureEofBeforeKnownRepeatedValue.MESSAGE
|
||||
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
|
||||
Required.ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
|
||||
Required.ProtobufInput.PrematureEofInPackedField.BOOL
|
||||
@ -43,4 +42,3 @@ Required.ProtobufInput.PrematureEofInPackedField.SINT32
|
||||
Required.ProtobufInput.PrematureEofInPackedField.SINT64
|
||||
Required.ProtobufInput.PrematureEofInPackedField.UINT32
|
||||
Required.ProtobufInput.PrematureEofInPackedField.UINT64
|
||||
Required.ProtobufInput.PrematureEofInsideKnownRepeatedValue.MESSAGE
|
||||
|
@ -0,0 +1,4 @@
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_0
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_1
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_2
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_3
|
@ -1,4 +1,6 @@
|
||||
# All tests currently passing.
|
||||
#
|
||||
# JSON input or output tests are skipped (in conformance_objc.m) as mobile
|
||||
# platforms don't support JSON wire format to avoid code bloat.
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_0
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_1
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_2
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_3
|
||||
|
@ -8,6 +8,7 @@ Recommended.JsonInput.DurationHas6FractionalDigits.Validator
|
||||
Recommended.JsonInput.DurationHas9FractionalDigits.Validator
|
||||
Recommended.JsonInput.DurationHasZeroFractionalDigit.Validator
|
||||
Recommended.JsonInput.Int64FieldBeString.Validator
|
||||
Recommended.JsonInput.MapFieldValueIsNull
|
||||
Recommended.JsonInput.OneofZeroBool.JsonOutput
|
||||
Recommended.JsonInput.OneofZeroBool.ProtobufOutput
|
||||
Recommended.JsonInput.OneofZeroBytes.JsonOutput
|
||||
@ -24,6 +25,8 @@ Recommended.JsonInput.OneofZeroUint32.JsonOutput
|
||||
Recommended.JsonInput.OneofZeroUint32.ProtobufOutput
|
||||
Recommended.JsonInput.OneofZeroUint64.JsonOutput
|
||||
Recommended.JsonInput.OneofZeroUint64.ProtobufOutput
|
||||
Recommended.JsonInput.RepeatedFieldMessageElementIsNull
|
||||
Recommended.JsonInput.RepeatedFieldPrimitiveElementIsNull
|
||||
Recommended.JsonInput.StringEndsWithEscapeChar
|
||||
Recommended.JsonInput.StringFieldSurrogateInWrongOrder
|
||||
Recommended.JsonInput.StringFieldUnpairedHighSurrogate
|
||||
@ -127,24 +130,12 @@ Required.JsonInput.Int32FieldStringValue.JsonOutput
|
||||
Required.JsonInput.Int32FieldStringValue.ProtobufOutput
|
||||
Required.JsonInput.Int32FieldStringValueEscaped.JsonOutput
|
||||
Required.JsonInput.Int32FieldStringValueEscaped.ProtobufOutput
|
||||
Required.JsonInput.Int32MapEscapedKey.JsonOutput
|
||||
Required.JsonInput.Int32MapEscapedKey.ProtobufOutput
|
||||
Required.JsonInput.Int32MapField.JsonOutput
|
||||
Required.JsonInput.Int32MapField.ProtobufOutput
|
||||
Required.JsonInput.Int64FieldMaxValue.JsonOutput
|
||||
Required.JsonInput.Int64FieldMaxValue.ProtobufOutput
|
||||
Required.JsonInput.Int64FieldMinValue.JsonOutput
|
||||
Required.JsonInput.Int64FieldMinValue.ProtobufOutput
|
||||
Required.JsonInput.Int64MapEscapedKey.JsonOutput
|
||||
Required.JsonInput.Int64MapEscapedKey.ProtobufOutput
|
||||
Required.JsonInput.Int64MapField.JsonOutput
|
||||
Required.JsonInput.Int64MapField.ProtobufOutput
|
||||
Required.JsonInput.MessageField.JsonOutput
|
||||
Required.JsonInput.MessageField.ProtobufOutput
|
||||
Required.JsonInput.MessageMapField.JsonOutput
|
||||
Required.JsonInput.MessageMapField.ProtobufOutput
|
||||
Required.JsonInput.MessageRepeatedField.JsonOutput
|
||||
Required.JsonInput.MessageRepeatedField.ProtobufOutput
|
||||
Required.JsonInput.OptionalBoolWrapper.JsonOutput
|
||||
Required.JsonInput.OptionalBoolWrapper.ProtobufOutput
|
||||
Required.JsonInput.OptionalBytesWrapper.JsonOutput
|
||||
@ -165,14 +156,13 @@ Required.JsonInput.OptionalUint64Wrapper.JsonOutput
|
||||
Required.JsonInput.OptionalUint64Wrapper.ProtobufOutput
|
||||
Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput
|
||||
Required.JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput
|
||||
Required.JsonInput.PrimitiveRepeatedField.JsonOutput
|
||||
Required.JsonInput.PrimitiveRepeatedField.ProtobufOutput
|
||||
Required.JsonInput.RepeatedBoolWrapper.JsonOutput
|
||||
Required.JsonInput.RepeatedBoolWrapper.ProtobufOutput
|
||||
Required.JsonInput.RepeatedBytesWrapper.JsonOutput
|
||||
Required.JsonInput.RepeatedBytesWrapper.ProtobufOutput
|
||||
Required.JsonInput.RepeatedDoubleWrapper.JsonOutput
|
||||
Required.JsonInput.RepeatedDoubleWrapper.ProtobufOutput
|
||||
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingMessagesGotInt
|
||||
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingStringsGotInt
|
||||
Required.JsonInput.RepeatedFloatWrapper.JsonOutput
|
||||
Required.JsonInput.RepeatedFloatWrapper.ProtobufOutput
|
||||
@ -186,9 +176,15 @@ Required.JsonInput.RepeatedUint32Wrapper.JsonOutput
|
||||
Required.JsonInput.RepeatedUint32Wrapper.ProtobufOutput
|
||||
Required.JsonInput.RepeatedUint64Wrapper.JsonOutput
|
||||
Required.JsonInput.RepeatedUint64Wrapper.ProtobufOutput
|
||||
Required.JsonInput.StringFieldEscape.JsonOutput
|
||||
Required.JsonInput.StringFieldEscape.ProtobufOutput
|
||||
Required.JsonInput.StringFieldNotAString
|
||||
Required.JsonInput.StringFieldSurrogatePair.JsonOutput
|
||||
Required.JsonInput.StringFieldSurrogatePair.ProtobufOutput
|
||||
Required.JsonInput.StringFieldUnicodeEscape.JsonOutput
|
||||
Required.JsonInput.StringFieldUnicodeEscape.ProtobufOutput
|
||||
Required.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.JsonOutput
|
||||
Required.JsonInput.StringFieldUnicodeEscapeWithLowercaseHexLetters.ProtobufOutput
|
||||
Required.JsonInput.Struct.JsonOutput
|
||||
Required.JsonInput.Struct.ProtobufOutput
|
||||
Required.JsonInput.TimestampMaxValue.JsonOutput
|
||||
@ -203,12 +199,8 @@ Required.JsonInput.TimestampWithPositiveOffset.JsonOutput
|
||||
Required.JsonInput.TimestampWithPositiveOffset.ProtobufOutput
|
||||
Required.JsonInput.Uint32FieldMaxFloatValue.JsonOutput
|
||||
Required.JsonInput.Uint32FieldMaxFloatValue.ProtobufOutput
|
||||
Required.JsonInput.Uint32MapField.JsonOutput
|
||||
Required.JsonInput.Uint32MapField.ProtobufOutput
|
||||
Required.JsonInput.Uint64FieldMaxValue.JsonOutput
|
||||
Required.JsonInput.Uint64FieldMaxValue.ProtobufOutput
|
||||
Required.JsonInput.Uint64MapField.JsonOutput
|
||||
Required.JsonInput.Uint64MapField.ProtobufOutput
|
||||
Required.JsonInput.ValueAcceptBool.JsonOutput
|
||||
Required.JsonInput.ValueAcceptBool.ProtobufOutput
|
||||
Required.JsonInput.ValueAcceptFloat.JsonOutput
|
||||
|
@ -11,3 +11,7 @@ Required.JsonInput.FloatFieldTooLarge
|
||||
Required.JsonInput.FloatFieldTooSmall
|
||||
Required.JsonInput.RepeatedFieldWrongElementTypeExpectingIntegersGotBool
|
||||
Required.JsonInput.TimestampJsonInputLowercaseT
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_0
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_1
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_2
|
||||
Required.ProtobufInput.IllegalZeroFieldNum_Case_3
|
||||
|
@ -5,7 +5,7 @@
|
||||
<title>Google Protocol Buffers tools</title>
|
||||
<summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
|
||||
<description>See project site for more info.</description>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.0</version>
|
||||
<authors>Google Inc.</authors>
|
||||
<owners>protobuf-packages</owners>
|
||||
<licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
|
||||
|
@ -95,57 +95,58 @@ namespace Google.Protobuf.Reflection {
|
||||
"X3ByZWZpeBgoIAEoCRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsy",
|
||||
"JC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRp",
|
||||
"bWl6ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JV",
|
||||
"TlRJTUUQAyoJCOgHEICAgIACSgQIJhAnIuwBCg5NZXNzYWdlT3B0aW9ucxIm",
|
||||
"TlRJTUUQAyoJCOgHEICAgIACSgQIJhAnIvIBCg5NZXNzYWdlT3B0aW9ucxIm",
|
||||
"ChdtZXNzYWdlX3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9f",
|
||||
"c3RhbmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoK",
|
||||
"ZGVwcmVjYXRlZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMK",
|
||||
"FHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1",
|
||||
"Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgIEAkingMKDEZp",
|
||||
"ZWxkT3B0aW9ucxI6CgVjdHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5G",
|
||||
"aWVsZE9wdGlvbnMuQ1R5cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoG",
|
||||
"anN0eXBlGAYgASgOMiQuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5K",
|
||||
"U1R5cGU6CUpTX05PUk1BTBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXBy",
|
||||
"ZWNhdGVkGAMgASgIOgVmYWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1",
|
||||
"bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYu",
|
||||
"VW5pbnRlcnByZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRD",
|
||||
"T1JEEAESEAoMU1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1B",
|
||||
"TBAAEg0KCUpTX1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAJK",
|
||||
"BAgEEAUiXgoMT25lb2ZPcHRpb25zEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9u",
|
||||
"Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgIEAlKBAgJEAoi",
|
||||
"ngMKDEZpZWxkT3B0aW9ucxI6CgVjdHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90",
|
||||
"b2J1Zi5GaWVsZE9wdGlvbnMuQ1R5cGU6BlNUUklORxIOCgZwYWNrZWQYAiAB",
|
||||
"KAgSPwoGanN0eXBlGAYgASgOMiQuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0",
|
||||
"aW9ucy5KU1R5cGU6CUpTX05PUk1BTBITCgRsYXp5GAUgASgIOgVmYWxzZRIZ",
|
||||
"CgpkZXByZWNhdGVkGAMgASgIOgVmYWxzZRITCgR3ZWFrGAogASgIOgVmYWxz",
|
||||
"ZRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJv",
|
||||
"dG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQ",
|
||||
"ABIICgRDT1JEEAESEAoMU1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpT",
|
||||
"X05PUk1BTBAAEg0KCUpTX1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQ",
|
||||
"gICAgAJKBAgEEAUiXgoMT25lb2ZPcHRpb25zEkMKFHVuaW50ZXJwcmV0ZWRf",
|
||||
"b3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVk",
|
||||
"T3B0aW9uKgkI6AcQgICAgAIikwEKC0VudW1PcHRpb25zEhMKC2FsbG93X2Fs",
|
||||
"aWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNlEkMKFHVuaW50",
|
||||
"ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5Vbmlu",
|
||||
"dGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAJKBAgFEAYifQoQRW51bVZhbHVl",
|
||||
"T3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxzZRJDChR1bmludGVy",
|
||||
"cHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRl",
|
||||
"cnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNlcnZpY2VPcHRpb25zEhkK",
|
||||
"CmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0",
|
||||
"aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0",
|
||||
"aW9uKgkI6AcQgICAgAIirQIKDU1ldGhvZE9wdGlvbnMSGQoKZGVwcmVjYXRl",
|
||||
"ZBghIAEoCDoFZmFsc2USXwoRaWRlbXBvdGVuY3lfbGV2ZWwYIiABKA4yLy5n",
|
||||
"b29nbGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucy5JZGVtcG90ZW5jeUxldmVs",
|
||||
"OhNJREVNUE9URU5DWV9VTktOT1dOEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9u",
|
||||
"GOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9u",
|
||||
"KgkI6AcQgICAgAIijQEKC0VudW1PcHRpb25zEhMKC2FsbG93X2FsaWFzGAIg",
|
||||
"ASgIEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0",
|
||||
"ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJl",
|
||||
"dGVkT3B0aW9uKgkI6AcQgICAgAIifQoQRW51bVZhbHVlT3B0aW9ucxIZCgpk",
|
||||
"ZXByZWNhdGVkGAEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlv",
|
||||
"bhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlv",
|
||||
"bioJCOgHEICAgIACInsKDlNlcnZpY2VPcHRpb25zEhkKCmRlcHJlY2F0ZWQY",
|
||||
"ISABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIk",
|
||||
"Lmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICA",
|
||||
"gAIirQIKDU1ldGhvZE9wdGlvbnMSGQoKZGVwcmVjYXRlZBghIAEoCDoFZmFs",
|
||||
"c2USXwoRaWRlbXBvdGVuY3lfbGV2ZWwYIiABKA4yLy5nb29nbGUucHJvdG9i",
|
||||
"dWYuTWV0aG9kT3B0aW9ucy5JZGVtcG90ZW5jeUxldmVsOhNJREVNUE9URU5D",
|
||||
"WV9VTktOT1dOEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdv",
|
||||
"b2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uIlAKEElkZW1wb3Rl",
|
||||
"bmN5TGV2ZWwSFwoTSURFTVBPVEVOQ1lfVU5LTk9XThAAEhMKD05PX1NJREVf",
|
||||
"RUZGRUNUUxABEg4KCklERU1QT1RFTlQQAioJCOgHEICAgIACIp4CChNVbmlu",
|
||||
"dGVycHJldGVkT3B0aW9uEjsKBG5hbWUYAiADKAsyLS5nb29nbGUucHJvdG9i",
|
||||
"dWYuVW5pbnRlcnByZXRlZE9wdGlvbi5OYW1lUGFydBIYChBpZGVudGlmaWVy",
|
||||
"X3ZhbHVlGAMgASgJEhoKEnBvc2l0aXZlX2ludF92YWx1ZRgEIAEoBBIaChJu",
|
||||
"ZWdhdGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoMZG91YmxlX3ZhbHVlGAYgASgB",
|
||||
"EhQKDHN0cmluZ192YWx1ZRgHIAEoDBIXCg9hZ2dyZWdhdGVfdmFsdWUYCCAB",
|
||||
"KAkaMwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0GAEgAigJEhQKDGlzX2V4dGVu",
|
||||
"c2lvbhgCIAIoCCLVAQoOU291cmNlQ29kZUluZm8SOgoIbG9jYXRpb24YASAD",
|
||||
"KAsyKC5nb29nbGUucHJvdG9idWYuU291cmNlQ29kZUluZm8uTG9jYXRpb24a",
|
||||
"hgEKCExvY2F0aW9uEhAKBHBhdGgYASADKAVCAhABEhAKBHNwYW4YAiADKAVC",
|
||||
"AhABEhgKEGxlYWRpbmdfY29tbWVudHMYAyABKAkSGQoRdHJhaWxpbmdfY29t",
|
||||
"bWVudHMYBCABKAkSIQoZbGVhZGluZ19kZXRhY2hlZF9jb21tZW50cxgGIAMo",
|
||||
"CSKnAQoRR2VuZXJhdGVkQ29kZUluZm8SQQoKYW5ub3RhdGlvbhgBIAMoCzIt",
|
||||
"Lmdvb2dsZS5wcm90b2J1Zi5HZW5lcmF0ZWRDb2RlSW5mby5Bbm5vdGF0aW9u",
|
||||
"Gk8KCkFubm90YXRpb24SEAoEcGF0aBgBIAMoBUICEAESEwoLc291cmNlX2Zp",
|
||||
"bGUYAiABKAkSDQoFYmVnaW4YAyABKAUSCwoDZW5kGAQgASgFQowBChNjb20u",
|
||||
"Z29vZ2xlLnByb3RvYnVmQhBEZXNjcmlwdG9yUHJvdG9zSAFaPmdpdGh1Yi5j",
|
||||
"b20vZ29sYW5nL3Byb3RvYnVmL3Byb3RvYy1nZW4tZ28vZGVzY3JpcHRvcjtk",
|
||||
"ZXNjcmlwdG9yogIDR1BCqgIaR29vZ2xlLlByb3RvYnVmLlJlZmxlY3Rpb24="));
|
||||
"IlAKEElkZW1wb3RlbmN5TGV2ZWwSFwoTSURFTVBPVEVOQ1lfVU5LTk9XThAA",
|
||||
"EhMKD05PX1NJREVfRUZGRUNUUxABEg4KCklERU1QT1RFTlQQAioJCOgHEICA",
|
||||
"gIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5hbWUYAiADKAsyLS5n",
|
||||
"b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbi5OYW1lUGFydBIY",
|
||||
"ChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0aXZlX2ludF92YWx1",
|
||||
"ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoMZG91Ymxl",
|
||||
"X3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEoDBIXCg9hZ2dyZWdh",
|
||||
"dGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0GAEgAigJ",
|
||||
"EhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291cmNlQ29kZUluZm8SOgoI",
|
||||
"bG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYuU291cmNlQ29kZUlu",
|
||||
"Zm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBhdGgYASADKAVCAhABEhAK",
|
||||
"BHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29tbWVudHMYAyABKAkSGQoR",
|
||||
"dHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVhZGluZ19kZXRhY2hlZF9j",
|
||||
"b21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29kZUluZm8SQQoKYW5ub3Rh",
|
||||
"dGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5HZW5lcmF0ZWRDb2RlSW5m",
|
||||
"by5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoEcGF0aBgBIAMoBUICEAES",
|
||||
"EwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4YAyABKAUSCwoDZW5kGAQg",
|
||||
"ASgFQowBChNjb20uZ29vZ2xlLnByb3RvYnVmQhBEZXNjcmlwdG9yUHJvdG9z",
|
||||
"SAFaPmdpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3Byb3RvYy1nZW4tZ28v",
|
||||
"ZGVzY3JpcHRvcjtkZXNjcmlwdG9yogIDR1BCqgIaR29vZ2xlLlByb3RvYnVm",
|
||||
"LlJlZmxlY3Rpb24="));
|
||||
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
|
||||
new pbr::FileDescriptor[] { },
|
||||
new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
|
||||
|
@ -46,6 +46,8 @@ namespace Google.Protobuf.WellKnownTypes {
|
||||
/// two Timestamp values is a Duration and it can be added or subtracted
|
||||
/// from a Timestamp. Range is approximately +-10,000 years.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||
///
|
||||
/// Timestamp start = ...;
|
||||
@ -85,6 +87,16 @@ namespace Google.Protobuf.WellKnownTypes {
|
||||
/// td = datetime.timedelta(days=3, minutes=10)
|
||||
/// duration = Duration()
|
||||
/// duration.FromTimedelta(td)
|
||||
///
|
||||
/// # JSON Mapping
|
||||
///
|
||||
/// In JSON format, the Duration type is encoded as a string rather than an
|
||||
/// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||
/// is preceded by the number of seconds, with nanoseconds expressed as
|
||||
/// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||
/// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||
/// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||
/// microsecond should be expressed in JSON format as "3.000001s".
|
||||
/// </summary>
|
||||
public sealed partial class Duration : pb::IMessage<Duration> {
|
||||
private static readonly pb::MessageParser<Duration> _parser = new pb::MessageParser<Duration>(() => new Duration());
|
||||
@ -124,7 +136,8 @@ namespace Google.Protobuf.WellKnownTypes {
|
||||
private long seconds_;
|
||||
/// <summary>
|
||||
/// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
/// to +315,576,000,000 inclusive.
|
||||
/// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||
/// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||
/// </summary>
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
|
||||
public long Seconds {
|
||||
|
@ -51,6 +51,8 @@ namespace Google.Protobuf.WellKnownTypes {
|
||||
/// and from RFC 3339 date strings.
|
||||
/// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Example 1: Compute Timestamp from POSIX `time()`.
|
||||
///
|
||||
/// Timestamp timestamp;
|
||||
@ -89,6 +91,29 @@ namespace Google.Protobuf.WellKnownTypes {
|
||||
///
|
||||
/// timestamp = Timestamp()
|
||||
/// timestamp.GetCurrentTime()
|
||||
///
|
||||
/// # JSON Mapping
|
||||
///
|
||||
/// In JSON format, the Timestamp type is encoded as a string in the
|
||||
/// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||
/// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||
/// where {year} is always expressed using four digits while {month}, {day},
|
||||
/// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||
/// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||
/// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||
/// is required, though only UTC (as indicated by "Z") is presently supported.
|
||||
///
|
||||
/// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||
/// 01:30 UTC on January 15, 2017.
|
||||
///
|
||||
/// In JavaScript, one can convert a Date object to this format using the
|
||||
/// standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||
/// method. In Python, a standard `datetime.datetime` object can be converted
|
||||
/// to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||
/// with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||
/// can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||
/// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime())
|
||||
/// to obtain a formatter capable of generating timestamps in this format.
|
||||
/// </summary>
|
||||
public sealed partial class Timestamp : pb::IMessage<Timestamp> {
|
||||
private static readonly pb::MessageParser<Timestamp> _parser = new pb::MessageParser<Timestamp>(() => new Timestamp());
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "3.2.0",
|
||||
"version": "3.3.0",
|
||||
"title": "Google Protocol Buffers",
|
||||
"description": "See project site for more info.",
|
||||
"authors": [ "Google Inc." ],
|
||||
|
@ -41,6 +41,11 @@ declare -a RUNTIME_PROTO_FILES=(\
|
||||
google/protobuf/type.proto \
|
||||
google/protobuf/wrappers.proto)
|
||||
|
||||
declare -a COMPILER_PROTO_FILES=(\
|
||||
google/protobuf/compiler/plugin.proto \
|
||||
google/protobuf/compiler/profile.proto \
|
||||
)
|
||||
|
||||
CORE_PROTO_IS_CORRECT=0
|
||||
PROCESS_ROUND=1
|
||||
TMP=$(mktemp -d)
|
||||
@ -57,9 +62,9 @@ do
|
||||
fi
|
||||
|
||||
./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \
|
||||
./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP google/protobuf/compiler/plugin.proto
|
||||
./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP ${COMPILER_PROTO_FILES[@]}
|
||||
|
||||
for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
|
||||
for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]} ${COMPILER_PROTO_FILES[@]}; do
|
||||
BASE_NAME=${PROTO_FILE%.*}
|
||||
diff ${BASE_NAME}.pb.h $TMP/${BASE_NAME}.pb.h > /dev/null
|
||||
if test $? -ne 0; then
|
||||
@ -71,24 +76,14 @@ do
|
||||
fi
|
||||
done
|
||||
|
||||
diff google/protobuf/compiler/plugin.pb.h $TMP/google/protobuf/compiler/plugin.pb.h > /dev/null
|
||||
if test $? -ne 0; then
|
||||
CORE_PROTO_IS_CORRECT=0
|
||||
fi
|
||||
diff google/protobuf/compiler/plugin.pb.cc $TMP/google/protobuf/compiler/plugin.pb.cc > /dev/null
|
||||
if test $? -ne 0; then
|
||||
CORE_PROTO_IS_CORRECT=0
|
||||
fi
|
||||
|
||||
# Only override the output if the files are different to avoid re-compilation
|
||||
# of the protoc.
|
||||
if [ $CORE_PROTO_IS_CORRECT -ne 1 ]; then
|
||||
for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do
|
||||
for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]} ${COMPILER_PROTO_FILES[@]}; do
|
||||
BASE_NAME=${PROTO_FILE%.*}
|
||||
mv $TMP/${BASE_NAME}.pb.h ${BASE_NAME}.pb.h
|
||||
mv $TMP/${BASE_NAME}.pb.cc ${BASE_NAME}.pb.cc
|
||||
done
|
||||
mv $TMP/google/protobuf/compiler/plugin.pb.* google/protobuf/compiler/
|
||||
fi
|
||||
|
||||
PROCESS_ROUND=$((PROCESS_ROUND + 1))
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-parent</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>protobuf-java</artifactId>
|
||||
@ -34,6 +34,11 @@
|
||||
<artifactId>easymockclassextension</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.truth</groupId>
|
||||
<artifactId>truth</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -34,7 +34,6 @@ import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
import com.google.protobuf.Internal.EnumLite;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
@ -328,7 +327,8 @@ public abstract class AbstractMessage
|
||||
extends AbstractMessageLite.Builder
|
||||
implements Message.Builder {
|
||||
// The compiler produces an error if this is not declared explicitly.
|
||||
// Method isn't abstract to bypass Java 1.6 compiler issue http://bugs.java.com/view_bug.do?bug_id=6908259
|
||||
// Method isn't abstract to bypass Java 1.6 compiler issue:
|
||||
// http://bugs.java.com/view_bug.do?bug_id=6908259
|
||||
@Override
|
||||
public BuilderType clone() {
|
||||
throw new UnsupportedOperationException("clone() should be implemented in subclasses.");
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -351,22 +353,23 @@ public abstract class AbstractMessageLite<
|
||||
*/
|
||||
protected static <T> void addAll(final Iterable<T> values,
|
||||
final Collection<? super T> list) {
|
||||
if (values == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(values);
|
||||
if (values instanceof LazyStringList) {
|
||||
// For StringOrByteStringLists, check the underlying elements to avoid
|
||||
// forcing conversions of ByteStrings to Strings.
|
||||
// TODO(dweis): Could we just prohibit nulls in all protobuf lists and get rid of this? Is
|
||||
// if even possible to hit this condition as all protobuf methods check for null first,
|
||||
// right?
|
||||
checkForNullValues(((LazyStringList) values).getUnderlyingElements());
|
||||
list.addAll((Collection<T>) values);
|
||||
} else if (values instanceof Collection) {
|
||||
checkForNullValues(values);
|
||||
if (!(values instanceof PrimitiveNonBoxingCollection)) {
|
||||
checkForNullValues(values);
|
||||
}
|
||||
list.addAll((Collection<T>) values);
|
||||
} else {
|
||||
for (final T value : values) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(value);
|
||||
list.add(value);
|
||||
}
|
||||
}
|
||||
@ -374,9 +377,7 @@ public abstract class AbstractMessageLite<
|
||||
|
||||
private static void checkForNullValues(final Iterable<?> values) {
|
||||
for (final Object value : values) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,9 +31,9 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* A partial implementation of the {@link Parser} interface which implements
|
||||
@ -130,6 +130,30 @@ public abstract class AbstractParser<MessageType extends MessageLite>
|
||||
return parseFrom(data, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
MessageType message;
|
||||
try {
|
||||
CodedInputStream input = CodedInputStream.newInstance(data);
|
||||
message = parsePartialFrom(input, extensionRegistry);
|
||||
try {
|
||||
input.checkLastTagWas(0);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e.setUnfinishedMessage(message);
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
return checkMessageInitialized(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException {
|
||||
return parseFrom(data, EMPTY_REGISTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageType parsePartialFrom(
|
||||
byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry)
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.BooleanList;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.BooleanList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
@ -41,9 +42,8 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class BooleanArrayList
|
||||
extends AbstractProtobufList<Boolean>
|
||||
implements BooleanList, RandomAccess {
|
||||
final class BooleanArrayList extends AbstractProtobufList<Boolean>
|
||||
implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
|
||||
static {
|
||||
@ -198,9 +198,7 @@ final class BooleanArrayList
|
||||
public boolean addAll(Collection<? extends Boolean> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
if (collection == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another BooleanArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof BooleanArrayList)) {
|
||||
|
@ -355,8 +355,8 @@ public abstract class CodedInputStream {
|
||||
* <p>Set the maximum message size. In order to prevent malicious messages from exhausting memory
|
||||
* or causing integer overflows, {@code CodedInputStream} limits how large a message may be. The
|
||||
* default limit is {@code Integer.MAX_INT}. You should set this limit as small as you can without
|
||||
* harming your app's functionality. Note that size limits only apply when reading from an
|
||||
* {@code InputStream}, not when constructed around a raw byte array.
|
||||
* harming your app's functionality. Note that size limits only apply when reading from an {@code
|
||||
* InputStream}, not when constructed around a raw byte array.
|
||||
*
|
||||
* <p>If you want to read several messages from a single CodedInputStream, you could call {@link
|
||||
* #resetSizeCounter()} after each one to avoid hitting the size limit.
|
||||
|
@ -184,7 +184,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
* maps are sorted on the lexicographical order of the UTF8 encoded keys.
|
||||
* </ul>
|
||||
*/
|
||||
void useDeterministicSerialization() {
|
||||
public void useDeterministicSerialization() {
|
||||
serializationDeterministic = true;
|
||||
}
|
||||
|
||||
@ -1854,7 +1854,7 @@ public abstract class CodedOutputStream extends ByteOutput {
|
||||
}
|
||||
|
||||
static boolean isSupported() {
|
||||
return UnsafeUtil.hasUnsafeByteBufferOperations();
|
||||
return UnsafeUtil.hasUnsafeByteBufferOperations() && UnsafeUtil.hasUnsafeCopyMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,9 +30,10 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.DescriptorProtos.*;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor.Syntax;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -682,9 +683,7 @@ public final class Descriptors {
|
||||
|
||||
/** Determines if the given field name is reserved. */
|
||||
public boolean isReservedName(final String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(name);
|
||||
for (final String reservedName : proto.getReservedNameList()) {
|
||||
if (reservedName.equals(name)) {
|
||||
return true;
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.DoubleList;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.DoubleList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
@ -41,9 +42,8 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class DoubleArrayList
|
||||
extends AbstractProtobufList<Double>
|
||||
implements DoubleList, RandomAccess {
|
||||
final class DoubleArrayList extends AbstractProtobufList<Double>
|
||||
implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
|
||||
static {
|
||||
@ -199,9 +199,7 @@ final class DoubleArrayList
|
||||
public boolean addAll(Collection<? extends Double> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
if (collection == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another DoubleArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof DoubleArrayList)) {
|
||||
|
@ -30,11 +30,12 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
@ -631,9 +632,7 @@ public final class DynamicMessage extends AbstractMessage {
|
||||
/** Verifies that the value is EnumValueDescriptor and matches Enum Type. */
|
||||
private void ensureSingularEnumValueDescriptor(
|
||||
FieldDescriptor field, Object value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(value);
|
||||
if (!(value instanceof EnumValueDescriptor)) {
|
||||
throw new IllegalArgumentException(
|
||||
"DynamicMessage should use EnumValueDescriptor to set Enum Value.");
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.LazyField.LazyIterator;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.LazyField.LazyIterator;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -385,9 +386,7 @@ final class FieldSet<FieldDescriptorType extends
|
||||
*/
|
||||
private static void verifyType(final WireFormat.FieldType type,
|
||||
final Object value) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(value);
|
||||
|
||||
boolean isValid = false;
|
||||
switch (type.getJavaType()) {
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.FloatList;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.FloatList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
@ -41,9 +42,8 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class FloatArrayList
|
||||
extends AbstractProtobufList<Float>
|
||||
implements FloatList, RandomAccess {
|
||||
final class FloatArrayList extends AbstractProtobufList<Float>
|
||||
implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
|
||||
static {
|
||||
@ -198,9 +198,7 @@ final class FloatArrayList
|
||||
public boolean addAll(Collection<? extends Float> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
if (collection == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another FloatArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof FloatArrayList)) {
|
||||
|
@ -34,6 +34,7 @@ import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream;
|
||||
import com.google.protobuf.GeneratedMessageLite.EqualsVisitor.NotEqualsException;
|
||||
import com.google.protobuf.Internal.BooleanList;
|
||||
import com.google.protobuf.Internal.DoubleList;
|
||||
import com.google.protobuf.Internal.EnumLiteMap;
|
||||
import com.google.protobuf.Internal.FloatList;
|
||||
import com.google.protobuf.Internal.IntList;
|
||||
import com.google.protobuf.Internal.LongList;
|
||||
@ -45,6 +46,7 @@ import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@ -136,6 +138,7 @@ public abstract class GeneratedMessageLite<
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
visit(EqualsVisitor.INSTANCE, (MessageType) other);
|
||||
} catch (NotEqualsException e) {
|
||||
@ -1154,6 +1157,7 @@ public abstract class GeneratedMessageLite<
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
|
||||
*
|
||||
@ -1527,6 +1531,20 @@ public abstract class GeneratedMessageLite<
|
||||
return message;
|
||||
}
|
||||
|
||||
// Validates last tag.
|
||||
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
|
||||
T defaultInstance, ByteBuffer data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException {
|
||||
return checkMessageInitialized(
|
||||
parseFrom(defaultInstance, CodedInputStream.newInstance(data), extensionRegistry));
|
||||
}
|
||||
|
||||
// Validates last tag.
|
||||
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
|
||||
T defaultInstance, ByteBuffer data) throws InvalidProtocolBufferException {
|
||||
return parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry());
|
||||
}
|
||||
|
||||
// Validates last tag.
|
||||
protected static <T extends GeneratedMessageLite<T, ?>> T parseFrom(
|
||||
T defaultInstance, ByteString data)
|
||||
@ -1979,13 +1997,13 @@ public abstract class GeneratedMessageLite<
|
||||
/**
|
||||
* Implements hashCode by accumulating state.
|
||||
*/
|
||||
private static class HashCodeVisitor implements Visitor {
|
||||
static class HashCodeVisitor implements Visitor {
|
||||
|
||||
// The caller must ensure that the visitor is invoked parameterized with this and this such that
|
||||
// other is this. This is required due to how oneof cases are handled. See the class comment
|
||||
// on Visitor for more information.
|
||||
|
||||
private int hashCode = 0;
|
||||
int hashCode = 0;
|
||||
|
||||
@Override
|
||||
public boolean visitBoolean(
|
||||
|
@ -41,7 +41,7 @@ import com.google.protobuf.Descriptors.OneofDescriptor;
|
||||
// class without breaking binary compatibility with old generated code that still subclasses
|
||||
// the old GeneratedMessageV3 class. To allow these different GeneratedMessageV3V? classes to
|
||||
// interoperate (e.g., a GeneratedMessageV3V3 object has a message extension field whose class
|
||||
// type is GeneratedMessageV3V4), these classes still share a common parent class AbstarctMessage
|
||||
// type is GeneratedMessageV3V4), these classes still share a common parent class AbstractMessage
|
||||
// and are using the same GeneratedMessage.GeneratedExtension class for extension definitions.
|
||||
// Since this class becomes GeneratedMessageV3V? in opensource, we have to add an import here
|
||||
// to be able to use GeneratedMessage.GeneratedExtension. The GeneratedExtension definition in
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.IntList;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.IntList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
@ -41,9 +42,8 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class IntArrayList
|
||||
extends AbstractProtobufList<Integer>
|
||||
implements IntList, RandomAccess {
|
||||
final class IntArrayList extends AbstractProtobufList<Integer>
|
||||
implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final IntArrayList EMPTY_LIST = new IntArrayList();
|
||||
static {
|
||||
@ -198,9 +198,7 @@ final class IntArrayList
|
||||
public boolean addAll(Collection<? extends Integer> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
if (collection == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another IntArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof IntArrayList)) {
|
||||
|
@ -59,6 +59,16 @@ public final class Internal {
|
||||
static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
|
||||
|
||||
/**
|
||||
* Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
|
||||
*/
|
||||
static <T> T checkNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an appropriate {@link NullPointerException} if the given objects is {@code null}.
|
||||
*/
|
||||
@ -420,6 +430,11 @@ public final class Internal {
|
||||
CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
|
||||
|
||||
|
||||
/** Helper method to merge two MessageLite instances. */
|
||||
static Object mergeMessage(Object destination, Object source) {
|
||||
return ((MessageLite) destination).toBuilder().mergeFrom((MessageLite) source).buildPartial();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
|
||||
*
|
||||
|
@ -394,6 +394,7 @@ public class LazyFieldLite {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Might lazily parse the bytes that were previously passed in. Is thread-safe.
|
||||
*/
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.LongList;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.LongList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.RandomAccess;
|
||||
@ -41,9 +42,8 @@ import java.util.RandomAccess;
|
||||
*
|
||||
* @author dweis@google.com (Daniel Weis)
|
||||
*/
|
||||
final class LongArrayList
|
||||
extends AbstractProtobufList<Long>
|
||||
implements LongList, RandomAccess {
|
||||
final class LongArrayList extends AbstractProtobufList<Long>
|
||||
implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
|
||||
|
||||
private static final LongArrayList EMPTY_LIST = new LongArrayList();
|
||||
static {
|
||||
@ -198,9 +198,7 @@ final class LongArrayList
|
||||
public boolean addAll(Collection<? extends Long> collection) {
|
||||
ensureIsMutable();
|
||||
|
||||
if (collection == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(collection);
|
||||
|
||||
// We specialize when adding another LongArrayList to avoid boxing elements.
|
||||
if (!(collection instanceof LongArrayList)) {
|
||||
|
@ -33,7 +33,6 @@ package com.google.protobuf;
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@ -171,7 +170,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
|
||||
@Override
|
||||
public Builder<K, V> toBuilder() {
|
||||
return new Builder<K, V>(metadata, key, value);
|
||||
return new Builder<K, V>(metadata, key, value, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -247,15 +246,19 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
private final Metadata<K, V> metadata;
|
||||
private K key;
|
||||
private V value;
|
||||
private boolean hasKey;
|
||||
private boolean hasValue;
|
||||
|
||||
private Builder(Metadata<K, V> metadata) {
|
||||
this(metadata, metadata.defaultKey, metadata.defaultValue);
|
||||
this(metadata, metadata.defaultKey, metadata.defaultValue, false, false);
|
||||
}
|
||||
|
||||
private Builder(Metadata<K, V> metadata, K key, V value) {
|
||||
private Builder(Metadata<K, V> metadata, K key, V value, boolean hasKey, boolean hasValue) {
|
||||
this.metadata = metadata;
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
this.hasKey = hasKey;
|
||||
this.hasValue = hasValue;
|
||||
}
|
||||
|
||||
public K getKey() {
|
||||
@ -268,21 +271,25 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
|
||||
public Builder<K, V> setKey(K key) {
|
||||
this.key = key;
|
||||
this.hasKey = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<K, V> clearKey() {
|
||||
this.key = metadata.defaultKey;
|
||||
this.hasKey = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<K, V> setValue(V value) {
|
||||
this.value = value;
|
||||
this.hasValue = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<K, V> clearValue() {
|
||||
this.value = metadata.defaultValue;
|
||||
this.hasValue = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -404,7 +411,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
@Override
|
||||
public boolean hasField(FieldDescriptor field) {
|
||||
checkFieldDescriptor(field);
|
||||
return true;
|
||||
return field.getNumber() == 1 ? hasKey : hasValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -438,7 +445,7 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Builder<K, V> clone() {
|
||||
return new Builder(metadata, key, value);
|
||||
return new Builder(metadata, key, value, hasKey, hasValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,4 +455,9 @@ public final class MapEntry<K, V> extends AbstractMessage {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns the metadata only for experimental runtime. */
|
||||
final Metadata<K, V> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
@ -223,4 +223,9 @@ public class MapEntryLite<K, V> {
|
||||
input.popLimit(oldLimit);
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
/** For experimental runtime internal use only. */
|
||||
Metadata<K, V> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -329,6 +331,8 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
checkNotNull(key);
|
||||
checkNotNull(value);
|
||||
return delegate.put(key, value);
|
||||
}
|
||||
|
||||
@ -341,6 +345,10 @@ public class MapField<K, V> implements MutabilityOracle {
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
mutabilityOracle.ensureMutable();
|
||||
for (K key : m.keySet()) {
|
||||
checkNotNull(key);
|
||||
checkNotNull(m.get(key));
|
||||
}
|
||||
delegate.putAll(m);
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,9 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import com.google.protobuf.Internal.EnumLite;
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import com.google.protobuf.Internal.EnumLite;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -88,6 +89,9 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
|
||||
@Override public V put(K key, V value) {
|
||||
ensureMutable();
|
||||
checkNotNull(key);
|
||||
|
||||
checkNotNull(value);
|
||||
return super.put(key, value);
|
||||
}
|
||||
|
||||
@ -97,6 +101,7 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
|
||||
@Override public void putAll(Map<? extends K, ? extends V> m) {
|
||||
ensureMutable();
|
||||
checkForNullKeysAndValues(m);
|
||||
super.putAll(m);
|
||||
}
|
||||
|
||||
@ -105,6 +110,13 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
|
||||
return super.remove(key);
|
||||
}
|
||||
|
||||
private static void checkForNullKeysAndValues(Map<?, ?> m) {
|
||||
for (Object key : m.keySet()) {
|
||||
checkNotNull(key);
|
||||
checkNotNull(m.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean equals(Object a, Object b) {
|
||||
if (a instanceof byte[] && b instanceof byte[]) {
|
||||
return Arrays.equals((byte[]) a, (byte[]) b);
|
||||
|
@ -31,6 +31,7 @@
|
||||
package com.google.protobuf;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Abstract interface for parsing Protocol Messages.
|
||||
@ -92,6 +93,18 @@ public interface Parser<MessageType> {
|
||||
// ---------------------------------------------------------------
|
||||
// Convenience methods.
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream)}.
|
||||
*/
|
||||
public MessageType parseFrom(ByteBuffer data) throws InvalidProtocolBufferException;
|
||||
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}. This is just a small wrapper around
|
||||
* {@link #parseFrom(CodedInputStream, ExtensionRegistryLite)}.
|
||||
*/
|
||||
public MessageType parseFrom(ByteBuffer data, ExtensionRegistryLite extensionRegistry)
|
||||
throws InvalidProtocolBufferException;
|
||||
/**
|
||||
* Parses {@code data} as a message of {@code MessageType}.
|
||||
* This is just a small wrapper around {@link #parseFrom(CodedInputStream)}.
|
||||
|
@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
/** A marker interface indicating that the collection supports primitives and is non-boxing. */
|
||||
interface PrimitiveNonBoxingCollection {}
|
@ -30,6 +30,8 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -290,9 +292,7 @@ public class RepeatedFieldBuilderV3
|
||||
*/
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(
|
||||
int index, MType message) {
|
||||
if (message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.set(index, message);
|
||||
if (builders != null) {
|
||||
@ -315,9 +315,7 @@ public class RepeatedFieldBuilderV3
|
||||
*/
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
|
||||
MType message) {
|
||||
if (message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.add(message);
|
||||
if (builders != null) {
|
||||
@ -339,9 +337,7 @@ public class RepeatedFieldBuilderV3
|
||||
*/
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
|
||||
int index, MType message) {
|
||||
if (message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(message);
|
||||
ensureMutableMessageList();
|
||||
messages.add(index, message);
|
||||
if (builders != null) {
|
||||
@ -363,9 +359,7 @@ public class RepeatedFieldBuilderV3
|
||||
public RepeatedFieldBuilderV3<MType, BType, IType> addAllMessages(
|
||||
Iterable<? extends MType> values) {
|
||||
for (final MType value : values) {
|
||||
if (value == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
checkNotNull(value);
|
||||
}
|
||||
|
||||
// If we can inspect the size, we can more efficiently add messages.
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.protobuf.Internal.checkNotNull;
|
||||
|
||||
/**
|
||||
* {@code SingleFieldBuilderV3} implements a structure that a protocol
|
||||
* message uses to hold a single field of another protocol message. It supports
|
||||
@ -84,10 +86,7 @@ public class SingleFieldBuilderV3
|
||||
MType message,
|
||||
AbstractMessage.BuilderParent parent,
|
||||
boolean isClean) {
|
||||
if (message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.message = message;
|
||||
this.message = checkNotNull(message);
|
||||
this.parent = parent;
|
||||
this.isClean = isClean;
|
||||
}
|
||||
@ -169,10 +168,7 @@ public class SingleFieldBuilderV3
|
||||
*/
|
||||
public SingleFieldBuilderV3<MType, BType, IType> setMessage(
|
||||
MType message) {
|
||||
if (message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
this.message = message;
|
||||
this.message = checkNotNull(message);
|
||||
if (builder != null) {
|
||||
builder.dispose();
|
||||
builder = null;
|
||||
|
@ -1442,7 +1442,7 @@ public final class TextFormat {
|
||||
|
||||
/**
|
||||
* Parse a single field from {@code tokenizer} and merge it into
|
||||
* {@code builder}.
|
||||
* {@code target}.
|
||||
*/
|
||||
private void mergeField(final Tokenizer tokenizer,
|
||||
final ExtensionRegistry extensionRegistry,
|
||||
@ -1712,6 +1712,8 @@ public final class TextFormat {
|
||||
}
|
||||
|
||||
if (field.isRepeated()) {
|
||||
// TODO(b/29122459): If field.isMapField() and FORBID_SINGULAR_OVERWRITES mode,
|
||||
// check for duplicate map keys here.
|
||||
target.addRepeatedField(field, value);
|
||||
} else if ((singularOverwritePolicy
|
||||
== SingularOverwritePolicy.FORBID_SINGULAR_OVERWRITES)
|
||||
|
@ -91,7 +91,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
* Construct an {@code UnknownFieldSet} around the given map. The map is
|
||||
* expected to be immutable.
|
||||
*/
|
||||
private UnknownFieldSet(final Map<Integer, Field> fields,
|
||||
UnknownFieldSet(final Map<Integer, Field> fields,
|
||||
final Map<Integer, Field> fieldsDescending) {
|
||||
this.fields = fields;
|
||||
}
|
||||
@ -715,7 +715,7 @@ public final class UnknownFieldSet implements MessageLite {
|
||||
* @see UnknownFieldSet
|
||||
*/
|
||||
public static final class Field {
|
||||
private Field() {}
|
||||
Field() {}
|
||||
|
||||
/** Construct a new {@link Builder}. */
|
||||
public static Builder newBuilder() {
|
||||
|
@ -33,19 +33,23 @@ package com.google.protobuf;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import sun.misc.Unsafe;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** Utility class for working with unsafe operations. */
|
||||
// TODO(nathanmittler): Add support for Android Memory/MemoryBlock
|
||||
final class UnsafeUtil {
|
||||
private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
|
||||
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
|
||||
private static final MemoryAccessor MEMORY_ACCESSOR = getMemoryAccessor();
|
||||
private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
|
||||
supportsUnsafeByteBufferOperations();
|
||||
private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
|
||||
private static final boolean HAS_UNSAFE_COPY_MEMORY = supportsUnsafeCopyMemory();
|
||||
private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
|
||||
private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.class, "address"));
|
||||
private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField());
|
||||
|
||||
private UnsafeUtil() {}
|
||||
|
||||
@ -53,20 +57,16 @@ final class UnsafeUtil {
|
||||
return HAS_UNSAFE_ARRAY_OPERATIONS;
|
||||
}
|
||||
|
||||
static boolean hasUnsafeCopyMemory() {
|
||||
return HAS_UNSAFE_COPY_MEMORY;
|
||||
}
|
||||
|
||||
static boolean hasUnsafeByteBufferOperations() {
|
||||
return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
|
||||
}
|
||||
|
||||
static Object allocateInstance(Class<?> clazz) {
|
||||
try {
|
||||
return UNSAFE.allocateInstance(clazz);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static long objectFieldOffset(Field field) {
|
||||
return UNSAFE.objectFieldOffset(field);
|
||||
return MEMORY_ACCESSOR.objectFieldOffset(field);
|
||||
}
|
||||
|
||||
static long getArrayBaseOffset() {
|
||||
@ -74,103 +74,103 @@ final class UnsafeUtil {
|
||||
}
|
||||
|
||||
static byte getByte(Object target, long offset) {
|
||||
return UNSAFE.getByte(target, offset);
|
||||
return MEMORY_ACCESSOR.getByte(target, offset);
|
||||
}
|
||||
|
||||
static void putByte(Object target, long offset, byte value) {
|
||||
UNSAFE.putByte(target, offset, value);
|
||||
MEMORY_ACCESSOR.putByte(target, offset, value);
|
||||
}
|
||||
|
||||
static int getInt(Object target, long offset) {
|
||||
return UNSAFE.getInt(target, offset);
|
||||
return MEMORY_ACCESSOR.getInt(target, offset);
|
||||
}
|
||||
|
||||
static void putInt(Object target, long offset, int value) {
|
||||
UNSAFE.putInt(target, offset, value);
|
||||
MEMORY_ACCESSOR.putInt(target, offset, value);
|
||||
}
|
||||
|
||||
static long getLong(Object target, long offset) {
|
||||
return UNSAFE.getLong(target, offset);
|
||||
return MEMORY_ACCESSOR.getLong(target, offset);
|
||||
}
|
||||
|
||||
static void putLong(Object target, long offset, long value) {
|
||||
UNSAFE.putLong(target, offset, value);
|
||||
MEMORY_ACCESSOR.putLong(target, offset, value);
|
||||
}
|
||||
|
||||
static boolean getBoolean(Object target, long offset) {
|
||||
return UNSAFE.getBoolean(target, offset);
|
||||
return MEMORY_ACCESSOR.getBoolean(target, offset);
|
||||
}
|
||||
|
||||
static void putBoolean(Object target, long offset, boolean value) {
|
||||
UNSAFE.putBoolean(target, offset, value);
|
||||
MEMORY_ACCESSOR.putBoolean(target, offset, value);
|
||||
}
|
||||
|
||||
static float getFloat(Object target, long offset) {
|
||||
return UNSAFE.getFloat(target, offset);
|
||||
return MEMORY_ACCESSOR.getFloat(target, offset);
|
||||
}
|
||||
|
||||
static void putFloat(Object target, long offset, float value) {
|
||||
UNSAFE.putFloat(target, offset, value);
|
||||
MEMORY_ACCESSOR.putFloat(target, offset, value);
|
||||
}
|
||||
|
||||
static double getDouble(Object target, long offset) {
|
||||
return UNSAFE.getDouble(target, offset);
|
||||
return MEMORY_ACCESSOR.getDouble(target, offset);
|
||||
}
|
||||
|
||||
static void putDouble(Object target, long offset, double value) {
|
||||
UNSAFE.putDouble(target, offset, value);
|
||||
MEMORY_ACCESSOR.putDouble(target, offset, value);
|
||||
}
|
||||
|
||||
static Object getObject(Object target, long offset) {
|
||||
return UNSAFE.getObject(target, offset);
|
||||
return MEMORY_ACCESSOR.getObject(target, offset);
|
||||
}
|
||||
|
||||
static void putObject(Object target, long offset, Object value) {
|
||||
UNSAFE.putObject(target, offset, value);
|
||||
MEMORY_ACCESSOR.putObject(target, offset, value);
|
||||
}
|
||||
|
||||
static void copyMemory(
|
||||
Object src, long srcOffset, Object target, long targetOffset, long length) {
|
||||
UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
|
||||
MEMORY_ACCESSOR.copyMemory(src, srcOffset, target, targetOffset, length);
|
||||
}
|
||||
|
||||
static byte getByte(long address) {
|
||||
return UNSAFE.getByte(address);
|
||||
return MEMORY_ACCESSOR.getByte(address);
|
||||
}
|
||||
|
||||
static void putByte(long address, byte value) {
|
||||
UNSAFE.putByte(address, value);
|
||||
MEMORY_ACCESSOR.putByte(address, value);
|
||||
}
|
||||
|
||||
static int getInt(long address) {
|
||||
return UNSAFE.getInt(address);
|
||||
return MEMORY_ACCESSOR.getInt(address);
|
||||
}
|
||||
|
||||
static void putInt(long address, int value) {
|
||||
UNSAFE.putInt(address, value);
|
||||
MEMORY_ACCESSOR.putInt(address, value);
|
||||
}
|
||||
|
||||
static long getLong(long address) {
|
||||
return UNSAFE.getLong(address);
|
||||
return MEMORY_ACCESSOR.getLong(address);
|
||||
}
|
||||
|
||||
static void putLong(long address, long value) {
|
||||
UNSAFE.putLong(address, value);
|
||||
MEMORY_ACCESSOR.putLong(address, value);
|
||||
}
|
||||
|
||||
static void copyMemory(long srcAddress, long targetAddress, long length) {
|
||||
UNSAFE.copyMemory(srcAddress, targetAddress, length);
|
||||
}
|
||||
|
||||
static void setMemory(long address, long numBytes, byte value) {
|
||||
UNSAFE.setMemory(address, numBytes, value);
|
||||
MEMORY_ACCESSOR.copyMemory(srcAddress, targetAddress, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
|
||||
*/
|
||||
static long addressOffset(ByteBuffer buffer) {
|
||||
return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
|
||||
return MEMORY_ACCESSOR.getLong(buffer, BUFFER_ADDRESS_OFFSET);
|
||||
}
|
||||
|
||||
static Object getStaticObject(Field field) {
|
||||
return MEMORY_ACCESSOR.getStaticObject(field);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,7 +181,7 @@ final class UnsafeUtil {
|
||||
try {
|
||||
unsafe =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<Unsafe>() {
|
||||
new PrivilegedExceptionAction<sun.misc.Unsafe>() {
|
||||
@Override
|
||||
public sun.misc.Unsafe run() throws Exception {
|
||||
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
|
||||
@ -204,69 +204,114 @@ final class UnsafeUtil {
|
||||
return unsafe;
|
||||
}
|
||||
|
||||
/** Get a {@link MemoryAccessor} appropriate for the platform, or null if not supported. */
|
||||
private static MemoryAccessor getMemoryAccessor() {
|
||||
if (UNSAFE == null) {
|
||||
return null;
|
||||
}
|
||||
return new JvmMemoryAccessor(UNSAFE);
|
||||
}
|
||||
|
||||
/** Indicates whether or not unsafe array operations are supported on this platform. */
|
||||
private static boolean supportsUnsafeArrayOperations() {
|
||||
boolean supported = false;
|
||||
if (UNSAFE != null) {
|
||||
try {
|
||||
Class<?> clazz = UNSAFE.getClass();
|
||||
clazz.getMethod("objectFieldOffset", Field.class);
|
||||
clazz.getMethod("allocateInstance", Class.class);
|
||||
clazz.getMethod("arrayBaseOffset", Class.class);
|
||||
clazz.getMethod("getByte", Object.class, long.class);
|
||||
clazz.getMethod("putByte", Object.class, long.class, byte.class);
|
||||
clazz.getMethod("getBoolean", Object.class, long.class);
|
||||
clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
|
||||
clazz.getMethod("getInt", Object.class, long.class);
|
||||
clazz.getMethod("putInt", Object.class, long.class, int.class);
|
||||
clazz.getMethod("getLong", Object.class, long.class);
|
||||
clazz.getMethod("putLong", Object.class, long.class, long.class);
|
||||
clazz.getMethod("getFloat", Object.class, long.class);
|
||||
clazz.getMethod("putFloat", Object.class, long.class, float.class);
|
||||
clazz.getMethod("getDouble", Object.class, long.class);
|
||||
clazz.getMethod("putDouble", Object.class, long.class, double.class);
|
||||
clazz.getMethod("getObject", Object.class, long.class);
|
||||
clazz.getMethod("putObject", Object.class, long.class, Object.class);
|
||||
clazz.getMethod(
|
||||
"copyMemory", Object.class, long.class, Object.class, long.class, long.class);
|
||||
supported = true;
|
||||
} catch (Throwable e) {
|
||||
// Do nothing.
|
||||
}
|
||||
if (UNSAFE == null) {
|
||||
return false;
|
||||
}
|
||||
return supported;
|
||||
try {
|
||||
Class<?> clazz = UNSAFE.getClass();
|
||||
clazz.getMethod("objectFieldOffset", Field.class);
|
||||
clazz.getMethod("arrayBaseOffset", Class.class);
|
||||
clazz.getMethod("getInt", Object.class, long.class);
|
||||
clazz.getMethod("putInt", Object.class, long.class, int.class);
|
||||
clazz.getMethod("getLong", Object.class, long.class);
|
||||
clazz.getMethod("putLong", Object.class, long.class, long.class);
|
||||
clazz.getMethod("getObject", Object.class, long.class);
|
||||
clazz.getMethod("putObject", Object.class, long.class, Object.class);
|
||||
clazz.getMethod("getByte", Object.class, long.class);
|
||||
clazz.getMethod("putByte", Object.class, long.class, byte.class);
|
||||
clazz.getMethod("getBoolean", Object.class, long.class);
|
||||
clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
|
||||
clazz.getMethod("getFloat", Object.class, long.class);
|
||||
clazz.getMethod("putFloat", Object.class, long.class, float.class);
|
||||
clazz.getMethod("getDouble", Object.class, long.class);
|
||||
clazz.getMethod("putDouble", Object.class, long.class, double.class);
|
||||
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"platform method missing - proto runtime falling back to safer methods: " + e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not unsafe copyMemory(object, long, object, long, long) operations are
|
||||
* supported on this platform.
|
||||
*/
|
||||
private static boolean supportsUnsafeCopyMemory() {
|
||||
if (UNSAFE == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = UNSAFE.getClass();
|
||||
clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
|
||||
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"copyMemory is missing from platform - proto runtime falling back to safer methods.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean supportsUnsafeByteBufferOperations() {
|
||||
boolean supported = false;
|
||||
if (UNSAFE != null) {
|
||||
try {
|
||||
Class<?> clazz = UNSAFE.getClass();
|
||||
// Methods for getting direct buffer address.
|
||||
clazz.getMethod("objectFieldOffset", Field.class);
|
||||
clazz.getMethod("getLong", Object.class, long.class);
|
||||
|
||||
clazz.getMethod("getByte", long.class);
|
||||
clazz.getMethod("putByte", long.class, byte.class);
|
||||
clazz.getMethod("getInt", long.class);
|
||||
clazz.getMethod("putInt", long.class, int.class);
|
||||
clazz.getMethod("getLong", long.class);
|
||||
clazz.getMethod("putLong", long.class, long.class);
|
||||
clazz.getMethod("setMemory", long.class, long.class, byte.class);
|
||||
clazz.getMethod("copyMemory", long.class, long.class, long.class);
|
||||
supported = true;
|
||||
} catch (Throwable e) {
|
||||
// Do nothing.
|
||||
}
|
||||
if (UNSAFE == null) {
|
||||
return false;
|
||||
}
|
||||
return supported;
|
||||
try {
|
||||
Class<?> clazz = UNSAFE.getClass();
|
||||
// Methods for getting direct buffer address.
|
||||
clazz.getMethod("objectFieldOffset", Field.class);
|
||||
clazz.getMethod("getLong", Object.class, long.class);
|
||||
|
||||
clazz.getMethod("getByte", long.class);
|
||||
clazz.getMethod("putByte", long.class, byte.class);
|
||||
clazz.getMethod("getInt", long.class);
|
||||
clazz.getMethod("putInt", long.class, int.class);
|
||||
clazz.getMethod("getLong", long.class);
|
||||
clazz.getMethod("putLong", long.class, long.class);
|
||||
clazz.getMethod("copyMemory", long.class, long.class, long.class);
|
||||
return true;
|
||||
} catch (Throwable e) {
|
||||
logger.log(
|
||||
Level.WARNING,
|
||||
"platform method missing - proto runtime falling back to safer methods: " + e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> Class<T> getClassForName(String name) {
|
||||
try {
|
||||
return (Class<T>) Class.forName(name);
|
||||
} catch (Throwable e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Finds the address field within a direct {@link Buffer}. */
|
||||
private static Field bufferAddressField() {
|
||||
return field(Buffer.class, "address");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not available.
|
||||
*/
|
||||
private static int byteArrayBaseOffset() {
|
||||
return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
|
||||
return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(byte[].class) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,7 +319,7 @@ final class UnsafeUtil {
|
||||
* available.
|
||||
*/
|
||||
private static long fieldOffset(Field field) {
|
||||
return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
|
||||
return field == null || MEMORY_ACCESSOR == null ? -1 : MEMORY_ACCESSOR.objectFieldOffset(field);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,4 +337,174 @@ final class UnsafeUtil {
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
private abstract static class MemoryAccessor {
|
||||
|
||||
sun.misc.Unsafe unsafe;
|
||||
|
||||
MemoryAccessor(sun.misc.Unsafe unsafe) {
|
||||
this.unsafe = unsafe;
|
||||
}
|
||||
|
||||
public final long objectFieldOffset(Field field) {
|
||||
return unsafe.objectFieldOffset(field);
|
||||
}
|
||||
|
||||
public abstract byte getByte(Object target, long offset);
|
||||
|
||||
public abstract void putByte(Object target, long offset, byte value);
|
||||
|
||||
public final int getInt(Object target, long offset) {
|
||||
return unsafe.getInt(target, offset);
|
||||
}
|
||||
|
||||
public final void putInt(Object target, long offset, int value) {
|
||||
unsafe.putInt(target, offset, value);
|
||||
}
|
||||
|
||||
public final long getLong(Object target, long offset) {
|
||||
return unsafe.getLong(target, offset);
|
||||
}
|
||||
|
||||
public final void putLong(Object target, long offset, long value) {
|
||||
unsafe.putLong(target, offset, value);
|
||||
}
|
||||
|
||||
public abstract boolean getBoolean(Object target, long offset);
|
||||
|
||||
public abstract void putBoolean(Object target, long offset, boolean value);
|
||||
|
||||
public abstract float getFloat(Object target, long offset);
|
||||
|
||||
public abstract void putFloat(Object target, long offset, float value);
|
||||
|
||||
public abstract double getDouble(Object target, long offset);
|
||||
|
||||
public abstract void putDouble(Object target, long offset, double value);
|
||||
|
||||
public final Object getObject(Object target, long offset) {
|
||||
return unsafe.getObject(target, offset);
|
||||
}
|
||||
|
||||
public final void putObject(Object target, long offset, Object value) {
|
||||
unsafe.putObject(target, offset, value);
|
||||
}
|
||||
|
||||
public final int arrayBaseOffset(Class<?> clazz) {
|
||||
return unsafe.arrayBaseOffset(clazz);
|
||||
}
|
||||
|
||||
public abstract byte getByte(long address);
|
||||
|
||||
public abstract void putByte(long address, byte value);
|
||||
|
||||
public abstract int getInt(long address);
|
||||
|
||||
public abstract void putInt(long address, int value);
|
||||
|
||||
public abstract long getLong(long address);
|
||||
|
||||
public abstract void putLong(long address, long value);
|
||||
|
||||
public abstract void copyMemory(long srcAddress, long targetAddress, long length);
|
||||
|
||||
public abstract void copyMemory(
|
||||
Object src, long srcOffset, Object target, long targetOffset, long length);
|
||||
|
||||
public abstract Object getStaticObject(Field field);
|
||||
}
|
||||
|
||||
private static final class JvmMemoryAccessor extends MemoryAccessor {
|
||||
|
||||
JvmMemoryAccessor(sun.misc.Unsafe unsafe) {
|
||||
super(unsafe);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(long address) {
|
||||
return unsafe.getByte(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putByte(long address, byte value) {
|
||||
unsafe.putByte(address, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(long address) {
|
||||
return unsafe.getInt(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putInt(long address, int value) {
|
||||
unsafe.putInt(address, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(long address) {
|
||||
return unsafe.getLong(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putLong(long address, long value) {
|
||||
unsafe.putLong(address, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getByte(Object target, long offset) {
|
||||
return unsafe.getByte(target, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putByte(Object target, long offset, byte value) {
|
||||
unsafe.putByte(target, offset, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(Object target, long offset) {
|
||||
return unsafe.getBoolean(target, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putBoolean(Object target, long offset, boolean value) {
|
||||
unsafe.putBoolean(target, offset, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(Object target, long offset) {
|
||||
return unsafe.getFloat(target, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putFloat(Object target, long offset, float value) {
|
||||
unsafe.putFloat(target, offset, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(Object target, long offset) {
|
||||
return unsafe.getDouble(target, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putDouble(Object target, long offset, double value) {
|
||||
unsafe.putDouble(target, offset, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyMemory(
|
||||
Object src, long srcOffset, Object target, long targetOffset, long length) {
|
||||
unsafe.copyMemory(src, srcOffset, target, targetOffset, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyMemory(long srcAddress, long targetAddress, long length) {
|
||||
unsafe.copyMemory(srcAddress, targetAddress, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getStaticObject(Field field) {
|
||||
return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1332,7 +1332,7 @@ final class Utf8 {
|
||||
// the index (relative to the start of the array) is also 8-byte aligned. We do this by
|
||||
// ANDing the index with 7 to determine the number of bytes that need to be read before
|
||||
// we're 8-byte aligned.
|
||||
final int unaligned = (int) offset & 7;
|
||||
final int unaligned = 8 - ((int) offset & 7);
|
||||
for (int j = unaligned; j > 0; j--) {
|
||||
if (UnsafeUtil.getByte(bytes, offset++) < 0) {
|
||||
return unaligned - j;
|
||||
|
@ -32,7 +32,6 @@ package com.google.protobuf;
|
||||
|
||||
import protobuf_unittest.UnittestProto.TestAllExtensions;
|
||||
import protobuf_unittest.UnittestProto.TestAllTypes;
|
||||
import java.io.IOException;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
@ -89,6 +88,7 @@ public class LazyFieldTest extends TestCase {
|
||||
assertFalse(message.equals(lazyField.getValue()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("EqualsIncompatibleType") // LazyField.equals() is not symmetric
|
||||
public void testEqualsObjectEx() throws Exception {
|
||||
TestAllExtensions message = TestUtil.getAllExtensionsSet();
|
||||
LazyField lazyField = createLazyFieldFromMessage(message);
|
||||
|
@ -52,6 +52,7 @@ import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime;
|
||||
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo;
|
||||
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals;
|
||||
import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof;
|
||||
import java.nio.ByteBuffer;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
@ -2174,6 +2175,24 @@ public class LiteTest extends TestCase {
|
||||
assertFalse(bar.equals(barPrime));
|
||||
}
|
||||
|
||||
public void testEqualsAndHashCodeForTrickySchemaTypes() {
|
||||
Foo foo1 = Foo.newBuilder()
|
||||
.build();
|
||||
Foo foo2 = Foo.newBuilder()
|
||||
.setSint64(1)
|
||||
.build();
|
||||
Foo foo3 = Foo.newBuilder()
|
||||
.putMyMap("key", "value2")
|
||||
.build();
|
||||
Foo foo4 = Foo.newBuilder()
|
||||
.setMyGroup(Foo.MyGroup.newBuilder().setValue(4).build())
|
||||
.build();
|
||||
|
||||
assertEqualsAndHashCodeAreFalse(foo1, foo2);
|
||||
assertEqualsAndHashCodeAreFalse(foo1, foo3);
|
||||
assertEqualsAndHashCodeAreFalse(foo1, foo4);
|
||||
}
|
||||
|
||||
public void testOneofEquals() throws Exception {
|
||||
TestOneofEquals.Builder builder = TestOneofEquals.newBuilder();
|
||||
TestOneofEquals message1 = builder.build();
|
||||
@ -2270,4 +2289,93 @@ public class LiteTest extends TestCase {
|
||||
// This tests that we don't infinite loop.
|
||||
TestRecursiveOneof.getDefaultInstance().hashCode();
|
||||
}
|
||||
|
||||
public void testParseFromByteBuffer() throws Exception {
|
||||
TestAllTypesLite message =
|
||||
TestAllTypesLite.newBuilder()
|
||||
.setOptionalInt32(123)
|
||||
.addRepeatedString("hello")
|
||||
.setOptionalNestedMessage(TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
|
||||
.build();
|
||||
|
||||
TestAllTypesLite copy =
|
||||
TestAllTypesLite.parseFrom(message.toByteString().asReadOnlyByteBuffer());
|
||||
|
||||
assertEquals(message, copy);
|
||||
}
|
||||
|
||||
public void testParseFromByteBufferThrows() {
|
||||
try {
|
||||
TestAllTypesLite.parseFrom(ByteBuffer.wrap(new byte[] { 0x5 }));
|
||||
fail();
|
||||
} catch (InvalidProtocolBufferException expected) {
|
||||
}
|
||||
|
||||
TestAllTypesLite message =
|
||||
TestAllTypesLite.newBuilder()
|
||||
.setOptionalInt32(123)
|
||||
.addRepeatedString("hello")
|
||||
.build();
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
|
||||
try {
|
||||
TestAllTypesLite.parseFrom(buffer);
|
||||
fail();
|
||||
} catch (InvalidProtocolBufferException expected) {
|
||||
assertEquals(
|
||||
TestAllTypesLite.newBuilder()
|
||||
.setOptionalInt32(123)
|
||||
.build(),
|
||||
expected.getUnfinishedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testParseFromByteBuffer_extensions() throws Exception {
|
||||
TestAllExtensionsLite message =
|
||||
TestAllExtensionsLite.newBuilder()
|
||||
.setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
|
||||
.addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
|
||||
.setExtension(
|
||||
UnittestLite.optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ)
|
||||
.setExtension(
|
||||
UnittestLite.optionalNestedMessageExtensionLite,
|
||||
TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
|
||||
.build();
|
||||
|
||||
ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
|
||||
UnittestLite.registerAllExtensions(registry);
|
||||
|
||||
TestAllExtensionsLite copy =
|
||||
TestAllExtensionsLite.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry);
|
||||
|
||||
assertEquals(message, copy);
|
||||
}
|
||||
|
||||
public void testParseFromByteBufferThrows_extensions() {
|
||||
ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
|
||||
UnittestLite.registerAllExtensions(registry);
|
||||
try {
|
||||
TestAllExtensionsLite.parseFrom(ByteBuffer.wrap(new byte[] { 0x5 }), registry);
|
||||
fail();
|
||||
} catch (InvalidProtocolBufferException expected) {
|
||||
}
|
||||
|
||||
TestAllExtensionsLite message =
|
||||
TestAllExtensionsLite.newBuilder()
|
||||
.setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
|
||||
.addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
|
||||
.build();
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(message.toByteArray(), 0, message.getSerializedSize() - 1);
|
||||
try {
|
||||
TestAllExtensionsLite.parseFrom(buffer, registry);
|
||||
fail();
|
||||
} catch (InvalidProtocolBufferException expected) {
|
||||
assertEquals(
|
||||
TestAllExtensionsLite.newBuilder()
|
||||
.setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
|
||||
.build(),
|
||||
expected.getUnfinishedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -759,6 +759,7 @@ public class MapForProto2Test extends TestCase {
|
||||
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
|
||||
}
|
||||
|
||||
// See additional coverage in TextFormatTest.java.
|
||||
public void testTextFormat() throws Exception {
|
||||
TestMap.Builder builder = TestMap.newBuilder();
|
||||
setMapValuesUsingAccessors(builder);
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.EnumDescriptor;
|
||||
import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
||||
@ -864,6 +864,7 @@ public class MapTest extends TestCase {
|
||||
assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
|
||||
}
|
||||
|
||||
// See additional coverage in TextFormatTest.java.
|
||||
public void testTextFormat() throws Exception {
|
||||
TestMap.Builder builder = TestMap.newBuilder();
|
||||
setMapValuesUsingAccessors(builder);
|
||||
@ -1483,4 +1484,41 @@ public class MapTest extends TestCase {
|
||||
map.put(key3, value3);
|
||||
return map;
|
||||
}
|
||||
|
||||
public void testMap_withNulls() {
|
||||
TestMap.Builder builder = TestMap.newBuilder();
|
||||
|
||||
try {
|
||||
builder.putStringToInt32Field(null, 3);
|
||||
fail();
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
builder.putAllStringToInt32Field(newMap(null, 3, "hi", 4));
|
||||
fail();
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
builder.putInt32ToMessageField(3, null);
|
||||
fail();
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
builder.putAllInt32ToMessageField(
|
||||
MapTest.<Integer, MessageValue>newMap(4, null, 5, null));
|
||||
fail();
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
|
||||
try {
|
||||
builder.putAllInt32ToMessageField(null);
|
||||
fail();
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
|
||||
assertArrayEquals(new byte[0], builder.build().toByteArray());
|
||||
}
|
||||
}
|
||||
|
@ -79,6 +79,8 @@ public class ParserTest extends TestCase {
|
||||
new ByteArrayInputStream(data), registry));
|
||||
assertMessageEquals(message, parser.parseFrom(
|
||||
CodedInputStream.newInstance(data), registry));
|
||||
assertMessageEquals(
|
||||
message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -99,6 +101,7 @@ public class ParserTest extends TestCase {
|
||||
new ByteArrayInputStream(data)));
|
||||
assertMessageEquals(message, parser.parseFrom(
|
||||
CodedInputStream.newInstance(data)));
|
||||
assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer()));
|
||||
}
|
||||
|
||||
private void assertMessageEquals(
|
||||
@ -178,6 +181,9 @@ public class ParserTest extends TestCase {
|
||||
public void testParseExtensions() throws Exception {
|
||||
assertRoundTripEquals(TestUtil.getAllExtensionsSet(),
|
||||
TestUtil.getExtensionRegistry());
|
||||
}
|
||||
|
||||
public void testParseExtensionsLite() throws Exception {
|
||||
assertRoundTripEquals(
|
||||
TestUtilLite.getAllLiteExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
|
||||
}
|
||||
@ -186,6 +192,9 @@ public class ParserTest extends TestCase {
|
||||
assertRoundTripEquals(TestUtil.getPackedSet());
|
||||
assertRoundTripEquals(TestUtil.getPackedExtensionsSet(),
|
||||
TestUtil.getExtensionRegistry());
|
||||
}
|
||||
|
||||
public void testParsePackedLite() throws Exception {
|
||||
assertRoundTripEquals(
|
||||
TestUtilLite.getLitePackedExtensionsSet(), TestUtilLite.getExtensionRegistryLite());
|
||||
}
|
||||
@ -195,15 +204,26 @@ public class ParserTest extends TestCase {
|
||||
TestAllTypes normalMessage = TestUtil.getAllSet();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
normalMessage.writeDelimitedTo(output);
|
||||
normalMessage.writeDelimitedTo(output);
|
||||
|
||||
InputStream input = new ByteArrayInputStream(output.toByteArray());
|
||||
assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input));
|
||||
assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input));
|
||||
}
|
||||
|
||||
public void testParseDelimitedToLite() throws Exception {
|
||||
// Write MessageLite with packed extension fields.
|
||||
TestPackedExtensionsLite packedMessage = TestUtilLite.getLitePackedExtensionsSet();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
packedMessage.writeDelimitedTo(output);
|
||||
packedMessage.writeDelimitedTo(output);
|
||||
|
||||
InputStream input = new ByteArrayInputStream(output.toByteArray());
|
||||
assertMessageEquals(
|
||||
normalMessage,
|
||||
normalMessage.getParserForType().parseDelimitedFrom(input));
|
||||
packedMessage,
|
||||
packedMessage
|
||||
.getParserForType()
|
||||
.parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite()));
|
||||
assertMessageEquals(
|
||||
packedMessage,
|
||||
packedMessage
|
||||
@ -314,8 +334,7 @@ public class ParserTest extends TestCase {
|
||||
|
||||
public void testParsingMergeLite() throws Exception {
|
||||
// Build messages.
|
||||
TestAllTypesLite.Builder builder =
|
||||
TestAllTypesLite.newBuilder();
|
||||
TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder();
|
||||
TestAllTypesLite msg1 = builder.setOptionalInt32(1).build();
|
||||
builder.clear();
|
||||
TestAllTypesLite msg2 = builder.setOptionalInt64(2).build();
|
||||
|
@ -2622,6 +2622,8 @@ public final class TestUtil {
|
||||
break;
|
||||
case FOO_NOT_SET:
|
||||
break;
|
||||
default:
|
||||
// TODO(b/18683919): go/enum-switch-lsc
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,12 @@
|
||||
|
||||
package com.google.protobuf;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy;
|
||||
import map_test.MapTestProto.TestMap;
|
||||
import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
|
||||
import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
|
||||
import protobuf_unittest.UnittestProto.OneString;
|
||||
@ -940,6 +943,7 @@ public class TextFormatTest extends TestCase {
|
||||
}
|
||||
|
||||
|
||||
// See additional coverage in testOneofOverwriteForbidden and testMapOverwriteForbidden.
|
||||
public void testParseNonRepeatedFields() throws Exception {
|
||||
assertParseSuccessWithOverwriteForbidden(
|
||||
"repeated_int32: 1\n" +
|
||||
@ -950,6 +954,7 @@ public class TextFormatTest extends TestCase {
|
||||
assertParseSuccessWithOverwriteForbidden(
|
||||
"repeated_nested_message { bb: 1 }\n" +
|
||||
"repeated_nested_message { bb: 2 }\n");
|
||||
|
||||
assertParseErrorWithOverwriteForbidden(
|
||||
"3:17: Non-repeated field " +
|
||||
"\"protobuf_unittest.TestAllTypes.optional_int32\" " +
|
||||
@ -988,6 +993,7 @@ public class TextFormatTest extends TestCase {
|
||||
assertParseSuccessWithOverwriteForbidden("repeated_int32: [ 1, 2 ]\n");
|
||||
assertParseSuccessWithOverwriteForbidden("RepeatedGroup [{ a: 1 },{ a: 2 }]\n");
|
||||
assertParseSuccessWithOverwriteForbidden("repeated_nested_message [{ bb: 1 }, { bb: 2 }]\n");
|
||||
// See also testMapShortForm.
|
||||
}
|
||||
|
||||
public void testParseShortRepeatedFormOfEmptyRepeatedFields() throws Exception {
|
||||
@ -995,6 +1001,7 @@ public class TextFormatTest extends TestCase {
|
||||
assertParseSuccessWithOverwriteForbidden("repeated_int32: []\n");
|
||||
assertParseSuccessWithOverwriteForbidden("RepeatedGroup []\n");
|
||||
assertParseSuccessWithOverwriteForbidden("repeated_nested_message []\n");
|
||||
// See also testMapShortFormEmpty.
|
||||
}
|
||||
|
||||
public void testParseShortRepeatedFormWithTrailingComma() throws Exception {
|
||||
@ -1010,6 +1017,7 @@ public class TextFormatTest extends TestCase {
|
||||
assertParseErrorWithOverwriteForbidden(
|
||||
"1:37: Expected \"{\".",
|
||||
"repeated_nested_message [{ bb: 1 }, ]\n");
|
||||
// See also testMapShortFormTrailingComma.
|
||||
}
|
||||
|
||||
public void testParseShortRepeatedFormOfNonRepeatedFields() throws Exception {
|
||||
@ -1057,6 +1065,90 @@ public class TextFormatTest extends TestCase {
|
||||
assertTrue(oneof.hasFooInt());
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// test map
|
||||
|
||||
public void testMapTextFormat() throws Exception {
|
||||
TestMap message =
|
||||
TestMap.newBuilder()
|
||||
.putInt32ToStringField(10, "apple")
|
||||
.putInt32ToStringField(20, "banana")
|
||||
.putInt32ToStringField(30, "cherry")
|
||||
.build();
|
||||
String text = TextFormat.printToUnicodeString(message);
|
||||
{
|
||||
TestMap.Builder dest = TestMap.newBuilder();
|
||||
TextFormat.merge(text, dest);
|
||||
assertThat(dest.build()).isEqualTo(message);
|
||||
}
|
||||
{
|
||||
TestMap.Builder dest = TestMap.newBuilder();
|
||||
parserWithOverwriteForbidden.merge(text, dest);
|
||||
assertThat(dest.build()).isEqualTo(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void testMapShortForm() throws Exception {
|
||||
String text =
|
||||
"string_to_int32_field [{ key: 'x' value: 10 }, { key: 'y' value: 20 }]\n"
|
||||
+ "int32_to_message_field "
|
||||
+ "[{ key: 1 value { value: 100 } }, { key: 2 value: { value: 200 } }]\n";
|
||||
TestMap.Builder dest = TestMap.newBuilder();
|
||||
parserWithOverwriteForbidden.merge(text, dest);
|
||||
TestMap message = dest.build();
|
||||
assertThat(message.getStringToInt32Field().size()).isEqualTo(2);
|
||||
assertThat(message.getInt32ToMessageField().size()).isEqualTo(2);
|
||||
assertThat(message.getStringToInt32Field().get("x")).isEqualTo(10);
|
||||
assertThat(message.getInt32ToMessageField().get(2).getValue()).isEqualTo(200);
|
||||
}
|
||||
|
||||
public void testMapShortFormEmpty() throws Exception {
|
||||
String text = "string_to_int32_field []\n"
|
||||
+ "int32_to_message_field: []\n";
|
||||
TestMap.Builder dest = TestMap.newBuilder();
|
||||
parserWithOverwriteForbidden.merge(text, dest);
|
||||
TestMap message = dest.build();
|
||||
assertThat(message.getStringToInt32Field().size()).isEqualTo(0);
|
||||
assertThat(message.getInt32ToMessageField().size()).isEqualTo(0);
|
||||
}
|
||||
|
||||
public void testMapShortFormTrailingComma() throws Exception {
|
||||
String text = "string_to_int32_field [{ key: 'x' value: 10 }, ]\n";
|
||||
TestMap.Builder dest = TestMap.newBuilder();
|
||||
try {
|
||||
parserWithOverwriteForbidden.merge(text, dest);
|
||||
fail("Expected parse exception.");
|
||||
} catch (TextFormat.ParseException e) {
|
||||
assertThat(e).hasMessageThat().isEqualTo("1:48: Expected \"{\".");
|
||||
}
|
||||
}
|
||||
|
||||
public void testMapOverwrite() throws Exception {
|
||||
String text =
|
||||
"int32_to_int32_field { key: 1 value: 10 }\n"
|
||||
+ "int32_to_int32_field { key: 2 value: 20 }\n"
|
||||
+ "int32_to_int32_field { key: 1 value: 30 }\n";
|
||||
|
||||
{
|
||||
// With default parser, last value set for the key holds.
|
||||
TestMap.Builder builder = TestMap.newBuilder();
|
||||
defaultParser.merge(text, builder);
|
||||
TestMap map = builder.build();
|
||||
assertThat(map.getInt32ToInt32Field().size()).isEqualTo(2);
|
||||
assertThat(map.getInt32ToInt32Field().get(1).intValue()).isEqualTo(30);
|
||||
}
|
||||
|
||||
{
|
||||
// With overwrite forbidden, same behavior.
|
||||
// TODO(b/29122459): Expect parse exception here.
|
||||
TestMap.Builder builder = TestMap.newBuilder();
|
||||
defaultParser.merge(text, builder);
|
||||
TestMap map = builder.build();
|
||||
assertThat(map.getInt32ToInt32Field().size()).isEqualTo(2);
|
||||
assertThat(map.getInt32ToInt32Field().get(1).intValue()).isEqualTo(30);
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// test location information
|
||||
|
||||
|
@ -46,6 +46,14 @@ message TestOneofEquals {
|
||||
message Foo {
|
||||
optional int32 value = 1;
|
||||
repeated Bar bar = 2;
|
||||
map<string, string> my_map = 3;
|
||||
oneof Single {
|
||||
sint64 sint64 = 4;
|
||||
// LINT: ALLOW_GROUPS
|
||||
group MyGroup = 5 {
|
||||
optional int32 value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
extensions 100 to max;
|
||||
}
|
||||
|
@ -137,6 +137,7 @@
|
||||
<include>**/MutabilityOracle.java</include>
|
||||
<include>**/NioByteString.java</include>
|
||||
<include>**/Parser.java</include>
|
||||
<include>**/PrimitiveNonBoxingCollection.java</include>
|
||||
<include>**/ProtobufArrayList.java</include>
|
||||
<include>**/ProtocolStringList.java</include>
|
||||
<include>**/RopeByteString.java</include>
|
||||
|
10
java/pom.xml
10
java/pom.xml
@ -11,7 +11,7 @@
|
||||
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-parent</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.0</version>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>Protocol Buffers [Parent]</name>
|
||||
@ -84,7 +84,13 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>18.0</version>
|
||||
<version>20.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.truth</groupId>
|
||||
<artifactId>truth</artifactId>
|
||||
<scope>test</scope>
|
||||
<version>0.32</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-parent</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>protobuf-java-util</artifactId>
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
package com.google.protobuf.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@ -102,7 +103,9 @@ public class JsonFormat {
|
||||
* Creates a {@link Printer} with default configurations.
|
||||
*/
|
||||
public static Printer printer() {
|
||||
return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false, false);
|
||||
return new Printer(
|
||||
TypeRegistry.getEmptyTypeRegistry(), false, Collections.<FieldDescriptor>emptySet(),
|
||||
false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,16 +113,27 @@ public class JsonFormat {
|
||||
*/
|
||||
public static class Printer {
|
||||
private final TypeRegistry registry;
|
||||
private final boolean includingDefaultValueFields;
|
||||
// NOTE: There are 3 states for these *defaultValueFields variables:
|
||||
// 1) Default - alwaysOutput is false & including is empty set. Fields only output if they are
|
||||
// set to non-default values.
|
||||
// 2) No-args includingDefaultValueFields() called - alwaysOutput is true & including is
|
||||
// irrelevant (but set to empty set). All fields are output regardless of their values.
|
||||
// 3) includingDefaultValueFields(Set<FieldDescriptor>) called - alwaysOutput is false &
|
||||
// including is set to the specified set. Fields in that set are always output & fields not
|
||||
// in that set are only output if set to non-default values.
|
||||
private boolean alwaysOutputDefaultValueFields;
|
||||
private Set<FieldDescriptor> includingDefaultValueFields;
|
||||
private final boolean preservingProtoFieldNames;
|
||||
private final boolean omittingInsignificantWhitespace;
|
||||
|
||||
private Printer(
|
||||
TypeRegistry registry,
|
||||
boolean includingDefaultValueFields,
|
||||
boolean alwaysOutputDefaultValueFields,
|
||||
Set<FieldDescriptor> includingDefaultValueFields,
|
||||
boolean preservingProtoFieldNames,
|
||||
boolean omittingInsignificantWhitespace) {
|
||||
this.registry = registry;
|
||||
this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
|
||||
this.includingDefaultValueFields = includingDefaultValueFields;
|
||||
this.preservingProtoFieldNames = preservingProtoFieldNames;
|
||||
this.omittingInsignificantWhitespace = omittingInsignificantWhitespace;
|
||||
@ -137,6 +151,7 @@ public class JsonFormat {
|
||||
}
|
||||
return new Printer(
|
||||
registry,
|
||||
alwaysOutputDefaultValueFields,
|
||||
includingDefaultValueFields,
|
||||
preservingProtoFieldNames,
|
||||
omittingInsignificantWhitespace);
|
||||
@ -149,8 +164,41 @@ public class JsonFormat {
|
||||
* {@link Printer}.
|
||||
*/
|
||||
public Printer includingDefaultValueFields() {
|
||||
checkUnsetIncludingDefaultValueFields();
|
||||
return new Printer(
|
||||
registry, true, preservingProtoFieldNames, omittingInsignificantWhitespace);
|
||||
registry,
|
||||
true,
|
||||
Collections.<FieldDescriptor>emptySet(),
|
||||
preservingProtoFieldNames,
|
||||
omittingInsignificantWhitespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Printer} that will also print default-valued fields if their
|
||||
* FieldDescriptors are found in the supplied set. Empty repeated fields and map fields will be
|
||||
* printed as well, if they match. The new Printer clones all other configurations from the
|
||||
* current {@link Printer}. Call includingDefaultValueFields() with no args to unconditionally
|
||||
* output all fields.
|
||||
*/
|
||||
public Printer includingDefaultValueFields(Set<FieldDescriptor> fieldsToAlwaysOutput) {
|
||||
Preconditions.checkArgument(
|
||||
null != fieldsToAlwaysOutput && !fieldsToAlwaysOutput.isEmpty(),
|
||||
"Non-empty Set must be supplied for includingDefaultValueFields.");
|
||||
|
||||
checkUnsetIncludingDefaultValueFields();
|
||||
return new Printer(
|
||||
registry,
|
||||
false,
|
||||
fieldsToAlwaysOutput,
|
||||
preservingProtoFieldNames,
|
||||
omittingInsignificantWhitespace);
|
||||
}
|
||||
|
||||
private void checkUnsetIncludingDefaultValueFields() {
|
||||
if (alwaysOutputDefaultValueFields || !includingDefaultValueFields.isEmpty()) {
|
||||
throw new IllegalStateException(
|
||||
"JsonFormat includingDefaultValueFields has already been set.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -161,15 +209,20 @@ public class JsonFormat {
|
||||
*/
|
||||
public Printer preservingProtoFieldNames() {
|
||||
return new Printer(
|
||||
registry, includingDefaultValueFields, true, omittingInsignificantWhitespace);
|
||||
registry,
|
||||
alwaysOutputDefaultValueFields,
|
||||
includingDefaultValueFields,
|
||||
true,
|
||||
omittingInsignificantWhitespace);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@link Printer} that will omit all insignificant whitespace
|
||||
* in the JSON output. This new Printer clones all other configurations from the
|
||||
* current Printer. Insignificant whitespace is defined by the JSON spec as whitespace
|
||||
* that appear between JSON structural elements:
|
||||
* Create a new {@link Printer} that will omit all insignificant whitespace in the JSON output.
|
||||
* This new Printer clones all other configurations from the current Printer. Insignificant
|
||||
* whitespace is defined by the JSON spec as whitespace that appear between JSON structural
|
||||
* elements:
|
||||
*
|
||||
* <pre>
|
||||
* ws = *(
|
||||
* %x20 / ; Space
|
||||
@ -177,18 +230,24 @@ public class JsonFormat {
|
||||
* %x0A / ; Line feed or New line
|
||||
* %x0D ) ; Carriage return
|
||||
* </pre>
|
||||
*
|
||||
* See <a href="https://tools.ietf.org/html/rfc7159">https://tools.ietf.org/html/rfc7159</a>
|
||||
* current {@link Printer}.
|
||||
*/
|
||||
public Printer omittingInsignificantWhitespace() {
|
||||
return new Printer(registry, includingDefaultValueFields, preservingProtoFieldNames, true);
|
||||
return new Printer(
|
||||
registry,
|
||||
alwaysOutputDefaultValueFields,
|
||||
includingDefaultValueFields,
|
||||
preservingProtoFieldNames,
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a protobuf message to JSON format.
|
||||
*
|
||||
* @throws InvalidProtocolBufferException if the message contains Any types
|
||||
* that can't be resolved.
|
||||
* @throws InvalidProtocolBufferException if the message contains Any types that can't be
|
||||
* resolved.
|
||||
* @throws IOException if writing to the output fails.
|
||||
*/
|
||||
public void appendTo(MessageOrBuilder message, Appendable output) throws IOException {
|
||||
@ -196,6 +255,7 @@ public class JsonFormat {
|
||||
// mobile.
|
||||
new PrinterImpl(
|
||||
registry,
|
||||
alwaysOutputDefaultValueFields,
|
||||
includingDefaultValueFields,
|
||||
preservingProtoFieldNames,
|
||||
output,
|
||||
@ -428,19 +488,16 @@ public class JsonFormat {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
/**
|
||||
* ignored by compact printer
|
||||
*/
|
||||
/** ignored by compact printer */
|
||||
@Override
|
||||
public void indent() {}
|
||||
|
||||
/**
|
||||
* ignored by compact printer
|
||||
*/
|
||||
/** ignored by compact printer */
|
||||
@Override
|
||||
public void outdent() {}
|
||||
|
||||
/**
|
||||
* Print text to the output stream.
|
||||
*/
|
||||
/** Print text to the output stream. */
|
||||
@Override
|
||||
public void print(final CharSequence text) throws IOException {
|
||||
output.append(text);
|
||||
}
|
||||
@ -458,18 +515,17 @@ public class JsonFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Indent text by two spaces. After calling Indent(), two spaces will be
|
||||
* inserted at the beginning of each line of text. Indent() may be called
|
||||
* multiple times to produce deeper indents.
|
||||
* Indent text by two spaces. After calling Indent(), two spaces will be inserted at the
|
||||
* beginning of each line of text. Indent() may be called multiple times to produce deeper
|
||||
* indents.
|
||||
*/
|
||||
@Override
|
||||
public void indent() {
|
||||
indent.append(" ");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduces the current indent level by two spaces, or crashes if the indent
|
||||
* level is zero.
|
||||
*/
|
||||
/** Reduces the current indent level by two spaces, or crashes if the indent level is zero. */
|
||||
@Override
|
||||
public void outdent() {
|
||||
final int length = indent.length();
|
||||
if (length < 2) {
|
||||
@ -478,9 +534,8 @@ public class JsonFormat {
|
||||
indent.delete(length - 2, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print text to the output stream.
|
||||
*/
|
||||
/** Print text to the output stream. */
|
||||
@Override
|
||||
public void print(final CharSequence text) throws IOException {
|
||||
final int size = text.length();
|
||||
int pos = 0;
|
||||
@ -512,7 +567,8 @@ public class JsonFormat {
|
||||
*/
|
||||
private static final class PrinterImpl {
|
||||
private final TypeRegistry registry;
|
||||
private final boolean includingDefaultValueFields;
|
||||
private final boolean alwaysOutputDefaultValueFields;
|
||||
private final Set<FieldDescriptor> includingDefaultValueFields;
|
||||
private final boolean preservingProtoFieldNames;
|
||||
private final TextGenerator generator;
|
||||
// We use Gson to help handle string escapes.
|
||||
@ -526,11 +582,13 @@ public class JsonFormat {
|
||||
|
||||
PrinterImpl(
|
||||
TypeRegistry registry,
|
||||
boolean includingDefaultValueFields,
|
||||
boolean alwaysOutputDefaultValueFields,
|
||||
Set<FieldDescriptor> includingDefaultValueFields,
|
||||
boolean preservingProtoFieldNames,
|
||||
Appendable jsonOutput,
|
||||
boolean omittingInsignificantWhitespace) {
|
||||
this.registry = registry;
|
||||
this.alwaysOutputDefaultValueFields = alwaysOutputDefaultValueFields;
|
||||
this.includingDefaultValueFields = includingDefaultValueFields;
|
||||
this.preservingProtoFieldNames = preservingProtoFieldNames;
|
||||
this.gson = GsonHolder.DEFAULT_GSON;
|
||||
@ -781,23 +839,26 @@ public class JsonFormat {
|
||||
printedField = true;
|
||||
}
|
||||
Map<FieldDescriptor, Object> fieldsToPrint = null;
|
||||
if (includingDefaultValueFields) {
|
||||
fieldsToPrint = new TreeMap<FieldDescriptor, Object>();
|
||||
if (alwaysOutputDefaultValueFields || !includingDefaultValueFields.isEmpty()) {
|
||||
fieldsToPrint = new TreeMap<FieldDescriptor, Object>(message.getAllFields());
|
||||
for (FieldDescriptor field : message.getDescriptorForType().getFields()) {
|
||||
if (field.isOptional()) {
|
||||
if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
|
||||
&& !message.hasField(field)){
|
||||
&& !message.hasField(field)) {
|
||||
// Always skip empty optional message fields. If not we will recurse indefinitely if
|
||||
// a message has itself as a sub-field.
|
||||
continue;
|
||||
}
|
||||
OneofDescriptor oneof = field.getContainingOneof();
|
||||
if (oneof != null && !message.hasField(field)) {
|
||||
// Skip all oneof fields except the one that is actually set
|
||||
// Skip all oneof fields except the one that is actually set
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fieldsToPrint.put(field, message.getField(field));
|
||||
if (!fieldsToPrint.containsKey(field)
|
||||
&& (alwaysOutputDefaultValueFields || includingDefaultValueFields.contains(field))) {
|
||||
fieldsToPrint.put(field, message.getField(field));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fieldsToPrint = message.getAllFields();
|
||||
@ -1451,45 +1512,6 @@ public class JsonFormat {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default value for a field type. Note that we use proto3
|
||||
* language defaults and ignore any default values set through the
|
||||
* proto "default" option.
|
||||
*/
|
||||
private Object getDefaultValue(FieldDescriptor field, Message.Builder builder) {
|
||||
switch (field.getType()) {
|
||||
case INT32:
|
||||
case SINT32:
|
||||
case SFIXED32:
|
||||
case UINT32:
|
||||
case FIXED32:
|
||||
return 0;
|
||||
case INT64:
|
||||
case SINT64:
|
||||
case SFIXED64:
|
||||
case UINT64:
|
||||
case FIXED64:
|
||||
return 0L;
|
||||
case FLOAT:
|
||||
return 0.0f;
|
||||
case DOUBLE:
|
||||
return 0.0;
|
||||
case BOOL:
|
||||
return false;
|
||||
case STRING:
|
||||
return "";
|
||||
case BYTES:
|
||||
return ByteString.EMPTY;
|
||||
case ENUM:
|
||||
return field.getEnumType().getValues().get(0);
|
||||
case MESSAGE:
|
||||
case GROUP:
|
||||
return builder.newBuilderForField(field).getDefaultInstanceForType();
|
||||
default:
|
||||
throw new IllegalStateException("Invalid field type: " + field.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeRepeatedField(
|
||||
FieldDescriptor field, JsonElement json, Message.Builder builder)
|
||||
throws InvalidProtocolBufferException {
|
||||
|
@ -297,7 +297,7 @@ public final class Timestamps {
|
||||
* Convert a Timestamp to the number of microseconds elapsed from the epoch.
|
||||
*
|
||||
* <p>The result will be rounded down to the nearest microsecond. E.g., if the timestamp
|
||||
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 millisecond.
|
||||
* represents "1969-12-31T23:59:59.999999999Z", it will be rounded to -1 microsecond.
|
||||
*/
|
||||
public static long toMicros(Timestamp timestamp) {
|
||||
checkValid(timestamp);
|
||||
|
@ -34,6 +34,7 @@ import com.google.protobuf.Any;
|
||||
import com.google.protobuf.BoolValue;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.BytesValue;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.DoubleValue;
|
||||
import com.google.protobuf.FloatValue;
|
||||
import com.google.protobuf.Int32Value;
|
||||
@ -68,9 +69,12 @@ import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class JsonFormatTest extends TestCase {
|
||||
@ -282,8 +286,8 @@ public class JsonFormatTest extends TestCase {
|
||||
assertEquals(9012, message.getOptionalSint32());
|
||||
assertEquals(3456, message.getOptionalFixed32());
|
||||
assertEquals(7890, message.getOptionalSfixed32());
|
||||
assertEquals(1.5f, message.getOptionalFloat());
|
||||
assertEquals(1.25, message.getOptionalDouble());
|
||||
assertEquals(1.5f, message.getOptionalFloat(), 0.0f);
|
||||
assertEquals(1.25, message.getOptionalDouble(), 0.0);
|
||||
assertEquals(true, message.getOptionalBool());
|
||||
}
|
||||
|
||||
@ -1223,6 +1227,115 @@ public class JsonFormatTest extends TestCase {
|
||||
+ "}",
|
||||
JsonFormat.printer().includingDefaultValueFields().print(message));
|
||||
|
||||
Set<FieldDescriptor> fixedFields = new HashSet<FieldDescriptor>();
|
||||
for (FieldDescriptor fieldDesc : TestAllTypes.getDescriptor().getFields()) {
|
||||
if (fieldDesc.getName().contains("_fixed")) {
|
||||
fixedFields.add(fieldDesc);
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
"{\n"
|
||||
+ " \"optionalFixed32\": 0,\n"
|
||||
+ " \"optionalFixed64\": \"0\",\n"
|
||||
+ " \"repeatedFixed32\": [],\n"
|
||||
+ " \"repeatedFixed64\": []\n"
|
||||
+ "}",
|
||||
JsonFormat.printer().includingDefaultValueFields(fixedFields).print(message));
|
||||
|
||||
TestAllTypes messageNonDefaults =
|
||||
message.toBuilder().setOptionalInt64(1234).setOptionalFixed32(3232).build();
|
||||
assertEquals(
|
||||
"{\n"
|
||||
+ " \"optionalInt64\": \"1234\",\n"
|
||||
+ " \"optionalFixed32\": 3232,\n"
|
||||
+ " \"optionalFixed64\": \"0\",\n"
|
||||
+ " \"repeatedFixed32\": [],\n"
|
||||
+ " \"repeatedFixed64\": []\n"
|
||||
+ "}",
|
||||
JsonFormat.printer().includingDefaultValueFields(fixedFields).print(messageNonDefaults));
|
||||
|
||||
try {
|
||||
JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields();
|
||||
fail("IllegalStateException is expected.");
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
assertTrue(
|
||||
"Exception message should mention includingDefaultValueFields.",
|
||||
e.getMessage().contains("includingDefaultValueFields"));
|
||||
}
|
||||
|
||||
try {
|
||||
JsonFormat.printer().includingDefaultValueFields().includingDefaultValueFields(fixedFields);
|
||||
fail("IllegalStateException is expected.");
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
assertTrue(
|
||||
"Exception message should mention includingDefaultValueFields.",
|
||||
e.getMessage().contains("includingDefaultValueFields"));
|
||||
}
|
||||
|
||||
try {
|
||||
JsonFormat.printer().includingDefaultValueFields(fixedFields).includingDefaultValueFields();
|
||||
fail("IllegalStateException is expected.");
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
assertTrue(
|
||||
"Exception message should mention includingDefaultValueFields.",
|
||||
e.getMessage().contains("includingDefaultValueFields"));
|
||||
}
|
||||
|
||||
try {
|
||||
JsonFormat.printer()
|
||||
.includingDefaultValueFields(fixedFields)
|
||||
.includingDefaultValueFields(fixedFields);
|
||||
fail("IllegalStateException is expected.");
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
assertTrue(
|
||||
"Exception message should mention includingDefaultValueFields.",
|
||||
e.getMessage().contains("includingDefaultValueFields"));
|
||||
}
|
||||
|
||||
Set<FieldDescriptor> intFields = new HashSet<FieldDescriptor>();
|
||||
for (FieldDescriptor fieldDesc : TestAllTypes.getDescriptor().getFields()) {
|
||||
if (fieldDesc.getName().contains("_int")) {
|
||||
intFields.add(fieldDesc);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
JsonFormat.printer()
|
||||
.includingDefaultValueFields(intFields)
|
||||
.includingDefaultValueFields(fixedFields);
|
||||
fail("IllegalStateException is expected.");
|
||||
} catch (IllegalStateException e) {
|
||||
// Expected.
|
||||
assertTrue(
|
||||
"Exception message should mention includingDefaultValueFields.",
|
||||
e.getMessage().contains("includingDefaultValueFields"));
|
||||
}
|
||||
|
||||
try {
|
||||
JsonFormat.printer().includingDefaultValueFields(null);
|
||||
fail("IllegalArgumentException is expected.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected.
|
||||
assertTrue(
|
||||
"Exception message should mention includingDefaultValueFields.",
|
||||
e.getMessage().contains("includingDefaultValueFields"));
|
||||
}
|
||||
|
||||
try {
|
||||
JsonFormat.printer().includingDefaultValueFields(Collections.<FieldDescriptor>emptySet());
|
||||
fail("IllegalArgumentException is expected.");
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Expected.
|
||||
assertTrue(
|
||||
"Exception message should mention includingDefaultValueFields.",
|
||||
e.getMessage().contains("includingDefaultValueFields"));
|
||||
}
|
||||
|
||||
TestMap mapMessage = TestMap.getDefaultInstance();
|
||||
assertEquals("{\n}", JsonFormat.printer().print(mapMessage));
|
||||
assertEquals(
|
||||
@ -1291,16 +1404,17 @@ public class JsonFormatTest extends TestCase {
|
||||
assertEquals("{\n}", JsonFormat.printer().includingDefaultValueFields().print(oneofMessage));
|
||||
|
||||
oneofMessage = TestOneof.newBuilder().setOneofInt32(42).build();
|
||||
assertEquals("{\n \"oneofInt32\": 42\n}",
|
||||
JsonFormat.printer().print(oneofMessage));
|
||||
assertEquals("{\n \"oneofInt32\": 42\n}",
|
||||
assertEquals("{\n \"oneofInt32\": 42\n}", JsonFormat.printer().print(oneofMessage));
|
||||
assertEquals(
|
||||
"{\n \"oneofInt32\": 42\n}",
|
||||
JsonFormat.printer().includingDefaultValueFields().print(oneofMessage));
|
||||
|
||||
TestOneof.Builder oneofBuilder = TestOneof.newBuilder();
|
||||
mergeFromJson("{\n" + " \"oneofNullValue\": null \n" + "}", oneofBuilder);
|
||||
oneofMessage = oneofBuilder.build();
|
||||
assertEquals("{\n \"oneofNullValue\": null\n}", JsonFormat.printer().print(oneofMessage));
|
||||
assertEquals("{\n \"oneofNullValue\": null\n}",
|
||||
assertEquals(
|
||||
"{\n \"oneofNullValue\": null\n}",
|
||||
JsonFormat.printer().includingDefaultValueFields().print(oneofMessage));
|
||||
}
|
||||
|
||||
@ -1432,11 +1546,12 @@ public class JsonFormatTest extends TestCase {
|
||||
|
||||
// Test that we are not leaking out JSON exceptions.
|
||||
public void testJsonException() throws Exception {
|
||||
InputStream throwingInputStream = new InputStream() {
|
||||
public int read() throws IOException {
|
||||
throw new IOException("12345");
|
||||
}
|
||||
};
|
||||
InputStream throwingInputStream =
|
||||
new InputStream() {
|
||||
public int read() throws IOException {
|
||||
throw new IOException("12345");
|
||||
}
|
||||
};
|
||||
InputStreamReader throwingReader = new InputStreamReader(throwingInputStream);
|
||||
// When the underlying reader throws IOException, JsonFormat should forward
|
||||
// through this IOException.
|
||||
|
@ -12,5 +12,5 @@
|
||||
export DOCKERFILE_DIR=jenkins/docker32
|
||||
export DOCKER_RUN_SCRIPT=jenkins/pull_request_in_docker.sh
|
||||
export OUTPUT_DIR=testoutput
|
||||
export TEST_SET="php_all_32"
|
||||
export TEST_SET="php_all"
|
||||
./jenkins/build_and_run_docker.sh
|
||||
|
@ -129,7 +129,7 @@ ENV MVN mvn --batch-mode
|
||||
RUN cd /tmp && \
|
||||
git clone https://github.com/google/protobuf.git && \
|
||||
cd protobuf && \
|
||||
git reset 6b27c1f981a9a93918e4039f236ead27165a8e91 && \
|
||||
git reset --hard c2b3b3e04e7a023efe06f2107705b45428847800 && \
|
||||
./autogen.sh && \
|
||||
./configure && \
|
||||
make -j4 && \
|
||||
@ -147,6 +147,23 @@ RUN cd php-5.5.38 && ./configure --enable-maintainer-zts --prefix=/usr/local/php
|
||||
make && make install && cd ..
|
||||
RUN cd php-5.5.38 && make clean && ./configure --prefix=/usr/local/php-5.5 && \
|
||||
make && make install && cd ..
|
||||
|
||||
RUN wget http://am1.php.net/get/php-5.6.30.tar.bz2/from/this/mirror
|
||||
RUN mv mirror php-5.6.30.tar.bz2
|
||||
RUN tar -xvf php-5.6.30.tar.bz2
|
||||
RUN cd php-5.6.30 && ./configure --enable-maintainer-zts --prefix=/usr/local/php-5.6-zts && \
|
||||
make && make install && cd ..
|
||||
RUN cd php-5.6.30 && make clean && ./configure --prefix=/usr/local/php-5.6 && \
|
||||
make && make install && cd ..
|
||||
|
||||
RUN wget http://am1.php.net/get/php-7.0.18.tar.bz2/from/this/mirror
|
||||
RUN mv mirror php-7.0.18.tar.bz2
|
||||
RUN tar -xvf php-7.0.18.tar.bz2
|
||||
RUN cd php-7.0.18 && ./configure --enable-maintainer-zts --prefix=/usr/local/php-7.0-zts && \
|
||||
make && make install && cd ..
|
||||
RUN cd php-7.0.18 && make clean && ./configure --prefix=/usr/local/php-7.0 && \
|
||||
make && make install && cd ..
|
||||
|
||||
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
|
||||
RUN php composer-setup.php
|
||||
RUN mv composer.phar /usr/bin/composer
|
||||
@ -157,21 +174,21 @@ RUN cd /tmp && \
|
||||
rm -rf protobuf && \
|
||||
git clone https://github.com/google/protobuf.git && \
|
||||
cd protobuf && \
|
||||
git reset 46ae90dc5e145b12fffa7e053a908a9f3e066286 && \
|
||||
git reset --hard 6b27c1f981a9a93918e4039f236ead27165a8e91 && \
|
||||
cd php && \
|
||||
ln -sfn /usr/local/php-5.5/bin/php /usr/bin/php && \
|
||||
ln -sfn /usr/local/php-5.5/bin/php-config /usr/bin/php-config && \
|
||||
ln -sfn /usr/local/php-5.5/bin/phpize /usr/bin/phpize && \
|
||||
composer install && \
|
||||
mv vendor /usr/local/vendor-5.5 && \
|
||||
ln -sfn /usr/bin/php5.6 /usr/bin/php && \
|
||||
ln -sfn /usr/bin/php-config5.6 /usr/bin/php-config && \
|
||||
ln -sfn /usr/bin/phpize5.6 /usr/bin/phpize && \
|
||||
ln -sfn /usr/local/php-5.6/bin/php /usr/bin/php && \
|
||||
ln -sfn /usr/local/php-5.6/bin/php-config /usr/bin/php-config && \
|
||||
ln -sfn /usr/local/php-5.6/bin/phpize /usr/bin/phpize && \
|
||||
composer install && \
|
||||
mv vendor /usr/local/vendor-5.6 && \
|
||||
ln -sfn /usr/bin/php7.0 /usr/bin/php && \
|
||||
ln -sfn /usr/bin/php-config7.0 /usr/bin/php-config && \
|
||||
ln -sfn /usr/bin/phpize7.0 /usr/bin/phpize && \
|
||||
ln -sfn /usr/local/php-7.0/bin/php /usr/bin/php && \
|
||||
ln -sfn /usr/local/php-7.0/bin/php-config /usr/bin/php-config && \
|
||||
ln -sfn /usr/local/php-7.0/bin/phpize /usr/bin/phpize && \
|
||||
composer install && \
|
||||
mv vendor /usr/local/vendor-7.0
|
||||
|
||||
|
@ -64,7 +64,7 @@ RUN php -r "unlink('composer-setup.php');"
|
||||
RUN cd /tmp && \
|
||||
git clone https://github.com/google/protobuf.git && \
|
||||
cd protobuf/php && \
|
||||
git reset 6b27c1f981a9a93918e4039f236ead27165a8e91 && \
|
||||
git reset --hard 6b27c1f981a9a93918e4039f236ead27165a8e91 && \
|
||||
ln -sfn /usr/bin/php5.5 /usr/bin/php && \
|
||||
ln -sfn /usr/bin/php-config5.5 /usr/bin/php-config && \
|
||||
ln -sfn /usr/bin/phpize5.5 /usr/bin/phpize && \
|
||||
@ -80,14 +80,31 @@ RUN cd /tmp && \
|
||||
ln -sfn /usr/bin/phpize7.0 /usr/bin/phpize && \
|
||||
composer install && \
|
||||
mv vendor /usr/local/vendor-7.0
|
||||
|
||||
RUN wget http://am1.php.net/get/php-5.5.38.tar.bz2/from/this/mirror
|
||||
RUN mv mirror php-5.5.38.tar.bz2
|
||||
RUN tar -xvf php-5.5.38.tar.bz2
|
||||
RUN cd php-5.5.38 && ./configure --enable-maintainer-zts --prefix=/usr/local/php-5.5-zts && \
|
||||
make && make install && make clean && cd ..
|
||||
RUN cd php-5.5.38 && ./configure --enable-bcmath --prefix=/usr/local/php-5.5-bc && \
|
||||
RUN cd php-5.5.38 && make clean && ./configure --enable-bcmath --prefix=/usr/local/php-5.5 && \
|
||||
make && make install && make clean && cd ..
|
||||
|
||||
RUN wget http://am1.php.net/get/php-5.6.30.tar.bz2/from/this/mirror
|
||||
RUN mv mirror php-5.6.30.tar.bz2
|
||||
RUN tar -xvf php-5.6.30.tar.bz2
|
||||
RUN cd php-5.6.30 && ./configure --enable-maintainer-zts --prefix=/usr/local/php-5.6-zts && \
|
||||
make && make install && cd ..
|
||||
RUN cd php-5.6.30 && make clean && ./configure --enable-bcmath --prefix=/usr/local/php-5.6 && \
|
||||
make && make install && cd ..
|
||||
|
||||
RUN wget http://am1.php.net/get/php-7.0.18.tar.bz2/from/this/mirror
|
||||
RUN mv mirror php-7.0.18.tar.bz2
|
||||
RUN tar -xvf php-7.0.18.tar.bz2
|
||||
RUN cd php-7.0.18 && ./configure --enable-maintainer-zts --prefix=/usr/local/php-7.0-zts && \
|
||||
make && make install && cd ..
|
||||
RUN cd php-7.0.18 && make clean && ./configure --enable-bcmath --prefix=/usr/local/php-7.0 && \
|
||||
make && make install && cd ..
|
||||
|
||||
##################
|
||||
# Python dependencies
|
||||
|
||||
|
@ -71,7 +71,7 @@ jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) {
|
||||
*/
|
||||
this.nextMethod_ = null;
|
||||
|
||||
/** @private {Array.<number>} */
|
||||
/** @private {?Array<number|boolean|string>} */
|
||||
this.elements_ = null;
|
||||
|
||||
/** @private {number} */
|
||||
@ -100,7 +100,7 @@ jspb.BinaryIterator.prototype.init_ =
|
||||
this.decoder_ = opt_decoder;
|
||||
this.nextMethod_ = opt_next;
|
||||
}
|
||||
this.elements_ = opt_elements ? opt_elements : null;
|
||||
this.elements_ = opt_elements || null;
|
||||
this.cursor_ = 0;
|
||||
this.nextValue_ = null;
|
||||
this.atEnd_ = !this.decoder_ && !this.elements_;
|
||||
@ -953,6 +953,7 @@ jspb.BinaryDecoder.prototype.readString = function(length) {
|
||||
var end = cursor + length;
|
||||
var codeUnits = [];
|
||||
|
||||
var result = '';
|
||||
while (cursor < end) {
|
||||
var c = bytes[cursor++];
|
||||
if (c < 128) { // Regular 7-bit ASCII.
|
||||
@ -973,7 +974,7 @@ jspb.BinaryDecoder.prototype.readString = function(length) {
|
||||
var c2 = bytes[cursor++];
|
||||
var c3 = bytes[cursor++];
|
||||
var c4 = bytes[cursor++];
|
||||
// Characters written on 4 bytes have 21 bits for a codepoint.
|
||||
// Characters written on 4 bytes have 21 bits for a codepoint.
|
||||
// We can't fit that on 16bit characters, so we use surrogates.
|
||||
var codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63);
|
||||
// Surrogates formula from wikipedia.
|
||||
@ -986,10 +987,14 @@ jspb.BinaryDecoder.prototype.readString = function(length) {
|
||||
var high = ((codepoint >> 10) & 1023) + 0xD800;
|
||||
codeUnits.push(high, low);
|
||||
}
|
||||
|
||||
// Avoid exceeding the maximum stack size when calling {@code apply}.
|
||||
if (codeUnits.length >= 8192) {
|
||||
result += String.fromCharCode.apply(null, codeUnits);
|
||||
codeUnits.length = 0;
|
||||
}
|
||||
}
|
||||
// String.fromCharCode.apply is faster than manually appending characters on
|
||||
// Chrome 25+, and generates no additional cons string garbage.
|
||||
var result = String.fromCharCode.apply(null, codeUnits);
|
||||
result += String.fromCharCode.apply(null, codeUnits);
|
||||
this.cursor_ = cursor;
|
||||
return result;
|
||||
};
|
||||
|
@ -210,6 +210,25 @@ describe('binaryDecoderTest', function() {
|
||||
assertEquals(hashD, decoder.readFixedHash64());
|
||||
});
|
||||
|
||||
/**
|
||||
* Tests reading and writing large strings
|
||||
*/
|
||||
it('testLargeStrings', function() {
|
||||
var encoder = new jspb.BinaryEncoder();
|
||||
|
||||
var len = 150000;
|
||||
var long_string = '';
|
||||
for (var i = 0; i < len; i++) {
|
||||
long_string += 'a';
|
||||
}
|
||||
|
||||
encoder.writeString(long_string);
|
||||
|
||||
var decoder = jspb.BinaryDecoder.alloc(encoder.end());
|
||||
|
||||
assertEquals(long_string, decoder.readString(len));
|
||||
});
|
||||
|
||||
/**
|
||||
* Test encoding and decoding utf-8.
|
||||
*/
|
||||
|
@ -355,8 +355,8 @@ jspb.BinaryEncoder.prototype.writeInt64 = function(value) {
|
||||
*/
|
||||
jspb.BinaryEncoder.prototype.writeInt64String = function(value) {
|
||||
goog.asserts.assert(value == Math.floor(value));
|
||||
goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
|
||||
(value < jspb.BinaryConstants.TWO_TO_63));
|
||||
goog.asserts.assert((+value >= -jspb.BinaryConstants.TWO_TO_63) &&
|
||||
(+value < jspb.BinaryConstants.TWO_TO_63));
|
||||
jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(value));
|
||||
this.writeSplitFixed64(jspb.utils.split64Low, jspb.utils.split64High);
|
||||
};
|
||||
|
@ -971,7 +971,7 @@ jspb.BinaryReader.prototype.readFixedHash64 = function() {
|
||||
|
||||
/**
|
||||
* Reads a packed scalar field using the supplied raw reader function.
|
||||
* @param {function()} decodeMethod
|
||||
* @param {function(this:jspb.BinaryDecoder)} decodeMethod
|
||||
* @return {!Array}
|
||||
* @private
|
||||
*/
|
||||
|
@ -430,7 +430,7 @@ jspb.utils.joinHash64 = function(bitsLow, bitsHigh) {
|
||||
|
||||
/**
|
||||
* Individual digits for number->string conversion.
|
||||
* @const {!Array.<number>}
|
||||
* @const {!Array.<string>}
|
||||
*/
|
||||
jspb.utils.DIGITS = [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
|
@ -596,8 +596,8 @@ jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
|
||||
*/
|
||||
jspb.BinaryWriter.prototype.writeSint64String = function(field, value) {
|
||||
if (value == null) return;
|
||||
goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
|
||||
(value < jspb.BinaryConstants.TWO_TO_63));
|
||||
goog.asserts.assert((+value >= -jspb.BinaryConstants.TWO_TO_63) &&
|
||||
(+value < jspb.BinaryConstants.TWO_TO_63));
|
||||
this.writeZigzagVarint64String_(field, value);
|
||||
};
|
||||
|
||||
|
@ -47,7 +47,7 @@ goog.require('jspb.BinaryWriter');
|
||||
* @param {function()} func This function should throw an error when run.
|
||||
*/
|
||||
function assertFails(func) {
|
||||
var e = assertThrows(func);
|
||||
assertThrows(func);
|
||||
}
|
||||
|
||||
|
||||
|
10
js/map.js
10
js/map.js
@ -136,7 +136,7 @@ jspb.Map.prototype.toArray = function() {
|
||||
*
|
||||
* @param {boolean=} includeInstance Whether to include the JSPB instance for
|
||||
* transitional soy proto support: http://goto/soy-param-migration
|
||||
* @param {!function((boolean|undefined),!V):!Object=} valueToObject
|
||||
* @param {!function((boolean|undefined),V):!Object=} valueToObject
|
||||
* The static toObject() method, if V is a message type.
|
||||
* @return {!Array<!Array<!Object>>}
|
||||
*/
|
||||
@ -146,7 +146,7 @@ jspb.Map.prototype.toObject = function(includeInstance, valueToObject) {
|
||||
for (var i = 0; i < rawArray.length; i++) {
|
||||
var entry = this.map_[rawArray[i][0].toString()];
|
||||
this.wrapEntry_(entry);
|
||||
var valueWrapper = /** @type {!V|undefined} */ (entry.valueWrapper);
|
||||
var valueWrapper = /** @type {V|undefined} */ (entry.valueWrapper);
|
||||
if (valueWrapper) {
|
||||
goog.asserts.assert(valueToObject);
|
||||
entries.push([entry.key, valueToObject(includeInstance, valueWrapper)]);
|
||||
@ -412,8 +412,8 @@ jspb.Map.prototype.has = function(key) {
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @param {!function(this:jspb.BinaryWriter,number,K)} keyWriterFn
|
||||
* The method on BinaryWriter that writes type K to the stream.
|
||||
* @param {!function(this:jspb.BinaryWriter,number,V)|
|
||||
* function(this:jspb.BinaryReader,V,?)} valueWriterFn
|
||||
* @param {!function(this:jspb.BinaryWriter,number,V,?=)|
|
||||
* function(this:jspb.BinaryWriter,number,V,?)} valueWriterFn
|
||||
* The method on BinaryWriter that writes type V to the stream. May be
|
||||
* writeMessage, in which case the second callback arg form is used.
|
||||
* @param {function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback
|
||||
@ -509,7 +509,7 @@ jspb.Map.prototype.stringKeys_ = function() {
|
||||
|
||||
|
||||
/**
|
||||
* @param {!K} key The entry's key.
|
||||
* @param {K} key The entry's key.
|
||||
* @param {V=} opt_value The entry's value wrapper.
|
||||
* @constructor
|
||||
* @struct
|
||||
|
@ -106,8 +106,9 @@ jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
|
||||
/**
|
||||
* Stores binary-related information for a single extension field.
|
||||
* @param {!jspb.ExtensionFieldInfo<T>} fieldInfo
|
||||
* @param {!function(number,?)} binaryReaderFn
|
||||
* @param {!function(number,?)|function(number,?,?,?,?,?)} binaryWriterFn
|
||||
* @param {function(this:jspb.BinaryReader,number,?)} binaryReaderFn
|
||||
* @param {function(this:jspb.BinaryWriter,number,?)
|
||||
* |function(this:jspb.BinaryWriter,number,?,?,?,?,?)} binaryWriterFn
|
||||
* @param {function(?,?)=} opt_binaryMessageSerializeFn
|
||||
* @param {function(?,?)=} opt_binaryMessageDeserializeFn
|
||||
* @param {boolean=} opt_isPacked
|
||||
@ -141,6 +142,21 @@ jspb.ExtensionFieldInfo.prototype.isMessageType = function() {
|
||||
|
||||
/**
|
||||
* Base class for all JsPb messages.
|
||||
*
|
||||
* Several common methods (toObject, serializeBinary, in particular) are not
|
||||
* defined on the prototype to encourage code patterns that minimize code bloat
|
||||
* due to otherwise unused code on all protos contained in the project.
|
||||
*
|
||||
* If you want to call these methods on a generic message, either
|
||||
* pass in your instance of method as a parameter:
|
||||
* someFunction(instanceOfKnownProto,
|
||||
* KnownProtoClass.prototype.serializeBinary);
|
||||
* or use a lambda that knows the type:
|
||||
* someFunction(()=>instanceOfKnownProto.serializeBinary());
|
||||
* or, if you don't care about code size, just suppress the
|
||||
* WARNING - Property serializeBinary never defined on jspb.Message
|
||||
* and call it the intuitive way.
|
||||
*
|
||||
* @constructor
|
||||
* @struct
|
||||
*/
|
||||
@ -524,7 +540,7 @@ jspb.Message.toObjectExtension = function(proto, obj, extensions,
|
||||
* @param {!jspb.Message} proto The proto whose extensions to convert.
|
||||
* @param {*} writer The binary-format writer to write to.
|
||||
* @param {!Object} extensions The proto class' registered extensions.
|
||||
* @param {function(jspb.ExtensionFieldInfo) : *} getExtensionFn The proto
|
||||
* @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo) : *} getExtensionFn The proto
|
||||
* class' getExtension function. Passed for effective dead code removal.
|
||||
*/
|
||||
jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
|
||||
@ -570,10 +586,13 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
|
||||
* Reads an extension field from the given reader and, if a valid extension,
|
||||
* sets the extension value.
|
||||
* @param {!jspb.Message} msg A jspb proto.
|
||||
* @param {{skipField:function(),getFieldNumber:function():number}} reader
|
||||
* @param {{
|
||||
* skipField:function(this:jspb.BinaryReader),
|
||||
* getFieldNumber:function(this:jspb.BinaryReader):number
|
||||
* }} reader
|
||||
* @param {!Object} extensions The extensions object.
|
||||
* @param {function(jspb.ExtensionFieldInfo)} getExtensionFn
|
||||
* @param {function(jspb.ExtensionFieldInfo, ?)} setExtensionFn
|
||||
* @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo)} getExtensionFn
|
||||
* @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo, ?)} setExtensionFn
|
||||
*/
|
||||
jspb.Message.readBinaryExtension = function(msg, reader, extensions,
|
||||
getExtensionFn, setExtensionFn) {
|
||||
|
@ -40,6 +40,7 @@ goog.require('goog.userAgent');
|
||||
goog.require('jspb.Message');
|
||||
|
||||
// CommonJS-LoadFromFile: test8_pb proto.jspb.exttest.nested
|
||||
goog.require('proto.jspb.exttest.nested.TestNestedExtensionsMessage');
|
||||
goog.require('proto.jspb.exttest.nested.TestOuterMessage');
|
||||
|
||||
// CommonJS-LoadFromFile: test5_pb proto.jspb.exttest.beta
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "google-protobuf",
|
||||
"version": "3.2.0",
|
||||
"version": "3.3.0",
|
||||
"description": "Protocol Buffers for JavaScript",
|
||||
"main": "google-protobuf.js",
|
||||
"files": [
|
||||
|
@ -59,6 +59,8 @@ typedef GPB_ENUM(GPBDuration_FieldNumber) {
|
||||
* two Timestamp values is a Duration and it can be added or subtracted
|
||||
* from a Timestamp. Range is approximately +-10,000 years.
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||
*
|
||||
* Timestamp start = ...;
|
||||
@ -98,12 +100,23 @@ typedef GPB_ENUM(GPBDuration_FieldNumber) {
|
||||
* td = datetime.timedelta(days=3, minutes=10)
|
||||
* duration = Duration()
|
||||
* duration.FromTimedelta(td)
|
||||
*
|
||||
* # JSON Mapping
|
||||
*
|
||||
* In JSON format, the Duration type is encoded as a string rather than an
|
||||
* object, where the string ends in the suffix "s" (indicating seconds) and
|
||||
* is preceded by the number of seconds, with nanoseconds expressed as
|
||||
* fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||
* encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||
* be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||
* microsecond should be expressed in JSON format as "3.000001s".
|
||||
**/
|
||||
@interface GPBDuration : GPBMessage
|
||||
|
||||
/**
|
||||
* Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
* to +315,576,000,000 inclusive.
|
||||
* to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||
* 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||
**/
|
||||
@property(nonatomic, readwrite) int64_t seconds;
|
||||
|
||||
|
@ -64,6 +64,8 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
|
||||
* and from RFC 3339 date strings.
|
||||
* See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt).
|
||||
*
|
||||
* # Examples
|
||||
*
|
||||
* Example 1: Compute Timestamp from POSIX `time()`.
|
||||
*
|
||||
* Timestamp timestamp;
|
||||
@ -103,6 +105,29 @@ typedef GPB_ENUM(GPBTimestamp_FieldNumber) {
|
||||
*
|
||||
* timestamp = Timestamp()
|
||||
* timestamp.GetCurrentTime()
|
||||
*
|
||||
* # JSON Mapping
|
||||
*
|
||||
* In JSON format, the Timestamp type is encoded as a string in the
|
||||
* [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||
* format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||
* where {year} is always expressed using four digits while {month}, {day},
|
||||
* {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||
* seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||
* are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||
* is required, though only UTC (as indicated by "Z") is presently supported.
|
||||
*
|
||||
* For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||
* 01:30 UTC on January 15, 2017.
|
||||
*
|
||||
* In JavaScript, one can convert a Date object to this format using the
|
||||
* standard [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString]
|
||||
* method. In Python, a standard `datetime.datetime` object can be converted
|
||||
* to this format using [`strftime`](https://docs.python.org/2/library/time.html#time.strftime)
|
||||
* with the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one
|
||||
* can use the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||
* http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime())
|
||||
* to obtain a formatter capable of generating timestamps in this format.
|
||||
**/
|
||||
@interface GPBTimestamp : GPBMessage
|
||||
|
||||
|
@ -69,19 +69,20 @@ static zend_function_entry repeated_field_iter_methods[] = {
|
||||
|
||||
// Forward declare static functions.
|
||||
|
||||
static zend_object_value repeated_field_create(zend_class_entry *ce TSRMLS_DC);
|
||||
static void repeated_field_free(void *object TSRMLS_DC);
|
||||
static int repeated_field_array_init(zval *array, upb_fieldtype_t type,
|
||||
uint size ZEND_FILE_LINE_DC);
|
||||
static void repeated_field_free_element(void *object);
|
||||
static void repeated_field_write_dimension(zval *object, zval *offset,
|
||||
zval *value TSRMLS_DC);
|
||||
static int repeated_field_has_dimension(zval *object, zval *offset TSRMLS_DC);
|
||||
static HashTable *repeated_field_get_gc(zval *object, zval ***table,
|
||||
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);
|
||||
static void repeated_field_iter_free(void *object 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
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RepeatedField creation/desctruction
|
||||
@ -90,76 +91,91 @@ static void repeated_field_iter_free(void *object TSRMLS_DC);
|
||||
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;
|
||||
|
||||
void repeated_field_init(TSRMLS_D) {
|
||||
zend_class_entry class_type;
|
||||
const char* class_name = "Google\\Protobuf\\Internal\\RepeatedField";
|
||||
INIT_CLASS_ENTRY_EX(class_type, class_name, strlen(class_name),
|
||||
repeated_field_methods);
|
||||
// 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
|
||||
|
||||
repeated_field_type = zend_register_internal_class(&class_type TSRMLS_CC);
|
||||
repeated_field_type->create_object = repeated_field_create;
|
||||
PHP_PROTO_OBJECT_DTOR_START(RepeatedField, repeated_field)
|
||||
PHP_PROTO_OBJECT_DTOR_END
|
||||
|
||||
zend_class_implements(repeated_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess,
|
||||
zend_ce_aggregate, spl_ce_Countable);
|
||||
// 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)
|
||||
|
||||
repeated_field_handlers = PEMALLOC(zend_object_handlers);
|
||||
memcpy(repeated_field_handlers, zend_get_std_object_handlers(),
|
||||
sizeof(zend_object_handlers));
|
||||
repeated_field_handlers->write_dimension = repeated_field_write_dimension;
|
||||
repeated_field_handlers->get_gc = repeated_field_get_gc;
|
||||
// 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);
|
||||
}
|
||||
|
||||
static zend_object_value repeated_field_create(zend_class_entry *ce TSRMLS_DC) {
|
||||
zend_object_value retval = {0};
|
||||
RepeatedField *intern;
|
||||
|
||||
intern = emalloc(sizeof(RepeatedField));
|
||||
memset(intern, 0, sizeof(RepeatedField));
|
||||
|
||||
zend_object_std_init(&intern->std, ce TSRMLS_CC);
|
||||
object_properties_init(&intern->std, ce);
|
||||
|
||||
intern->array = NULL;
|
||||
intern->type = 0;
|
||||
intern->msg_ce = NULL;
|
||||
|
||||
retval.handle = zend_objects_store_put(
|
||||
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
|
||||
(zend_objects_free_object_storage_t)repeated_field_free, NULL TSRMLS_CC);
|
||||
retval.handlers = repeated_field_handlers;
|
||||
|
||||
return retval;
|
||||
static inline void php_proto_array_object_release(void *value) {
|
||||
zval_ptr_dtor(value);
|
||||
}
|
||||
|
||||
static void repeated_field_free(void *object TSRMLS_DC) {
|
||||
RepeatedField *intern = object;
|
||||
zend_object_std_dtor(&intern->std TSRMLS_CC);
|
||||
zval_ptr_dtor(&intern->array);
|
||||
efree(object);
|
||||
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) {
|
||||
void* ptr = Z_PTR_P(value);
|
||||
zend_object* object = *(zend_object**)ptr;
|
||||
if(--GC_REFCOUNT(object) == 0) {
|
||||
zend_objects_store_del(object);
|
||||
}
|
||||
efree(ptr);
|
||||
}
|
||||
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) {
|
||||
ALLOC_HASHTABLE(Z_ARRVAL_P(array));
|
||||
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, ZVAL_PTR_DTOR, 0);
|
||||
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, repeated_field_free_element,
|
||||
0);
|
||||
zend_hash_init(Z_ARRVAL_P(array), size, NULL,
|
||||
php_proto_array_default_release, 0);
|
||||
}
|
||||
Z_TYPE_P(array) = IS_ARRAY;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static void repeated_field_free_element(void *object) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RepeatedField Handlers
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -168,23 +184,25 @@ static void repeated_field_write_dimension(zval *object, zval *offset,
|
||||
zval *value TSRMLS_DC) {
|
||||
uint64_t index;
|
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(object TSRMLS_CC);
|
||||
HashTable *ht = HASH_OF(intern->array);
|
||||
RepeatedField *intern = UNBOX(RepeatedField, object);
|
||||
HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
|
||||
int size = native_slot_size(intern->type);
|
||||
|
||||
unsigned char memory[NATIVE_SLOT_MAX_SIZE];
|
||||
memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
|
||||
|
||||
if (!native_slot_set(intern->type, intern->msg_ce, memory, value TSRMLS_CC)) {
|
||||
if (!native_slot_set_by_array(intern->type, intern->msg_ce, memory,
|
||||
value TSRMLS_CC)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!offset || Z_TYPE_P(offset) == IS_NULL) {
|
||||
index = zend_hash_num_elements(HASH_OF(intern->array));
|
||||
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", index);
|
||||
zend_error(E_USER_ERROR, "Element at %llu doesn't exist.\n",
|
||||
(long long unsigned int)index);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@ -192,15 +210,19 @@ static void repeated_field_write_dimension(zval *object, zval *offset,
|
||||
}
|
||||
}
|
||||
|
||||
zend_hash_index_update(ht, index, memory, size, NULL);
|
||||
php_proto_zend_hash_index_update(ht, index, memory, size, NULL);
|
||||
}
|
||||
|
||||
#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 = zend_object_store_get_object(object TSRMLS_CC);
|
||||
return HASH_OF(intern->array);
|
||||
RepeatedField *intern = UNBOX(RepeatedField, object);
|
||||
return PHP_PROTO_HASH_OF(intern->array);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -208,10 +230,10 @@ static HashTable *repeated_field_get_gc(zval *object, zval ***table,
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC) {
|
||||
HashTable *ht = HASH_OF(intern->array);
|
||||
HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
|
||||
void *value;
|
||||
|
||||
if (zend_hash_index_find(ht, index, (void **)&value) == FAILURE) {
|
||||
if (php_proto_zend_hash_index_find(ht, index, (void **)&value) == FAILURE) {
|
||||
zend_error(E_USER_ERROR, "Element at %d doesn't exist.\n", index);
|
||||
return NULL;
|
||||
}
|
||||
@ -219,35 +241,37 @@ void *repeated_field_index_native(RepeatedField *intern, int index TSRMLS_DC) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void repeated_field_push_native(RepeatedField *intern, void *value TSRMLS_DC) {
|
||||
HashTable *ht = HASH_OF(intern->array);
|
||||
void repeated_field_push_native(RepeatedField *intern, void *value) {
|
||||
HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
|
||||
int size = native_slot_size(intern->type);
|
||||
zend_hash_next_index_insert(ht, (void **)value, size, NULL);
|
||||
php_proto_zend_hash_next_index_insert(ht, (void **)value, size, NULL);
|
||||
}
|
||||
|
||||
void repeated_field_create_with_field(zend_class_entry *ce,
|
||||
const upb_fielddef *field,
|
||||
zval **repeated_field TSRMLS_DC) {
|
||||
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 TSRMLS_CC);
|
||||
repeated_field_create_with_type(ce, type, msg_ce, repeated_field TSRMLS_CC);
|
||||
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,
|
||||
zval **repeated_field TSRMLS_DC) {
|
||||
MAKE_STD_ZVAL(*repeated_field);
|
||||
Z_TYPE_PP(repeated_field) = IS_OBJECT;
|
||||
Z_OBJVAL_PP(repeated_field) =
|
||||
repeated_field_type->create_object(repeated_field_type 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 =
|
||||
zend_object_store_get_object(*repeated_field TSRMLS_CC);
|
||||
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
|
||||
}
|
||||
@ -271,12 +295,16 @@ PHP_METHOD(RepeatedField, __construct) {
|
||||
return;
|
||||
}
|
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
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
|
||||
|
||||
if (intern->type == UPB_TYPE_MESSAGE && klass == NULL) {
|
||||
zend_error(E_USER_ERROR, "Message type must have concrete class.");
|
||||
@ -313,10 +341,10 @@ PHP_METHOD(RepeatedField, offsetExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RepeatedField *intern = UNBOX(RepeatedField, getThis());
|
||||
|
||||
RETURN_BOOL(index >= 0 &&
|
||||
index < zend_hash_num_elements(HASH_OF(intern->array)));
|
||||
index < zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -336,15 +364,16 @@ PHP_METHOD(RepeatedField, offsetGet) {
|
||||
return;
|
||||
}
|
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
HashTable *table = HASH_OF(intern->array);
|
||||
RepeatedField *intern = UNBOX(RepeatedField, getThis());
|
||||
HashTable *table = PHP_PROTO_HASH_OF(intern->array);
|
||||
|
||||
if (zend_hash_index_find(table, index, (void **)&memory) == FAILURE) {
|
||||
if (php_proto_zend_hash_index_find(table, index, (void **)&memory) == FAILURE) {
|
||||
zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
|
||||
return;
|
||||
}
|
||||
|
||||
native_slot_get(intern->type, memory, return_value_ptr TSRMLS_CC);
|
||||
native_slot_get_by_array(intern->type, memory,
|
||||
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -379,16 +408,16 @@ PHP_METHOD(RepeatedField, offsetUnset) {
|
||||
return;
|
||||
}
|
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
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(HASH_OF(intern->array)) - 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);
|
||||
return;
|
||||
}
|
||||
|
||||
zend_hash_index_del(HASH_OF(intern->array), index);
|
||||
zend_hash_index_del(PHP_PROTO_HASH_OF(intern->array), index);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -397,13 +426,13 @@ PHP_METHOD(RepeatedField, offsetUnset) {
|
||||
* @return long The number of stored elements.
|
||||
*/
|
||||
PHP_METHOD(RepeatedField, count) {
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RepeatedField *intern = UNBOX(RepeatedField, getThis());
|
||||
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->array)));
|
||||
RETURN_LONG(zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -412,105 +441,77 @@ PHP_METHOD(RepeatedField, count) {
|
||||
* @return object Beginning iterator.
|
||||
*/
|
||||
PHP_METHOD(RepeatedField, getIterator) {
|
||||
zval *iter_php = NULL;
|
||||
MAKE_STD_ZVAL(iter_php);
|
||||
Z_TYPE_P(iter_php) = IS_OBJECT;
|
||||
Z_OBJVAL_P(iter_php) = repeated_field_iter_type->create_object(
|
||||
repeated_field_iter_type TSRMLS_CC);
|
||||
CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(return_value,
|
||||
repeated_field_iter_type);
|
||||
|
||||
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RepeatedFieldIter *iter = zend_object_store_get_object(iter_php TSRMLS_CC);
|
||||
RepeatedField *intern = UNBOX(RepeatedField, getThis());
|
||||
RepeatedFieldIter *iter = UNBOX(RepeatedFieldIter, return_value);
|
||||
iter->repeated_field = intern;
|
||||
iter->position = 0;
|
||||
|
||||
RETURN_ZVAL(iter_php, 1, 1);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// RepeatedFieldIter creation/desctruction
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void repeated_field_iter_init(TSRMLS_D) {
|
||||
zend_class_entry class_type;
|
||||
const char* class_name = "Google\\Protobuf\\Internal\\RepeatedFieldIter";
|
||||
INIT_CLASS_ENTRY_EX(class_type, class_name, strlen(class_name),
|
||||
repeated_field_iter_methods);
|
||||
// Define object free method.
|
||||
PHP_PROTO_OBJECT_FREE_START(RepeatedFieldIter, repeated_field_iter)
|
||||
PHP_PROTO_OBJECT_FREE_END
|
||||
|
||||
repeated_field_iter_type =
|
||||
zend_register_internal_class(&class_type TSRMLS_CC);
|
||||
repeated_field_iter_type->create_object = repeated_field_iter_create;
|
||||
PHP_PROTO_OBJECT_DTOR_START(RepeatedFieldIter, repeated_field_iter)
|
||||
PHP_PROTO_OBJECT_DTOR_END
|
||||
|
||||
zend_class_implements(repeated_field_iter_type TSRMLS_CC, 1,
|
||||
zend_ce_iterator);
|
||||
}
|
||||
// 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)
|
||||
|
||||
static zend_object_value repeated_field_iter_create(
|
||||
zend_class_entry *ce TSRMLS_DC) {
|
||||
zend_object_value retval = {0};
|
||||
RepeatedFieldIter *intern;
|
||||
|
||||
intern = emalloc(sizeof(RepeatedFieldIter));
|
||||
memset(intern, 0, sizeof(RepeatedFieldIter));
|
||||
|
||||
zend_object_std_init(&intern->std, ce TSRMLS_CC);
|
||||
object_properties_init(&intern->std, ce);
|
||||
|
||||
intern->repeated_field = NULL;
|
||||
intern->position = 0;
|
||||
|
||||
retval.handle = zend_objects_store_put(
|
||||
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
|
||||
(zend_objects_free_object_storage_t)repeated_field_iter_free,
|
||||
NULL TSRMLS_CC);
|
||||
retval.handlers = zend_get_std_object_handlers();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void repeated_field_iter_free(void *object TSRMLS_DC) {
|
||||
RepeatedFieldIter *intern = object;
|
||||
zend_object_std_dtor(&intern->std TSRMLS_CC);
|
||||
efree(object);
|
||||
}
|
||||
// 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
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PHP RepeatedFieldIter Methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
PHP_METHOD(RepeatedFieldIter, rewind) {
|
||||
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
|
||||
intern->position = 0;
|
||||
}
|
||||
|
||||
PHP_METHOD(RepeatedFieldIter, current) {
|
||||
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
|
||||
RepeatedField *repeated_field = intern->repeated_field;
|
||||
|
||||
long index;
|
||||
void *memory;
|
||||
|
||||
HashTable *table = HASH_OF(repeated_field->array);
|
||||
HashTable *table = PHP_PROTO_HASH_OF(repeated_field->array);
|
||||
|
||||
if (zend_hash_index_find(table, intern->position, (void **)&memory) ==
|
||||
if (php_proto_zend_hash_index_find(table, intern->position, (void **)&memory) ==
|
||||
FAILURE) {
|
||||
zend_error(E_USER_ERROR, "Element at %ld doesn't exist.\n", index);
|
||||
return;
|
||||
}
|
||||
native_slot_get(repeated_field->type, memory, return_value_ptr TSRMLS_CC);
|
||||
native_slot_get_by_array(repeated_field->type, memory,
|
||||
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHP_METHOD(RepeatedFieldIter, key) {
|
||||
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
|
||||
RETURN_LONG(intern->position);
|
||||
}
|
||||
|
||||
PHP_METHOD(RepeatedFieldIter, next) {
|
||||
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
|
||||
++intern->position;
|
||||
}
|
||||
|
||||
PHP_METHOD(RepeatedFieldIter, valid) {
|
||||
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
RETURN_BOOL(zend_hash_num_elements(HASH_OF(intern->repeated_field->array)) >
|
||||
intern->position);
|
||||
RepeatedFieldIter *intern = UNBOX(RepeatedFieldIter, getThis());
|
||||
RETURN_BOOL(zend_hash_num_elements(PHP_PROTO_HASH_OF(
|
||||
intern->repeated_field->array)) > intern->position);
|
||||
}
|
||||
|
@ -30,20 +30,17 @@
|
||||
|
||||
#include "protobuf.h"
|
||||
|
||||
const char* const kReservedNames[] = {"Empty"};
|
||||
const int kReservedNamesSize = 1;
|
||||
|
||||
// Forward declare.
|
||||
static zend_object_value descriptor_create(zend_class_entry *ce TSRMLS_DC);
|
||||
static void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC);
|
||||
static void descriptor_free_c(Descriptor* object TSRMLS_DC);
|
||||
static void descriptor_free(void* object TSRMLS_DC);
|
||||
|
||||
static zend_object_value enum_descriptor_create(zend_class_entry *ce 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_descriptor_free(void* object TSRMLS_DC);
|
||||
|
||||
static zend_object_value descriptor_pool_create(zend_class_entry *ce TSRMLS_DC);
|
||||
static void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC);
|
||||
static void descriptor_pool_free(void* object TSRMLS_DC);
|
||||
static void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -104,40 +101,31 @@ static void append_map_entry_name(char *result, const char *field_name,
|
||||
} while (0)
|
||||
|
||||
// Define PHP class
|
||||
#define DEFINE_PROTOBUF_INIT_CLASS(name_lower, string_name) \
|
||||
void name_lower##_init(TSRMLS_D) { \
|
||||
zend_class_entry class_type; \
|
||||
INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods); \
|
||||
name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \
|
||||
name_lower##_type->create_object = name_lower##_create; \
|
||||
}
|
||||
#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, name_lower) \
|
||||
static zend_object_value name_lower##_create( \
|
||||
zend_class_entry* ce TSRMLS_DC) { \
|
||||
zend_object_value return_value; \
|
||||
name* intern = (name*)emalloc(sizeof(name)); \
|
||||
memset(intern, 0, sizeof(name)); \
|
||||
name_lower##_init_c_instance(intern TSRMLS_CC); \
|
||||
return_value.handle = zend_objects_store_put( \
|
||||
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \
|
||||
name_lower##_free, NULL TSRMLS_CC); \
|
||||
return_value.handlers = zend_get_std_object_handlers(); \
|
||||
return return_value; \
|
||||
}
|
||||
#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(name, name_lower) \
|
||||
static void name_lower##_free(void* object TSRMLS_DC) { \
|
||||
name* intern = (name*)object; \
|
||||
name_lower##_free_c(intern TSRMLS_CC); \
|
||||
efree(object); \
|
||||
}
|
||||
#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_CLASS(name, name_lower, string_name) \
|
||||
zend_class_entry* name_lower##_type; \
|
||||
DEFINE_PROTOBUF_FREE(name, name_lower) \
|
||||
DEFINE_PROTOBUF_CREATE(name, name_lower) \
|
||||
DEFINE_PROTOBUF_INIT_CLASS(name_lower, string_name)
|
||||
#define DEFINE_PROTOBUF_DTOR(CAMELNAME, LOWERNAME) \
|
||||
PHP_PROTO_OBJECT_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)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// GPBType
|
||||
@ -176,228 +164,6 @@ void gpb_type_init(TSRMLS_D) {
|
||||
zend_declare_class_constant_long(gpb_type_type, STR("SINT64"), 18 TSRMLS_CC);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// DescriptorPool
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static zend_function_entry descriptor_pool_methods[] = {
|
||||
PHP_ME(DescriptorPool, getGeneratedPool, NULL,
|
||||
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS(DescriptorPool, descriptor_pool,
|
||||
"Google\\Protobuf\\Internal\\DescriptorPool");
|
||||
|
||||
zval* generated_pool_php; // wrapper of generated pool
|
||||
DescriptorPool *generated_pool; // The actual generated pool
|
||||
|
||||
static void init_generated_pool_once(TSRMLS_D) {
|
||||
if (generated_pool_php == NULL) {
|
||||
MAKE_STD_ZVAL(generated_pool_php);
|
||||
Z_TYPE_P(generated_pool_php) = IS_OBJECT;
|
||||
generated_pool = ALLOC(DescriptorPool);
|
||||
descriptor_pool_init_c_instance(generated_pool TSRMLS_CC);
|
||||
Z_OBJ_HANDLE_P(generated_pool_php) = zend_objects_store_put(
|
||||
generated_pool, NULL,
|
||||
(zend_objects_free_object_storage_t)descriptor_pool_free,
|
||||
NULL TSRMLS_CC);
|
||||
Z_OBJ_HT_P(generated_pool_php) = zend_get_std_object_handlers();
|
||||
}
|
||||
}
|
||||
|
||||
static void descriptor_pool_init_c_instance(DescriptorPool *pool TSRMLS_DC) {
|
||||
zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC);
|
||||
pool->symtab = upb_symtab_new();
|
||||
|
||||
ALLOC_HASHTABLE(pool->pending_list);
|
||||
zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0);
|
||||
}
|
||||
|
||||
static void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) {
|
||||
upb_symtab_free(pool->symtab);
|
||||
|
||||
zend_hash_destroy(pool->pending_list);
|
||||
FREE_HASHTABLE(pool->pending_list);
|
||||
}
|
||||
|
||||
static void validate_enumdef(const upb_enumdef *enumdef) {
|
||||
// Verify that an entry exists with integer value 0. (This is the default
|
||||
// value.)
|
||||
const char *lookup = upb_enumdef_iton(enumdef, 0);
|
||||
if (lookup == NULL) {
|
||||
zend_error(E_USER_ERROR,
|
||||
"Enum definition does not contain a value for '0'.");
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_msgdef(const upb_msgdef* msgdef) {
|
||||
// Verify that no required fields exist. proto3 does not support these.
|
||||
upb_msg_field_iter it;
|
||||
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);
|
||||
if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
|
||||
zend_error(E_ERROR, "Required fields are unsupported in proto3.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DescriptorPool, getGeneratedPool) {
|
||||
init_generated_pool_once(TSRMLS_C);
|
||||
RETURN_ZVAL(generated_pool_php, 1, 0);
|
||||
}
|
||||
|
||||
static void convert_to_class_name_inplace(char *class_name,
|
||||
const char* fullname,
|
||||
const char* prefix,
|
||||
const char* package_name) {
|
||||
size_t i = 0, j;
|
||||
bool first_char = true;
|
||||
size_t pkg_name_len = package_name == NULL ? 0 : strlen(package_name);
|
||||
size_t prefix_len = prefix == NULL ? 0 : strlen(prefix);
|
||||
size_t message_name_start = package_name == NULL ? 0 : pkg_name_len + 1;
|
||||
size_t message_len = (strlen(fullname) - message_name_start);
|
||||
|
||||
// In php, class name cannot be Empty.
|
||||
if (strcmp("google.protobuf.Empty", fullname) == 0) {
|
||||
strcpy(class_name, "\\Google\\Protobuf\\GPBEmpty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pkg_name_len != 0) {
|
||||
class_name[i++] = '\\';
|
||||
for (j = 0; j < pkg_name_len; j++) {
|
||||
// php packages are divided by '\'.
|
||||
if (package_name[j] == '.') {
|
||||
class_name[i++] = '\\';
|
||||
first_char = true;
|
||||
} else if (first_char) {
|
||||
// PHP package uses camel case.
|
||||
if (package_name[j] < 'A' || package_name[j] > 'Z') {
|
||||
class_name[i++] = package_name[j] + 'A' - 'a';
|
||||
} else {
|
||||
class_name[i++] = package_name[j];
|
||||
}
|
||||
first_char = false;
|
||||
} else {
|
||||
class_name[i++] = package_name[j];
|
||||
}
|
||||
}
|
||||
class_name[i++] = '\\';
|
||||
}
|
||||
|
||||
if (prefix_len > 0) {
|
||||
strcpy(class_name + i, prefix);
|
||||
i += prefix_len;
|
||||
}
|
||||
|
||||
// Submessage is concatenated with its containing messages by '_'.
|
||||
for (j = message_name_start; j < message_name_start + message_len; j++) {
|
||||
if (fullname[j] == '.') {
|
||||
class_name[i++] = '_';
|
||||
} else {
|
||||
class_name[i++] = fullname[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
|
||||
char *data = NULL;
|
||||
int data_len;
|
||||
upb_filedef **files;
|
||||
size_t i;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
DescriptorPool *pool = UNBOX(DescriptorPool, getThis());
|
||||
CHECK_UPB(files = upb_loaddescriptor(data, data_len, &pool, &status),
|
||||
"Parse binary descriptors to internal descriptors failed");
|
||||
|
||||
// This method is called only once in each file.
|
||||
assert(files[0] != NULL);
|
||||
assert(files[1] == NULL);
|
||||
|
||||
CHECK_UPB(upb_symtab_addfile(pool->symtab, files[0], &status),
|
||||
"Unable to add file to DescriptorPool");
|
||||
|
||||
// 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_defcount(files[0]); i++) {
|
||||
const upb_def *def = upb_filedef_def(files[0], i);
|
||||
switch (upb_def_type(def)) {
|
||||
#define CASE_TYPE(def_type, def_type_lower, desc_type, desc_type_lower) \
|
||||
case UPB_DEF_##def_type: { \
|
||||
desc_type *desc; \
|
||||
zval *desc_php; \
|
||||
CREATE(desc_type, desc, desc_type_lower##_init_c_instance); \
|
||||
BOX(desc_type, desc_php, desc, desc_type_lower##_free); \
|
||||
Z_DELREF_P(desc_php); \
|
||||
const upb_##def_type_lower *def_type_lower = \
|
||||
upb_downcast_##def_type_lower(def); \
|
||||
desc->def_type_lower = def_type_lower; \
|
||||
add_def_obj(desc->def_type_lower, desc_php); \
|
||||
/* Unlike other messages, MapEntry is shared by all map fields and doesn't \
|
||||
* have generated PHP class.*/ \
|
||||
if (upb_def_type(def) == UPB_DEF_MSG && \
|
||||
upb_msgdef_mapentry(upb_downcast_msgdef(def))) { \
|
||||
break; \
|
||||
} \
|
||||
/* 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 *fullname = upb_##def_type_lower##_fullname(def_type_lower); \
|
||||
const char *prefix = upb_filedef_phpprefix(files[0]); \
|
||||
size_t klass_name_len = strlen(fullname) + 5; \
|
||||
if (prefix != NULL) { \
|
||||
klass_name_len += strlen(prefix); \
|
||||
} \
|
||||
char *klass_name = ecalloc(sizeof(char), klass_name_len); \
|
||||
convert_to_class_name_inplace(klass_name, fullname, prefix, \
|
||||
upb_filedef_package(files[0])); \
|
||||
zend_class_entry **pce; \
|
||||
if (zend_lookup_class(klass_name, strlen(klass_name), &pce TSRMLS_CC) == \
|
||||
FAILURE) { \
|
||||
zend_error(E_ERROR, "Generated message class %s hasn't been defined", \
|
||||
klass_name); \
|
||||
return; \
|
||||
} else { \
|
||||
desc->klass = *pce; \
|
||||
} \
|
||||
add_ce_obj(desc->klass, desc_php); \
|
||||
efree(klass_name); \
|
||||
break; \
|
||||
}
|
||||
|
||||
CASE_TYPE(MSG, msgdef, Descriptor, descriptor)
|
||||
CASE_TYPE(ENUM, enumdef, EnumDescriptor, enum_descriptor)
|
||||
#undef CASE_TYPE
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < upb_filedef_defcount(files[0]); i++) {
|
||||
const upb_def *def = upb_filedef_def(files[0], i);
|
||||
if (upb_def_type(def) == UPB_DEF_MSG) {
|
||||
const upb_msgdef *msgdef = upb_downcast_msgdef(def);
|
||||
zval *desc_php = get_def_obj(msgdef);
|
||||
build_class_from_descriptor(desc_php TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
upb_filedef_unref(files[0], &pool);
|
||||
upb_gfree(files);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Descriptor
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -437,7 +203,7 @@ static void descriptor_free_c(Descriptor *self TSRMLS_DC) {
|
||||
}
|
||||
|
||||
static void descriptor_init_c_instance(Descriptor *desc TSRMLS_DC) {
|
||||
zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC);
|
||||
// zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC);
|
||||
desc->msgdef = NULL;
|
||||
desc->layout = NULL;
|
||||
desc->klass = NULL;
|
||||
@ -464,7 +230,7 @@ static void enum_descriptor_free_c(EnumDescriptor *self TSRMLS_DC) {
|
||||
}
|
||||
|
||||
static void enum_descriptor_init_c_instance(EnumDescriptor *self TSRMLS_DC) {
|
||||
zend_object_std_init(&self->std, enum_descriptor_type TSRMLS_CC);
|
||||
// zend_object_std_init(&self->std, enum_descriptor_type TSRMLS_CC);
|
||||
self->enumdef = NULL;
|
||||
self->klass = NULL;
|
||||
}
|
||||
@ -505,3 +271,267 @@ upb_fieldtype_t to_fieldtype(upb_descriptortype_t type) {
|
||||
zend_error(E_ERROR, "Unknown field type.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// DescriptorPool
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static zend_function_entry descriptor_pool_methods[] = {
|
||||
PHP_ME(DescriptorPool, getGeneratedPool, NULL,
|
||||
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||
PHP_ME(DescriptorPool, internalAddGeneratedFile, NULL, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
DEFINE_CLASS(DescriptorPool, descriptor_pool,
|
||||
"Google\\Protobuf\\Internal\\DescriptorPool");
|
||||
|
||||
// wrapper of generated pool
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval* generated_pool_php;
|
||||
#else
|
||||
zend_object *generated_pool_php;
|
||||
#endif
|
||||
DescriptorPool *generated_pool; // The actual generated pool
|
||||
|
||||
static void init_generated_pool_once(TSRMLS_D) {
|
||||
if (generated_pool_php == NULL) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
MAKE_STD_ZVAL(generated_pool_php);
|
||||
ZVAL_OBJ(generated_pool_php, descriptor_pool_type->create_object(
|
||||
descriptor_pool_type TSRMLS_CC));
|
||||
generated_pool = UNBOX(DescriptorPool, generated_pool_php);
|
||||
#else
|
||||
generated_pool_php =
|
||||
descriptor_pool_type->create_object(descriptor_pool_type TSRMLS_CC);
|
||||
generated_pool = (DescriptorPool *)((char *)generated_pool_php -
|
||||
XtOffsetOf(DescriptorPool, std));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void descriptor_pool_init_c_instance(DescriptorPool *pool TSRMLS_DC) {
|
||||
// zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC);
|
||||
pool->symtab = upb_symtab_new();
|
||||
|
||||
ALLOC_HASHTABLE(pool->pending_list);
|
||||
zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0);
|
||||
}
|
||||
|
||||
static void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) {
|
||||
upb_symtab_free(pool->symtab);
|
||||
|
||||
zend_hash_destroy(pool->pending_list);
|
||||
FREE_HASHTABLE(pool->pending_list);
|
||||
}
|
||||
|
||||
static void validate_enumdef(const upb_enumdef *enumdef) {
|
||||
// Verify that an entry exists with integer value 0. (This is the default
|
||||
// value.)
|
||||
const char *lookup = upb_enumdef_iton(enumdef, 0);
|
||||
if (lookup == NULL) {
|
||||
zend_error(E_USER_ERROR,
|
||||
"Enum definition does not contain a value for '0'.");
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_msgdef(const upb_msgdef* msgdef) {
|
||||
// Verify that no required fields exist. proto3 does not support these.
|
||||
upb_msg_field_iter it;
|
||||
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);
|
||||
if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) {
|
||||
zend_error(E_ERROR, "Required fields are unsupported in proto3.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(DescriptorPool, getGeneratedPool) {
|
||||
init_generated_pool_once(TSRMLS_C);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
RETURN_ZVAL(generated_pool_php, 1, 0);
|
||||
#else
|
||||
++GC_REFCOUNT(generated_pool_php);
|
||||
RETURN_OBJ(generated_pool_php);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void classname_no_prefix(const char *fullname, const char *package_name,
|
||||
char *class_name) {
|
||||
size_t i = 0, j;
|
||||
bool first_char = true, is_reserved = false;
|
||||
size_t pkg_name_len = package_name == NULL ? 0 : strlen(package_name);
|
||||
size_t message_name_start = package_name == NULL ? 0 : pkg_name_len + 1;
|
||||
size_t message_len = (strlen(fullname) - message_name_start);
|
||||
|
||||
// Submessage is concatenated with its containing messages by '_'.
|
||||
for (j = message_name_start; j < message_name_start + message_len; j++) {
|
||||
if (fullname[j] == '.') {
|
||||
class_name[i++] = '_';
|
||||
} else {
|
||||
class_name[i++] = fullname[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char *classname_prefix(const char *classname,
|
||||
const char *prefix_given,
|
||||
const char *package_name) {
|
||||
size_t i;
|
||||
bool is_reserved = false;
|
||||
|
||||
if (prefix_given != NULL && strcmp(prefix_given, "") != 0) {
|
||||
return prefix_given;
|
||||
}
|
||||
|
||||
for (i = 0; i < kReservedNamesSize; i++) {
|
||||
if (strcmp(kReservedNames[i], classname) == 0) {
|
||||
is_reserved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_reserved) {
|
||||
if (package_name != NULL && strcmp("google.protobuf", package_name) == 0) {
|
||||
return "GPB";
|
||||
} else {
|
||||
return "PB";
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static void convert_to_class_name_inplace(const char *package,
|
||||
const char *prefix, char *classname) {
|
||||
size_t package_len = package == NULL ? 0 : strlen(package);
|
||||
size_t prefix_len = prefix == NULL ? 0 : strlen(prefix);
|
||||
size_t classname_len = strlen(classname);
|
||||
int i = 0, j;
|
||||
bool first_char = true;
|
||||
|
||||
int offset = package_len != 0 ? 2 : 0;
|
||||
|
||||
for (j = 0; j < classname_len; j++) {
|
||||
classname[package_len + prefix_len + classname_len + offset - 1 - j] =
|
||||
classname[classname_len - j - 1];
|
||||
}
|
||||
|
||||
if (package_len != 0) {
|
||||
classname[i++] = '\\';
|
||||
for (j = 0; j < package_len; j++) {
|
||||
// php packages are divided by '\'.
|
||||
if (package[j] == '.') {
|
||||
classname[i++] = '\\';
|
||||
first_char = true;
|
||||
} else if (first_char) {
|
||||
// PHP package uses camel case.
|
||||
if (package[j] < 'A' || package[j] > 'Z') {
|
||||
classname[i++] = package[j] + 'A' - 'a';
|
||||
} else {
|
||||
classname[i++] = package[j];
|
||||
}
|
||||
first_char = false;
|
||||
} else {
|
||||
classname[i++] = package[j];
|
||||
}
|
||||
}
|
||||
classname[i++] = '\\';
|
||||
}
|
||||
|
||||
memcpy(classname + i, prefix, prefix_len);
|
||||
}
|
||||
|
||||
PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
|
||||
char *data = NULL;
|
||||
PHP_PROTO_SIZE data_len;
|
||||
upb_filedef **files;
|
||||
size_t i;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
DescriptorPool *pool = UNBOX(DescriptorPool, getThis());
|
||||
CHECK_UPB(files = upb_loaddescriptor(data, data_len, &pool, &status),
|
||||
"Parse binary descriptors to internal descriptors failed");
|
||||
|
||||
// This method is called only once in each file.
|
||||
assert(files[0] != NULL);
|
||||
assert(files[1] == NULL);
|
||||
|
||||
CHECK_UPB(upb_symtab_addfile(pool->symtab, files[0], &status),
|
||||
"Unable to add file to DescriptorPool");
|
||||
|
||||
// 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_defcount(files[0]); i++) {
|
||||
const upb_def *def = upb_filedef_def(files[0], i);
|
||||
switch (upb_def_type(def)) {
|
||||
#define CASE_TYPE(def_type, def_type_lower, desc_type, desc_type_lower) \
|
||||
case UPB_DEF_##def_type: { \
|
||||
CREATE_HASHTABLE_VALUE(desc, desc_php, desc_type, desc_type_lower##_type); \
|
||||
const upb_##def_type_lower *def_type_lower = \
|
||||
upb_downcast_##def_type_lower(def); \
|
||||
desc->def_type_lower = def_type_lower; \
|
||||
add_def_obj(desc->def_type_lower, desc_php); \
|
||||
/* Unlike other messages, MapEntry is shared by all map fields and doesn't \
|
||||
* have generated PHP class.*/ \
|
||||
if (upb_def_type(def) == UPB_DEF_MSG && \
|
||||
upb_msgdef_mapentry(upb_downcast_msgdef(def))) { \
|
||||
break; \
|
||||
} \
|
||||
/* 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 *fullname = upb_##def_type_lower##_fullname(def_type_lower); \
|
||||
const char *prefix_given = upb_filedef_phpprefix(files[0]); \
|
||||
size_t classname_len = strlen(fullname) + 5; \
|
||||
if (prefix_given != NULL) { \
|
||||
classname_len += strlen(prefix_given); \
|
||||
} \
|
||||
char *classname = ecalloc(sizeof(char), classname_len); \
|
||||
const char *package = upb_filedef_package(files[0]); \
|
||||
classname_no_prefix(fullname, package, classname); \
|
||||
const char *prefix = classname_prefix(classname, prefix_given, package); \
|
||||
convert_to_class_name_inplace(package, prefix, classname); \
|
||||
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", \
|
||||
classname); \
|
||||
return; \
|
||||
} else { \
|
||||
desc->klass = PHP_PROTO_CE_UNREF(pce); \
|
||||
} \
|
||||
add_ce_obj(desc->klass, desc_php); \
|
||||
efree(classname); \
|
||||
break; \
|
||||
}
|
||||
|
||||
CASE_TYPE(MSG, msgdef, Descriptor, descriptor)
|
||||
CASE_TYPE(ENUM, enumdef, EnumDescriptor, enum_descriptor)
|
||||
#undef CASE_TYPE
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < upb_filedef_defcount(files[0]); i++) {
|
||||
const upb_def *def = upb_filedef_def(files[0], i);
|
||||
if (upb_def_type(def) == UPB_DEF_MSG) {
|
||||
const upb_msgdef *msgdef = upb_downcast_msgdef(def);
|
||||
PHP_PROTO_HASHTABLE_VALUE desc_php = get_def_obj(msgdef);
|
||||
build_class_from_descriptor(desc_php TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
upb_filedef_unref(files[0], &pool);
|
||||
upb_gfree(files);
|
||||
}
|
||||
|
@ -197,19 +197,18 @@ static const void *newoneofhandlerdata(upb_handlers *h,
|
||||
static void *startseq_handler(void* closure, const void* hd) {
|
||||
MessageHeader* msg = closure;
|
||||
const size_t *ofs = hd;
|
||||
return (void*)(*DEREF(msg, *ofs, zval**));
|
||||
return CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), *ofs, CACHED_VALUE*));
|
||||
}
|
||||
|
||||
// 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 = \
|
||||
(RepeatedField*)zend_object_store_get_object(array TSRMLS_CC); \
|
||||
repeated_field_push_native(intern, &val TSRMLS_CC); \
|
||||
return true; \
|
||||
#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)
|
||||
@ -226,15 +225,19 @@ static void* appendstr_handler(void *closure,
|
||||
size_t size_hint) {
|
||||
zval* array = (zval*)closure;
|
||||
TSRMLS_FETCH();
|
||||
RepeatedField* intern =
|
||||
(RepeatedField*)zend_object_store_get_object(array TSRMLS_CC);
|
||||
RepeatedField* intern = UNBOX(RepeatedField, array);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval* str;
|
||||
MAKE_STD_ZVAL(str);
|
||||
ZVAL_STRING(str, "", 1);
|
||||
|
||||
repeated_field_push_native(intern, &str TSRMLS_CC);
|
||||
PHP_PROTO_ZVAL_STRING(str, "", 1);
|
||||
repeated_field_push_native(intern, &str);
|
||||
return (void*)str;
|
||||
#else
|
||||
zend_string* str = zend_string_init("", 0, 1);
|
||||
repeated_field_push_native(intern, &str);
|
||||
return intern;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Appends a 'bytes' string to a repeated field.
|
||||
@ -243,24 +246,51 @@ static void* appendbytes_handler(void *closure,
|
||||
size_t size_hint) {
|
||||
zval* array = (zval*)closure;
|
||||
TSRMLS_FETCH();
|
||||
RepeatedField* intern =
|
||||
(RepeatedField*)zend_object_store_get_object(array TSRMLS_CC);
|
||||
RepeatedField* intern = UNBOX(RepeatedField, array);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval* str;
|
||||
MAKE_STD_ZVAL(str);
|
||||
ZVAL_STRING(str, "", 1);
|
||||
|
||||
repeated_field_push_native(intern, &str TSRMLS_CC);
|
||||
PHP_PROTO_ZVAL_STRING(str, "", 1);
|
||||
repeated_field_push_native(intern, &str);
|
||||
return (void*)str;
|
||||
#else
|
||||
zend_string* str = zend_string_init("", 0, 1);
|
||||
repeated_field_push_native(intern, &str);
|
||||
return intern;
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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 *empty_php_string(zval** value_ptr) {
|
||||
SEPARATE_ZVAL_IF_NOT_REF(value_ptr);
|
||||
zval* str = *value_ptr;
|
||||
zval_dtor(str);
|
||||
ZVAL_STRINGL(str, "", 0, 1);
|
||||
return (void*)str;
|
||||
return (void*)(*value_ptr);
|
||||
}
|
||||
#else
|
||||
static void *empty_php_string(zval* value_ptr) {
|
||||
return value_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Sets a non-repeated string field in a message.
|
||||
static void* str_handler(void *closure,
|
||||
@ -268,7 +298,7 @@ static void* str_handler(void *closure,
|
||||
size_t size_hint) {
|
||||
MessageHeader* msg = closure;
|
||||
const size_t *ofs = hd;
|
||||
return empty_php_string(DEREF(msg, *ofs, zval**));
|
||||
return empty_php_string(DEREF(message_data(msg), *ofs, CACHED_VALUE*));
|
||||
}
|
||||
|
||||
// Sets a non-repeated 'bytes' field in a message.
|
||||
@ -277,52 +307,73 @@ static void* bytes_handler(void *closure,
|
||||
size_t size_hint) {
|
||||
MessageHeader* msg = closure;
|
||||
const size_t *ofs = hd;
|
||||
return empty_php_string(DEREF(msg, *ofs, zval**));
|
||||
return empty_php_string(DEREF(message_data(msg), *ofs, CACHED_VALUE*));
|
||||
}
|
||||
|
||||
static size_t stringdata_handler(void* closure, const void* hd,
|
||||
const char* str, size_t len,
|
||||
const upb_bufhandle* handle) {
|
||||
zval* php_str = (zval*)closure;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
// Oneof string/bytes fields may have NULL initial value, which doesn't need
|
||||
// to be freed.
|
||||
if (Z_TYPE_P(php_str) == IS_STRING && !IS_INTERNED(Z_STRVAL_P(php_str))) {
|
||||
FREE(Z_STRVAL_P(php_str));
|
||||
}
|
||||
ZVAL_STRINGL(php_str, str, len, 1);
|
||||
#else
|
||||
if (Z_TYPE_P(php_str) == IS_STRING) {
|
||||
zend_string_release(Z_STR_P(php_str));
|
||||
}
|
||||
ZVAL_NEW_STR(php_str, zend_string_init(str, len, 0));
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
char* old_str = Z_STRVAL_P(php_str);
|
||||
size_t old_len = Z_STRLEN_P(php_str);
|
||||
assert(old_str != NULL);
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
static size_t zendstringdata_handler(void* closure, const void* hd,
|
||||
const char* str, size_t len,
|
||||
const upb_bufhandle* handle) {
|
||||
RepeatedField* intern = (RepeatedField*)closure;
|
||||
|
||||
char* new_str = emalloc(old_len + len + 1);
|
||||
unsigned char memory[NATIVE_SLOT_MAX_SIZE];
|
||||
memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
|
||||
*(zend_string**)memory = zend_string_init(str, len, 0);
|
||||
|
||||
memcpy(new_str, old_str, old_len);
|
||||
memcpy(new_str + old_len, str, len);
|
||||
new_str[old_len + len] = 0;
|
||||
FREE(old_str);
|
||||
|
||||
Z_STRVAL_P(php_str) = new_str;
|
||||
Z_STRLEN_P(php_str) = old_len + len;
|
||||
HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
|
||||
int index = zend_hash_num_elements(ht) - 1;
|
||||
php_proto_zend_hash_index_update(
|
||||
ht, index, memory, sizeof(zend_string*), NULL);
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Appends a submessage to a repeated field.
|
||||
static void *appendsubmsg_handler(void *closure, const void *hd) {
|
||||
zval* array = (zval*)closure;
|
||||
TSRMLS_FETCH();
|
||||
RepeatedField* intern =
|
||||
(RepeatedField*)zend_object_store_get_object(array TSRMLS_CC);
|
||||
RepeatedField* intern = UNBOX(RepeatedField, array);
|
||||
|
||||
const submsg_handlerdata_t *submsgdata = hd;
|
||||
zval* subdesc_php = get_def_obj((void*)submsgdata->md);
|
||||
Descriptor* subdesc = zend_object_store_get_object(subdesc_php TSRMLS_CC);
|
||||
Descriptor* subdesc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
|
||||
zend_class_entry* subklass = subdesc->klass;
|
||||
MessageHeader* submsg;
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval* val = NULL;
|
||||
MAKE_STD_ZVAL(val);
|
||||
Z_TYPE_P(val) = IS_OBJECT;
|
||||
Z_OBJVAL_P(val) = subklass->create_object(subklass TSRMLS_CC);
|
||||
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);
|
||||
|
||||
repeated_field_push_native(intern, &val TSRMLS_CC);
|
||||
|
||||
submsg = zend_object_store_get_object(val TSRMLS_CC);
|
||||
return submsg;
|
||||
}
|
||||
|
||||
@ -330,26 +381,35 @@ static void *appendsubmsg_handler(void *closure, const void *hd) {
|
||||
static void *submsg_handler(void *closure, const void *hd) {
|
||||
MessageHeader* msg = closure;
|
||||
const submsg_handlerdata_t* submsgdata = hd;
|
||||
zval* subdesc_php = get_def_obj((void*)submsgdata->md);
|
||||
TSRMLS_FETCH();
|
||||
Descriptor* subdesc = zend_object_store_get_object(subdesc_php TSRMLS_CC);
|
||||
Descriptor* subdesc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)submsgdata->md));
|
||||
zend_class_entry* subklass = subdesc->klass;
|
||||
zval* submsg_php;
|
||||
MessageHeader* submsg;
|
||||
|
||||
if (Z_TYPE_P(*DEREF(msg, submsgdata->ofs, zval**)) == IS_NULL) {
|
||||
if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(message_data(msg), submsgdata->ofs,
|
||||
CACHED_VALUE*))) == IS_NULL) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval* val = NULL;
|
||||
MAKE_STD_ZVAL(val);
|
||||
Z_TYPE_P(val) = IS_OBJECT;
|
||||
Z_OBJVAL_P(val) = subklass->create_object(subklass TSRMLS_CC);
|
||||
|
||||
zval_ptr_dtor(DEREF(msg, submsgdata->ofs, zval**));
|
||||
*DEREF(msg, submsgdata->ofs, 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);
|
||||
php_proto_zval_ptr_dtor(*DEREF(message_data(msg), submsgdata->ofs, zval**));
|
||||
*DEREF(message_data(msg), submsgdata->ofs, zval**) = val;
|
||||
#else
|
||||
zend_object* obj = subklass->create_object(subklass TSRMLS_CC);
|
||||
ZVAL_OBJ(DEREF(message_data(msg), submsgdata->ofs, zval*), obj);
|
||||
MessageHeader* intern = UNBOX_HASHTABLE_VALUE(MessageHeader, obj);
|
||||
custom_data_init(subklass, intern PHP_PROTO_TSRMLS_CC);
|
||||
#endif
|
||||
}
|
||||
|
||||
submsg_php = *DEREF(msg, submsgdata->ofs, zval**);
|
||||
submsg_php = CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), submsgdata->ofs, CACHED_VALUE*));
|
||||
|
||||
submsg = zend_object_store_get_object(submsg_php TSRMLS_CC);
|
||||
submsg = UNBOX(MessageHeader, submsg_php);
|
||||
return submsg;
|
||||
}
|
||||
|
||||
@ -372,32 +432,52 @@ typedef struct {
|
||||
// submessage. When the submessage ends, another handler is called to insert the
|
||||
// value into the map.
|
||||
typedef struct {
|
||||
zval* map;
|
||||
char key_storage[NATIVE_SLOT_MAX_SIZE];
|
||||
char value_storage[NATIVE_SLOT_MAX_SIZE];
|
||||
} map_parse_frame_t;
|
||||
} map_parse_frame_data_t;
|
||||
|
||||
static void map_slot_init(void* memory, upb_fieldtype_t type) {
|
||||
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) {
|
||||
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* tmp;
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_STRINGL(tmp, "", 0, 1);
|
||||
PHP_PROTO_ZVAL_STRINGL(tmp, "", 0, 1);
|
||||
*holder = tmp;
|
||||
*(zval***)memory = holder;
|
||||
#else
|
||||
*(zval**)memory = cache;
|
||||
PHP_PROTO_ZVAL_STRINGL(*(zval**)memory, "", 0, 1);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
zval** holder = ALLOC(zval*);
|
||||
zval* tmp;
|
||||
MAKE_STD_ZVAL(tmp);
|
||||
ZVAL_NULL(tmp);
|
||||
*holder = tmp;
|
||||
*(zval***)memory = holder;
|
||||
#else
|
||||
*(zval**)memory = cache;
|
||||
ZVAL_NULL(*(zval**)memory);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -410,9 +490,13 @@ static void map_slot_uninit(void* memory, upb_fieldtype_t 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);
|
||||
php_proto_zval_ptr_dtor(*holder);
|
||||
FREE(holder);
|
||||
#else
|
||||
php_proto_zval_ptr_dtor(*(zval**)memory);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -424,7 +508,11 @@ 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 {
|
||||
@ -444,6 +532,7 @@ static void map_slot_value(upb_fieldtype_t type, const void* from,
|
||||
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: {
|
||||
@ -451,6 +540,17 @@ static void map_slot_value(upb_fieldtype_t type, const void* 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:
|
||||
*(zend_object**)to = Z_OBJ_P(*(zval**)from);
|
||||
++GC_REFCOUNT(*(zend_object**)to);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
len = native_slot_size(type);
|
||||
memcpy(to, from, len);
|
||||
@ -462,13 +562,17 @@ static void map_slot_value(upb_fieldtype_t type, const void* from,
|
||||
static void *startmapentry_handler(void *closure, const void *hd) {
|
||||
MessageHeader* msg = closure;
|
||||
const map_handlerdata_t* mapdata = hd;
|
||||
zval* map = *DEREF(msg, mapdata->ofs, zval**);
|
||||
zval* map = CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), mapdata->ofs, CACHED_VALUE*));
|
||||
|
||||
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->key_storage, mapdata->key_field_type);
|
||||
map_slot_init(&frame->value_storage, mapdata->value_field_type);
|
||||
map_slot_init(&frame->data->key_storage, mapdata->key_field_type,
|
||||
&frame->key_zval);
|
||||
map_slot_init(&frame->data->value_storage, mapdata->value_field_type,
|
||||
&frame->value_zval);
|
||||
|
||||
return frame;
|
||||
}
|
||||
@ -480,19 +584,20 @@ static bool endmap_handler(void* closure, const void* hd, upb_status* s) {
|
||||
const map_handlerdata_t* mapdata = hd;
|
||||
|
||||
TSRMLS_FETCH();
|
||||
Map *map = (Map *)zend_object_store_get_object(frame->map TSRMLS_CC);
|
||||
Map *map = UNBOX(Map, frame->map);
|
||||
|
||||
const char* keyval = NULL;
|
||||
upb_value v;
|
||||
size_t length;
|
||||
|
||||
map_slot_key(map->key_type, &frame->key_storage, &keyval, &length);
|
||||
map_slot_value(map->value_type, &frame->value_storage, &v);
|
||||
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->key_storage, mapdata->key_field_type);
|
||||
map_slot_uninit(&frame->value_storage, mapdata->value_field_type);
|
||||
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;
|
||||
@ -528,14 +633,15 @@ static map_handlerdata_t* new_map_handlerdata(
|
||||
}
|
||||
|
||||
// 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(closure, oneofdata->case_ofs, uint32_t) = \
|
||||
oneofdata->oneof_case_num; \
|
||||
DEREF(closure, oneofdata->ofs, ctype) = val; \
|
||||
return true; \
|
||||
#define DEFINE_ONEOF_HANDLER(type, ctype) \
|
||||
static bool oneof##type##_handler(void* closure, const void* hd, \
|
||||
ctype val) { \
|
||||
const oneof_handlerdata_t* oneofdata = hd; \
|
||||
MessageHeader* msg = (MessageHeader*)closure; \
|
||||
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)
|
||||
@ -548,74 +654,71 @@ DEFINE_ONEOF_HANDLER(double, double)
|
||||
|
||||
#undef DEFINE_ONEOF_HANDLER
|
||||
|
||||
// Handlers for strings in a oneof.
|
||||
static void *oneofstr_handler(void *closure,
|
||||
const void *hd,
|
||||
size_t size_hint) {
|
||||
MessageHeader* msg = closure;
|
||||
const oneof_handlerdata_t *oneofdata = hd;
|
||||
|
||||
DEREF(msg, oneofdata->case_ofs, uint32_t) =
|
||||
oneofdata->oneof_case_num;
|
||||
DEREF(msg, oneofdata->ofs, zval**) =
|
||||
&(msg->std.properties_table)[oneofdata->property_ofs];
|
||||
|
||||
return empty_php_string(DEREF(msg, oneofdata->ofs, zval**));
|
||||
}
|
||||
|
||||
// Handlers for string/bytes in a oneof.
|
||||
static void *oneofbytes_handler(void *closure,
|
||||
const void *hd,
|
||||
size_t size_hint) {
|
||||
MessageHeader* msg = closure;
|
||||
const oneof_handlerdata_t *oneofdata = hd;
|
||||
|
||||
DEREF(msg, oneofdata->case_ofs, uint32_t) =
|
||||
DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) =
|
||||
oneofdata->oneof_case_num;
|
||||
DEREF(msg, oneofdata->ofs, zval**) =
|
||||
DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) =
|
||||
&(msg->std.properties_table)[oneofdata->property_ofs];
|
||||
|
||||
return empty_php_string(DEREF(
|
||||
message_data(msg), oneofdata->ofs, CACHED_VALUE*));
|
||||
}
|
||||
|
||||
static void *oneofstr_handler(void *closure,
|
||||
const void *hd,
|
||||
size_t size_hint) {
|
||||
// TODO(teboring): Add it back.
|
||||
// rb_enc_associate(str, kRubyString8bitEncoding);
|
||||
|
||||
SEPARATE_ZVAL_IF_NOT_REF(DEREF(msg, oneofdata->ofs, zval**));
|
||||
zval* str = *DEREF(msg, oneofdata->ofs, zval**);
|
||||
zval_dtor(str);
|
||||
ZVAL_STRINGL(str, "", 0, 1);
|
||||
return (void*)str;
|
||||
return oneofbytes_handler(closure, hd, size_hint);
|
||||
}
|
||||
|
||||
// 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(msg, oneofdata->case_ofs, uint32_t);
|
||||
zval* subdesc_php = get_def_obj((void*)oneofdata->md);
|
||||
uint32_t oldcase = DEREF(message_data(msg), oneofdata->case_ofs, uint32_t);
|
||||
TSRMLS_FETCH();
|
||||
Descriptor* subdesc = zend_object_store_get_object(subdesc_php TSRMLS_CC);
|
||||
Descriptor* subdesc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)oneofdata->md));
|
||||
zend_class_entry* subklass = subdesc->klass;
|
||||
zval* submsg_php;
|
||||
MessageHeader* submsg;
|
||||
|
||||
if (oldcase != oneofdata->oneof_case_num) {
|
||||
DEREF(msg, oneofdata->ofs, zval**) =
|
||||
// Ideally, we should clean up the old data. However, we don't even know the
|
||||
// type of the old data. So, we will defer the desctruction of the old data
|
||||
// to the time that containing message's destroyed or the same oneof field
|
||||
// is accessed again and find that the old data hasn't been cleaned.
|
||||
DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*) =
|
||||
&(msg->std.properties_table)[oneofdata->property_ofs];
|
||||
|
||||
// Old data was't cleaned when the oneof was accessed from another field.
|
||||
if (Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(
|
||||
message_data(msg), oneofdata->ofs, CACHED_VALUE*))) != IS_NULL) {
|
||||
php_proto_zval_ptr_dtor(
|
||||
CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)));
|
||||
}
|
||||
|
||||
// Create new message.
|
||||
ZVAL_OBJ(CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), oneofdata->ofs, CACHED_VALUE*)),
|
||||
subklass->create_object(subklass TSRMLS_CC));
|
||||
}
|
||||
|
||||
if (Z_TYPE_P(*DEREF(msg, oneofdata->ofs, zval**)) == IS_NULL) {
|
||||
zval* val = NULL;
|
||||
MAKE_STD_ZVAL(val);
|
||||
Z_TYPE_P(val) = IS_OBJECT;
|
||||
Z_OBJVAL_P(val) = subklass->create_object(subklass TSRMLS_CC);
|
||||
|
||||
zval_ptr_dtor(DEREF(msg, oneofdata->ofs, zval**));
|
||||
*DEREF(msg, oneofdata->ofs, zval**) = val;
|
||||
}
|
||||
|
||||
DEREF(msg, oneofdata->case_ofs, uint32_t) =
|
||||
DEREF(message_data(msg), oneofdata->case_ofs, uint32_t) =
|
||||
oneofdata->oneof_case_num;
|
||||
|
||||
submsg_php = *DEREF(msg, oneofdata->ofs, zval**);
|
||||
submsg = zend_object_store_get_object(submsg_php TSRMLS_CC);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -652,7 +755,11 @@ static void add_handlers_for_repeated_field(upb_handlers *h,
|
||||
upb_handlers_setstartstr(h, f, is_bytes ?
|
||||
appendbytes_handler : appendstr_handler,
|
||||
NULL);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
upb_handlers_setstring(h, f, stringdata_handler, NULL);
|
||||
#else
|
||||
upb_handlers_setstring(h, f, zendstringdata_handler, NULL);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
@ -670,16 +777,26 @@ static void add_handlers_for_singular_field(upb_handlers *h,
|
||||
const upb_fielddef *f,
|
||||
size_t offset) {
|
||||
switch (upb_fielddef_type(f)) {
|
||||
case UPB_TYPE_BOOL:
|
||||
case UPB_TYPE_INT32:
|
||||
case UPB_TYPE_UINT32:
|
||||
case UPB_TYPE_ENUM:
|
||||
case UPB_TYPE_FLOAT:
|
||||
case UPB_TYPE_INT64:
|
||||
case UPB_TYPE_UINT64:
|
||||
case UPB_TYPE_DOUBLE:
|
||||
upb_msg_setscalarhandler(h, f, offset, -1);
|
||||
break;
|
||||
|
||||
#define SET_HANDLER(utype, ltype) \
|
||||
case utype: { \
|
||||
upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; \
|
||||
upb_handlerattr_sethandlerdata(&attr, 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: {
|
||||
bool is_bytes = upb_fielddef_type(f) == UPB_TYPE_BYTES;
|
||||
@ -730,9 +847,11 @@ static void add_handlers_for_mapentry(const upb_msgdef* msgdef, upb_handlers* h,
|
||||
upb_handlers_setendmsg(h, endmap_handler, &attr);
|
||||
|
||||
add_handlers_for_singular_field(h, key_field,
|
||||
offsetof(map_parse_frame_t, key_storage));
|
||||
offsetof(map_parse_frame_data_t,
|
||||
key_storage));
|
||||
add_handlers_for_singular_field(h, value_field,
|
||||
offsetof(map_parse_frame_t, value_storage));
|
||||
offsetof(map_parse_frame_data_t,
|
||||
value_storage));
|
||||
}
|
||||
|
||||
// Set up handlers for a oneof field.
|
||||
@ -787,8 +906,8 @@ static void add_handlers_for_message(const void* closure,
|
||||
upb_handlers* h) {
|
||||
const upb_msgdef* msgdef = upb_handlers_msgdef(h);
|
||||
TSRMLS_FETCH();
|
||||
Descriptor* desc = (Descriptor*)zend_object_store_get_object(
|
||||
get_def_obj((void*)msgdef) TSRMLS_CC);
|
||||
Descriptor* desc =
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj((void*)msgdef));
|
||||
upb_msg_field_iter i;
|
||||
|
||||
// If this is a mapentry message type, set up a special set of handlers and
|
||||
@ -810,13 +929,11 @@ static void add_handlers_for_message(const void* closure,
|
||||
!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 +
|
||||
sizeof(MessageHeader);
|
||||
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 +
|
||||
sizeof(MessageHeader);
|
||||
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, f, offset, oneof_case_offset,
|
||||
@ -883,6 +1000,8 @@ static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) {
|
||||
|
||||
static void putmsg(zval* msg, const Descriptor* desc, upb_sink* sink,
|
||||
int depth TSRMLS_DC);
|
||||
static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth TSRMLS_DC);
|
||||
|
||||
static void putstr(zval* str, const upb_fielddef* f, upb_sink* sink);
|
||||
|
||||
@ -891,6 +1010,8 @@ static void putrawstr(const char* str, int len, const upb_fielddef* f,
|
||||
|
||||
static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink* sink,
|
||||
int depth TSRMLS_DC);
|
||||
static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
|
||||
upb_sink* sink, int depth TSRMLS_DC);
|
||||
|
||||
static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
|
||||
int depth TSRMLS_DC);
|
||||
@ -933,8 +1054,14 @@ static void put_optional_value(const void* memory, int len, const upb_fielddef*
|
||||
putrawstr(memory, len, f, sink);
|
||||
break;
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
zval* submsg = *(zval**)memory;
|
||||
putsubmsg(submsg, f, sink, depth TSRMLS_CC);
|
||||
#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 TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -947,7 +1074,11 @@ 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;
|
||||
@ -958,8 +1089,11 @@ 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);
|
||||
break;
|
||||
#else
|
||||
return ZSTR_LEN(*(zend_string**)memory);
|
||||
#endif
|
||||
default:
|
||||
return len;
|
||||
}
|
||||
@ -967,7 +1101,6 @@ static int raw_value_len(void* memory, int len, const upb_fielddef* f) {
|
||||
|
||||
static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
|
||||
int depth TSRMLS_DC) {
|
||||
Map* self;
|
||||
upb_sink subsink;
|
||||
const upb_fielddef* key_field;
|
||||
const upb_fielddef* value_field;
|
||||
@ -975,8 +1108,7 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
|
||||
int len, size;
|
||||
|
||||
assert(map != NULL);
|
||||
Map* intern =
|
||||
(Map*)zend_object_store_get_object(map TSRMLS_CC);
|
||||
Map* intern = UNBOX(Map, map);
|
||||
size = upb_strtable_count(&intern->table);
|
||||
if (size == 0) return;
|
||||
|
||||
@ -1013,6 +1145,12 @@ static void putmap(zval* map, const upb_fielddef* f, upb_sink* sink,
|
||||
|
||||
static void putmsg(zval* msg_php, const Descriptor* desc, upb_sink* sink,
|
||||
int depth TSRMLS_DC) {
|
||||
MessageHeader* msg = UNBOX(MessageHeader, msg_php);
|
||||
putrawmsg(msg, desc, sink, depth TSRMLS_CC);
|
||||
}
|
||||
|
||||
static void putrawmsg(MessageHeader* msg, const Descriptor* desc,
|
||||
upb_sink* sink, int depth TSRMLS_DC) {
|
||||
upb_msg_field_iter i;
|
||||
upb_status status;
|
||||
|
||||
@ -1025,21 +1163,18 @@ static void putmsg(zval* msg_php, const Descriptor* desc, upb_sink* sink,
|
||||
"Maximum recursion depth exceeded during encoding.");
|
||||
}
|
||||
|
||||
MessageHeader* msg = zend_object_store_get_object(msg_php TSRMLS_CC);
|
||||
|
||||
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 +
|
||||
sizeof(MessageHeader);
|
||||
uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset;
|
||||
|
||||
if (upb_fielddef_containingoneof(f)) {
|
||||
uint32_t oneof_case_offset =
|
||||
desc->layout->fields[upb_fielddef_index(f)].case_offset +
|
||||
sizeof(MessageHeader);
|
||||
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(msg, oneof_case_offset, uint32_t) != upb_fielddef_number(f)) {
|
||||
if (DEREF(message_data(msg), oneof_case_offset, uint32_t) !=
|
||||
upb_fielddef_number(f)) {
|
||||
continue;
|
||||
}
|
||||
// Otherwise, fall through to the appropriate singular-field handler
|
||||
@ -1047,31 +1182,36 @@ static void putmsg(zval* msg_php, const Descriptor* desc, upb_sink* sink,
|
||||
}
|
||||
|
||||
if (is_map_field(f)) {
|
||||
zval* map = *DEREF(msg, offset, zval**);
|
||||
zval* map = CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), offset, CACHED_VALUE*));
|
||||
if (map != NULL) {
|
||||
putmap(map, f, sink, depth TSRMLS_CC);
|
||||
}
|
||||
} else if (upb_fielddef_isseq(f)) {
|
||||
zval* array = *DEREF(msg, offset, zval**);
|
||||
zval* array = CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), offset, CACHED_VALUE*));
|
||||
if (array != NULL) {
|
||||
putarray(array, f, sink, depth TSRMLS_CC);
|
||||
}
|
||||
} else if (upb_fielddef_isstring(f)) {
|
||||
zval* str = *DEREF(msg, offset, zval**);
|
||||
zval* str = CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), offset, CACHED_VALUE*));
|
||||
if (Z_STRLEN_P(str) > 0) {
|
||||
putstr(str, f, sink);
|
||||
}
|
||||
} else if (upb_fielddef_issubmsg(f)) {
|
||||
putsubmsg(*DEREF(msg, offset, zval**), f, sink, depth TSRMLS_CC);
|
||||
putsubmsg(CACHED_PTR_TO_ZVAL_PTR(
|
||||
DEREF(message_data(msg), offset, CACHED_VALUE*)),
|
||||
f, sink, depth 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(msg, offset, ctype); \
|
||||
if (value != default_value) { \
|
||||
upb_sink_put##upbtype(sink, sel, value); \
|
||||
} \
|
||||
#define T(upbtypeconst, upbtype, ctype, default_value) \
|
||||
case upbtypeconst: { \
|
||||
ctype value = DEREF(message_data(msg), offset, ctype); \
|
||||
if (value != default_value) { \
|
||||
upb_sink_put##upbtype(sink, sel, value); \
|
||||
} \
|
||||
} break;
|
||||
|
||||
switch (upb_fielddef_type(f)) {
|
||||
@ -1138,18 +1278,23 @@ static void putrawstr(const char* str, int len, const upb_fielddef* f,
|
||||
upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR));
|
||||
}
|
||||
|
||||
static void putsubmsg(zval* submsg, const upb_fielddef* f, upb_sink* sink,
|
||||
static void putsubmsg(zval* submsg_php, const upb_fielddef* f, upb_sink* sink,
|
||||
int depth TSRMLS_DC) {
|
||||
if (Z_TYPE_P(submsg_php) == IS_NULL) return;
|
||||
|
||||
MessageHeader *submsg = UNBOX(MessageHeader, submsg_php);
|
||||
putrawsubmsg(submsg, f, sink, depth TSRMLS_CC);
|
||||
}
|
||||
|
||||
static void putrawsubmsg(MessageHeader* submsg, const upb_fielddef* f,
|
||||
upb_sink* sink, int depth TSRMLS_DC) {
|
||||
upb_sink subsink;
|
||||
|
||||
if (Z_TYPE_P(submsg) == IS_NULL) return;
|
||||
|
||||
zval* php_descriptor = get_def_obj(upb_fielddef_msgsubdef(f));
|
||||
Descriptor* subdesc =
|
||||
(Descriptor*)zend_object_store_get_object(php_descriptor TSRMLS_CC);
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(upb_fielddef_msgsubdef(f)));
|
||||
|
||||
upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
|
||||
putmsg(submsg, subdesc, &subsink, depth + 1 TSRMLS_CC);
|
||||
putrawmsg(submsg, subdesc, &subsink, depth + 1 TSRMLS_CC);
|
||||
upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG));
|
||||
}
|
||||
|
||||
@ -1161,9 +1306,10 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
|
||||
int size, i;
|
||||
|
||||
assert(array != NULL);
|
||||
RepeatedField* intern =
|
||||
(RepeatedField*)zend_object_store_get_object(array TSRMLS_CC);
|
||||
size = zend_hash_num_elements(HASH_OF(intern->array));
|
||||
RepeatedField* intern = UNBOX(RepeatedField, array);
|
||||
HashTable *ht = PHP_PROTO_HASH_OF(intern->array);
|
||||
size = zend_hash_num_elements(ht);
|
||||
// size = zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array));
|
||||
if (size == 0) return;
|
||||
|
||||
upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink);
|
||||
@ -1190,12 +1336,28 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink,
|
||||
T(UPB_TYPE_UINT64, uint64, uint64_t)
|
||||
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES:
|
||||
putstr(*((zval**)memory), f, &subsink);
|
||||
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);
|
||||
break;
|
||||
case UPB_TYPE_MESSAGE:
|
||||
putsubmsg(*((zval**)memory), f, &subsink, depth TSRMLS_CC);
|
||||
}
|
||||
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, &subsink, depth TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
|
||||
#undef T
|
||||
}
|
||||
@ -1235,9 +1397,8 @@ static const upb_handlers* msgdef_json_serialize_handlers(
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
PHP_METHOD(Message, serializeToString) {
|
||||
zval* php_descriptor = get_ce_obj(Z_OBJCE_P(getThis()));
|
||||
Descriptor* desc =
|
||||
(Descriptor*)zend_object_store_get_object(php_descriptor TSRMLS_CC);
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
|
||||
|
||||
stringsink sink;
|
||||
stringsink_init(&sink);
|
||||
@ -1253,7 +1414,7 @@ PHP_METHOD(Message, serializeToString) {
|
||||
|
||||
putmsg(getThis(), desc, upb_pb_encoder_input(encoder), 0 TSRMLS_CC);
|
||||
|
||||
RETVAL_STRINGL(sink.ptr, sink.len, 1);
|
||||
PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
|
||||
|
||||
stackenv_uninit(&se);
|
||||
stringsink_uninit(&sink);
|
||||
@ -1261,13 +1422,13 @@ PHP_METHOD(Message, serializeToString) {
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, mergeFromString) {
|
||||
zval* php_descriptor = get_ce_obj(Z_OBJCE_P(getThis()));
|
||||
Descriptor* desc =
|
||||
(Descriptor*)zend_object_store_get_object(php_descriptor TSRMLS_CC);
|
||||
MessageHeader* msg = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
|
||||
MessageHeader* msg = UNBOX(MessageHeader, getThis());
|
||||
|
||||
char *data = NULL;
|
||||
int data_len;
|
||||
PHP_PROTO_SIZE data_len;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &data_len) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
@ -1290,9 +1451,8 @@ PHP_METHOD(Message, mergeFromString) {
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, jsonEncode) {
|
||||
zval* php_descriptor = get_ce_obj(Z_OBJCE_P(getThis()));
|
||||
Descriptor* desc =
|
||||
(Descriptor*)zend_object_store_get_object(php_descriptor TSRMLS_CC);
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
|
||||
|
||||
zend_bool preserve_proto_fieldnames = false;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b",
|
||||
@ -1314,7 +1474,7 @@ PHP_METHOD(Message, jsonEncode) {
|
||||
|
||||
putmsg(getThis(), desc, upb_json_printer_input(printer), 0 TSRMLS_CC);
|
||||
|
||||
RETVAL_STRINGL(sink.ptr, sink.len, 1);
|
||||
PHP_PROTO_RETVAL_STRINGL(sink.ptr, sink.len, 1);
|
||||
|
||||
stackenv_uninit(&se);
|
||||
stringsink_uninit(&sink);
|
||||
@ -1322,10 +1482,9 @@ PHP_METHOD(Message, jsonEncode) {
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, jsonDecode) {
|
||||
zval* php_descriptor = get_ce_obj(Z_OBJCE_P(getThis()));
|
||||
Descriptor* desc =
|
||||
(Descriptor*)zend_object_store_get_object(php_descriptor TSRMLS_CC);
|
||||
MessageHeader* msg = zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(Z_OBJCE_P(getThis())));
|
||||
MessageHeader* msg = UNBOX(MessageHeader, getThis());
|
||||
|
||||
char *data = NULL;
|
||||
int data_len;
|
||||
|
@ -103,16 +103,16 @@ static bool table_key(Map* self, zval* 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(self->key_type, NULL, buf, key TSRMLS_CC); \
|
||||
*out_key = buf; \
|
||||
*out_length = native_slot_size(self->key_type); \
|
||||
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; \
|
||||
}
|
||||
CASE_TYPE(BOOL, bool, int8_t, BOOL)
|
||||
CASE_TYPE(INT32, int32, int32_t, LONG)
|
||||
@ -148,7 +148,7 @@ static zend_function_entry map_field_methods[] = {
|
||||
|
||||
// Forward declare static functions.
|
||||
|
||||
static bool map_field_write_dimension(zval *object, zval *key,
|
||||
static void map_field_write_dimension(zval *object, zval *key,
|
||||
zval *value TSRMLS_DC);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -163,8 +163,7 @@ static void map_begin_internal(Map *map, MapIter *iter) {
|
||||
upb_strtable_begin(&iter->it, &map->table);
|
||||
}
|
||||
|
||||
static HashTable *map_field_get_gc(zval *object, zval ***table,
|
||||
int *n TSRMLS_DC) {
|
||||
static HashTable *map_field_get_gc(zval *object, CACHED_VALUE **table, int *n) {
|
||||
// TODO(teboring): Unfortunately, zend engine does not support garbage
|
||||
// collection for custom array. We have to use zend engine's native array
|
||||
// instead.
|
||||
@ -173,111 +172,101 @@ static HashTable *map_field_get_gc(zval *object, zval ***table,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void map_field_init(TSRMLS_D) {
|
||||
zend_class_entry class_type;
|
||||
const char* class_name = "Google\\Protobuf\\Internal\\MapField";
|
||||
INIT_CLASS_ENTRY_EX(class_type, class_name, strlen(class_name),
|
||||
map_field_methods);
|
||||
|
||||
map_field_type = zend_register_internal_class(&class_type TSRMLS_CC);
|
||||
map_field_type->create_object = map_field_create;
|
||||
|
||||
zend_class_implements(map_field_type TSRMLS_CC, 2, spl_ce_ArrayAccess,
|
||||
spl_ce_Countable);
|
||||
|
||||
map_field_handlers = PEMALLOC(zend_object_handlers);
|
||||
memcpy(map_field_handlers, zend_get_std_object_handlers(),
|
||||
sizeof(zend_object_handlers));
|
||||
map_field_handlers->write_dimension = map_field_write_dimension;
|
||||
map_field_handlers->get_gc = map_field_get_gc;
|
||||
// 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);
|
||||
}
|
||||
|
||||
zend_object_value map_field_create(zend_class_entry *ce TSRMLS_DC) {
|
||||
zend_object_value retval = {0};
|
||||
Map *intern;
|
||||
|
||||
intern = emalloc(sizeof(Map));
|
||||
memset(intern, 0, sizeof(Map));
|
||||
|
||||
zend_object_std_init(&intern->std, ce TSRMLS_CC);
|
||||
object_properties_init(&intern->std, ce);
|
||||
|
||||
// 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.");
|
||||
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;
|
||||
if(--GC_REFCOUNT(object) == 0) {
|
||||
zend_objects_store_del(object);
|
||||
}
|
||||
|
||||
retval.handle = zend_objects_store_put(
|
||||
intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
|
||||
(zend_objects_free_object_storage_t)map_field_free, NULL TSRMLS_CC);
|
||||
retval.handlers = map_field_handlers;
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
void map_field_free(void *object TSRMLS_DC) {
|
||||
Map *map = (Map *)object;
|
||||
|
||||
switch (map->value_type) {
|
||||
// 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:
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES: {
|
||||
MapIter it;
|
||||
int len;
|
||||
for (map_begin_internal(map, &it); !map_done(&it); map_next(&it)) {
|
||||
upb_value value = map_iter_value(&it, &len);
|
||||
void *mem = upb_value_memory(&value);
|
||||
zval_ptr_dtor(mem);
|
||||
}
|
||||
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(&map->table);
|
||||
zend_object_std_dtor(&map->std TSRMLS_CC);
|
||||
efree(object);
|
||||
}
|
||||
upb_strtable_uninit(&intern->table);
|
||||
PHP_PROTO_OBJECT_FREE_END
|
||||
|
||||
void map_field_create_with_field(zend_class_entry *ce, const upb_fielddef *field,
|
||||
zval **map_field TSRMLS_DC) {
|
||||
PHP_PROTO_OBJECT_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, 2, spl_ce_ArrayAccess,
|
||||
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_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 TSRMLS_CC);
|
||||
field_type_class(value_field TSRMLS_CC), map_field PHP_PROTO_TSRMLS_CC);
|
||||
}
|
||||
|
||||
void map_field_create_with_type(zend_class_entry *ce, upb_fieldtype_t key_type,
|
||||
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,
|
||||
zval **map_field TSRMLS_DC) {
|
||||
MAKE_STD_ZVAL(*map_field);
|
||||
Z_TYPE_PP(map_field) = IS_OBJECT;
|
||||
Z_OBJVAL_PP(map_field) =
|
||||
map_field_type->create_object(map_field_type TSRMLS_CC);
|
||||
|
||||
Map* intern =
|
||||
(Map*)zend_object_store_get_object(*map_field TSRMLS_CC);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void map_field_free_element(void *object) {
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// MapField Handlers
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
static bool map_field_read_dimension(zval *object, zval *key, int type,
|
||||
zval **retval TSRMLS_DC) {
|
||||
Map *intern =
|
||||
(Map *)zend_object_store_get_object(object TSRMLS_CC);
|
||||
CACHED_VALUE *retval TSRMLS_DC) {
|
||||
Map *intern = UNBOX(Map, object);
|
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH];
|
||||
const char* keyval = NULL;
|
||||
@ -292,7 +281,7 @@ static bool map_field_read_dimension(zval *object, zval *key, int type,
|
||||
|
||||
if (upb_strtable_lookup2(&intern->table, keyval, length, &v)) {
|
||||
void* mem = upb_value_memory(&v);
|
||||
native_slot_get(intern->value_type, mem, retval TSRMLS_CC);
|
||||
native_slot_get_by_array(intern->value_type, mem, retval TSRMLS_CC);
|
||||
return true;
|
||||
} else {
|
||||
zend_error(E_USER_ERROR, "Given key doesn't exist.");
|
||||
@ -310,9 +299,9 @@ bool map_index_set(Map *intern, const char* keyval, int length, upb_value v) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool map_field_write_dimension(zval *object, zval *key,
|
||||
static void map_field_write_dimension(zval *object, zval *key,
|
||||
zval *value TSRMLS_DC) {
|
||||
Map *intern = (Map *)zend_object_store_get_object(object TSRMLS_CC);
|
||||
Map *intern = UNBOX(Map, object);
|
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH];
|
||||
const char* keyval = NULL;
|
||||
@ -320,14 +309,14 @@ static bool map_field_write_dimension(zval *object, zval *key,
|
||||
upb_value v;
|
||||
void* mem;
|
||||
if (!table_key(intern, key, keybuf, &keyval, &length TSRMLS_CC)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
mem = upb_value_memory(&v);
|
||||
memset(mem, 0, native_slot_size(intern->value_type));
|
||||
if (!native_slot_set(intern->value_type, intern->msg_ce, mem,
|
||||
value TSRMLS_CC)) {
|
||||
return false;
|
||||
if (!native_slot_set_by_array(intern->value_type, intern->msg_ce, mem,
|
||||
value TSRMLS_CC)) {
|
||||
return;
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
v.ctype = UPB_CTYPE_UINT64;
|
||||
@ -337,14 +326,12 @@ static bool map_field_write_dimension(zval *object, zval *key,
|
||||
upb_strtable_remove2(&intern->table, keyval, length, NULL);
|
||||
if (!upb_strtable_insert2(&intern->table, keyval, length, v)) {
|
||||
zend_error(E_USER_ERROR, "Could not insert into table");
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool map_field_unset_dimension(zval *object, zval *key TSRMLS_DC) {
|
||||
Map *intern = (Map *)zend_object_store_get_object(object TSRMLS_CC);
|
||||
Map *intern = UNBOX(Map, object);
|
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH];
|
||||
const char* keyval = NULL;
|
||||
@ -375,8 +362,7 @@ PHP_METHOD(MapField, __construct) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map* intern =
|
||||
(Map*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
Map *intern = UNBOX(Map, getThis());
|
||||
intern->key_type = to_fieldtype(key_type);
|
||||
intern->value_type = to_fieldtype(value_type);
|
||||
intern->msg_ce = klass;
|
||||
@ -404,7 +390,7 @@ PHP_METHOD(MapField, offsetExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map *intern = (Map *)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
Map *intern = UNBOX(Map, getThis());
|
||||
|
||||
char keybuf[TABLE_KEY_BUF_LENGTH];
|
||||
const char* keyval = NULL;
|
||||
@ -427,7 +413,7 @@ PHP_METHOD(MapField, offsetGet) {
|
||||
return;
|
||||
}
|
||||
map_field_read_dimension(getThis(), index, BP_VAR_R,
|
||||
return_value_ptr TSRMLS_CC);
|
||||
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHP_METHOD(MapField, offsetSet) {
|
||||
@ -449,8 +435,7 @@ PHP_METHOD(MapField, offsetUnset) {
|
||||
}
|
||||
|
||||
PHP_METHOD(MapField, count) {
|
||||
Map *intern =
|
||||
(Map *)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
Map *intern = UNBOX(Map, getThis());
|
||||
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
|
@ -53,40 +53,64 @@ static zend_function_entry message_methods[] = {
|
||||
|
||||
// Forward declare static functions.
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static void message_set_property(zval* object, zval* member, zval* value,
|
||||
const zend_literal* key TSRMLS_DC);
|
||||
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,
|
||||
const zend_literal* key TSRMLS_DC);
|
||||
static HashTable* message_get_properties(zval* object TSRMLS_DC);
|
||||
php_proto_zend_literal key TSRMLS_DC);
|
||||
static HashTable* message_get_gc(zval* object, zval*** table, int* n TSRMLS_DC);
|
||||
|
||||
static zend_object_value message_create(zend_class_entry* ce TSRMLS_DC);
|
||||
static void message_free(void* object TSRMLS_DC);
|
||||
#else
|
||||
static void message_set_property(zval* object, zval* member, zval* value,
|
||||
void** cache_slot);
|
||||
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
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void message_init(TSRMLS_D) {
|
||||
zend_class_entry class_type;
|
||||
INIT_CLASS_ENTRY(class_type, "Google\\Protobuf\\Internal\\Message",
|
||||
message_methods);
|
||||
message_type = zend_register_internal_class(&class_type TSRMLS_CC);
|
||||
// Define object free method.
|
||||
PHP_PROTO_OBJECT_FREE_START(MessageHeader, message)
|
||||
FREE(intern->data);
|
||||
PHP_PROTO_OBJECT_FREE_END
|
||||
|
||||
message_handlers = PEMALLOC(zend_object_handlers);
|
||||
memcpy(message_handlers, zend_get_std_object_handlers(),
|
||||
sizeof(zend_object_handlers));
|
||||
PHP_PROTO_OBJECT_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 decriptor of this class
|
||||
// hasn't been added to descritpor 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
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static void message_set_property(zval* object, zval* member, zval* value,
|
||||
const zend_literal* key TSRMLS_DC) {
|
||||
php_proto_zend_literal key TSRMLS_DC) {
|
||||
#else
|
||||
static void 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");
|
||||
return;
|
||||
@ -100,7 +124,7 @@ static void message_set_property(zval* object, zval* member, zval* value,
|
||||
|
||||
const upb_fielddef* field;
|
||||
|
||||
MessageHeader* self = zend_object_store_get_object(object TSRMLS_CC);
|
||||
MessageHeader* self = UNBOX(MessageHeader, object);
|
||||
|
||||
field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member));
|
||||
if (field == NULL) {
|
||||
@ -110,46 +134,55 @@ static void message_set_property(zval* object, zval* member, zval* value,
|
||||
layout_set(self->descriptor->layout, self, field, value TSRMLS_CC);
|
||||
}
|
||||
|
||||
#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 EG(uninitialized_zval_ptr);
|
||||
return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL;
|
||||
}
|
||||
|
||||
if (Z_OBJCE_P(object) != EG(scope)) {
|
||||
// User cannot get property directly (e.g., $a = $m->a)
|
||||
zend_error(E_USER_ERROR, "Cannot access private property.");
|
||||
return EG(uninitialized_zval_ptr);
|
||||
return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL;
|
||||
}
|
||||
|
||||
zend_property_info* property_info = NULL;
|
||||
|
||||
// All properties should have been declared in the generated code and have
|
||||
// corresponding zvals in properties_table.
|
||||
ulong h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
|
||||
if (zend_hash_quick_find(&Z_OBJCE_P(object)->properties_info,
|
||||
Z_STRVAL_P(member), Z_STRLEN_P(member) + 1, h,
|
||||
(void**)&property_info) != SUCCESS) {
|
||||
zend_error(E_USER_ERROR, "Property does not exist.");
|
||||
return EG(uninitialized_zval_ptr);
|
||||
}
|
||||
|
||||
MessageHeader* self =
|
||||
(MessageHeader*)zend_object_store_get_object(object TSRMLS_CC);
|
||||
|
||||
MessageHeader* self = UNBOX(MessageHeader, object);
|
||||
const upb_fielddef* field;
|
||||
field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member));
|
||||
if (field == NULL) {
|
||||
return EG(uninitialized_zval_ptr);
|
||||
return PHP_PROTO_GLOBAL_UNINITIALIZED_ZVAL;
|
||||
}
|
||||
|
||||
zend_property_info* property_info;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
property_info =
|
||||
zend_get_property_info(Z_OBJCE_P(object), member, true TSRMLS_CC);
|
||||
return layout_get(
|
||||
self->descriptor->layout, message_data(self), field,
|
||||
&Z_OBJ_P(object)->properties_table[property_info->offset] TSRMLS_CC);
|
||||
#else
|
||||
property_info =
|
||||
zend_get_property_info(Z_OBJCE_P(object), Z_STR_P(member), true);
|
||||
return layout_get(
|
||||
self->descriptor->layout, message_data(self), field,
|
||||
OBJ_PROP(Z_OBJ_P(object), property_info->offset) TSRMLS_CC);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
static zval** message_get_property_ptr_ptr(zval* object, zval* member, int type,
|
||||
const zend_literal* key TSRMLS_DC) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -157,68 +190,37 @@ static HashTable* message_get_properties(zval* object TSRMLS_DC) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HashTable* message_get_gc(zval* object, zval*** table, int* n TSRMLS_DC) {
|
||||
zend_object* zobj = Z_OBJ_P(object);
|
||||
*table = zobj->properties_table;
|
||||
*n = zobj->ce->default_properties_count;
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// C Message Utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void* message_data(void* msg) {
|
||||
return ((uint8_t*)msg) + sizeof(MessageHeader);
|
||||
void* message_data(MessageHeader* msg) {
|
||||
return msg->data;
|
||||
}
|
||||
|
||||
static void message_free(void* object TSRMLS_DC) {
|
||||
MessageHeader* msg = (MessageHeader*)object;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < msg->std.ce->default_properties_count; i++) {
|
||||
zval_ptr_dtor(&msg->std.properties_table[i]);
|
||||
}
|
||||
efree(msg->std.properties_table);
|
||||
efree(msg);
|
||||
}
|
||||
|
||||
static zend_object_value message_create(zend_class_entry* ce TSRMLS_DC) {
|
||||
zend_object_value return_value;
|
||||
|
||||
zval* php_descriptor = get_ce_obj(ce);
|
||||
|
||||
Descriptor* desc = zend_object_store_get_object(php_descriptor TSRMLS_CC);
|
||||
MessageHeader* msg = (MessageHeader*)ALLOC_N(
|
||||
uint8_t, sizeof(MessageHeader) + desc->layout->size);
|
||||
memset(message_data(msg), 0, desc->layout->size);
|
||||
|
||||
void custom_data_init(const zend_class_entry* ce,
|
||||
MessageHeader* intern PHP_PROTO_TSRMLS_DC) {
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_ce_obj(ce));
|
||||
intern->data = ALLOC_N(uint8_t, desc->layout->size);
|
||||
memset(message_data(intern), 0, 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().
|
||||
msg->descriptor = desc;
|
||||
|
||||
zend_object_std_init(&msg->std, ce TSRMLS_CC);
|
||||
object_properties_init(&msg->std, ce);
|
||||
layout_init(desc->layout, message_data(msg),
|
||||
msg->std.properties_table TSRMLS_CC);
|
||||
|
||||
return_value.handle = zend_objects_store_put(
|
||||
msg, (zend_objects_store_dtor_t)zend_objects_destroy_object, message_free,
|
||||
NULL TSRMLS_CC);
|
||||
|
||||
return_value.handlers = message_handlers;
|
||||
return return_value;
|
||||
intern->descriptor = desc;
|
||||
layout_init(desc->layout, message_data(intern),
|
||||
intern->std.properties_table PHP_PROTO_TSRMLS_CC);
|
||||
}
|
||||
|
||||
void message_create_with_type(zend_class_entry* ce, zval** message TSRMLS_DC) {
|
||||
MAKE_STD_ZVAL(*message);
|
||||
Z_TYPE_PP(message) = IS_OBJECT;
|
||||
Z_OBJVAL_PP(message) = ce->create_object(ce TSRMLS_CC);
|
||||
Z_DELREF_PP(message);
|
||||
}
|
||||
|
||||
void build_class_from_descriptor(zval* php_descriptor TSRMLS_DC) {
|
||||
Descriptor* desc = UNBOX(Descriptor, php_descriptor);
|
||||
void build_class_from_descriptor(
|
||||
PHP_PROTO_HASHTABLE_VALUE php_descriptor TSRMLS_DC) {
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, php_descriptor);
|
||||
|
||||
// Map entries don't have existing php class.
|
||||
if (upb_msgdef_mapentry(desc->msgdef)) {
|
||||
@ -243,26 +245,18 @@ void build_class_from_descriptor(zval* php_descriptor TSRMLS_DC) {
|
||||
// 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) {
|
||||
if (Z_OBJVAL_P(getThis()).handlers != message_handlers) {
|
||||
zend_class_entry* ce = Z_OBJCE_P(getThis());
|
||||
zval_dtor(getThis());
|
||||
Z_OBJVAL_P(getThis()) = message_create(ce TSRMLS_CC);
|
||||
zend_class_entry* ce = Z_OBJCE_P(getThis());
|
||||
if (EXPECTED(class_added(ce))) {
|
||||
MessageHeader* intern = UNBOX(MessageHeader, getThis());
|
||||
custom_data_init(ce, intern PHP_PROTO_TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, clear) {
|
||||
MessageHeader* msg =
|
||||
(MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
MessageHeader* msg = UNBOX(MessageHeader, getThis());
|
||||
Descriptor* desc = msg->descriptor;
|
||||
zend_class_entry* ce = desc->klass;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < msg->std.ce->default_properties_count; i++) {
|
||||
zval_ptr_dtor(&msg->std.properties_table[i]);
|
||||
}
|
||||
efree(msg->std.properties_table);
|
||||
|
||||
zend_object_std_init(&msg->std, ce TSRMLS_CC);
|
||||
object_properties_init(&msg->std, ce);
|
||||
layout_init(desc->layout, message_data(msg),
|
||||
msg->std.properties_table TSRMLS_CC);
|
||||
@ -275,10 +269,8 @@ PHP_METHOD(Message, mergeFrom) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHeader* from =
|
||||
(MessageHeader*)zend_object_store_get_object(value TSRMLS_CC);
|
||||
MessageHeader* to =
|
||||
(MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
MessageHeader* from = UNBOX(MessageHeader, value);
|
||||
MessageHeader* to = UNBOX(MessageHeader, getThis());
|
||||
|
||||
if(from->descriptor != to->descriptor) {
|
||||
zend_error(E_USER_ERROR, "Cannot merge messages with different class.");
|
||||
@ -289,36 +281,37 @@ PHP_METHOD(Message, mergeFrom) {
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, readOneof) {
|
||||
long index;
|
||||
PHP_PROTO_LONG index;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &index) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHeader* msg =
|
||||
(MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
MessageHeader* msg = UNBOX(MessageHeader, getThis());
|
||||
|
||||
const upb_fielddef* field = upb_msgdef_itof(msg->descriptor->msgdef, index);
|
||||
|
||||
int property_cache_index =
|
||||
msg->descriptor->layout->fields[upb_fielddef_index(field)].cache_index;
|
||||
zval** cache_ptr = &(msg->std.properties_table)[property_cache_index];
|
||||
zval* property_ptr = OBJ_PROP(Z_OBJ_P(getThis()), property_cache_index);
|
||||
|
||||
// Unlike singular fields, oneof fields share cached property. So we cannot
|
||||
// let lay_get modify the cached property. Instead, we pass in the return
|
||||
// value directly.
|
||||
layout_get(msg->descriptor->layout, message_data(msg), field,
|
||||
&return_value TSRMLS_CC);
|
||||
ZVAL_PTR_TO_CACHED_PTR(return_value) TSRMLS_CC);
|
||||
}
|
||||
|
||||
PHP_METHOD(Message, writeOneof) {
|
||||
long index;
|
||||
PHP_PROTO_LONG index;
|
||||
zval* value;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz", &index, &value) ==
|
||||
FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHeader* msg =
|
||||
(MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
MessageHeader* msg = UNBOX(MessageHeader, getThis());
|
||||
|
||||
const upb_fielddef* field = upb_msgdef_itof(msg->descriptor->msgdef, index);
|
||||
|
||||
@ -327,19 +320,18 @@ PHP_METHOD(Message, writeOneof) {
|
||||
|
||||
PHP_METHOD(Message, whichOneof) {
|
||||
char* oneof_name;
|
||||
int length;
|
||||
PHP_PROTO_SIZE length;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &oneof_name,
|
||||
&length) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageHeader* msg =
|
||||
(MessageHeader*)zend_object_store_get_object(getThis() TSRMLS_CC);
|
||||
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);
|
||||
RETURN_STRING(oneof_case_name, 1);
|
||||
PHP_PROTO_RETURN_STRING(oneof_case_name, 1);
|
||||
}
|
||||
|
@ -13,16 +13,16 @@
|
||||
<date>2017-01-13</date>
|
||||
<time>16:06:07</time>
|
||||
<version>
|
||||
<release>3.2.0a1</release>
|
||||
<api>3.2.0a1</api>
|
||||
<release>3.3.0</release>
|
||||
<api>3.3.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>alpha</release>
|
||||
<api>alpha</api>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
|
||||
<notes>
|
||||
Second alpha release.
|
||||
GA release.
|
||||
</notes>
|
||||
<contents>
|
||||
<dir baseinstalldir="/" name="/">
|
||||
@ -87,5 +87,21 @@ First alpha release
|
||||
Second alpha release.
|
||||
</notes>
|
||||
</release>
|
||||
<release>
|
||||
<version>
|
||||
<release>3.3.0</release>
|
||||
<api>3.3.0</api>
|
||||
</version>
|
||||
<stability>
|
||||
<release>stable</release>
|
||||
<api>stable</api>
|
||||
</stability>
|
||||
<date>2017-04-28</date>
|
||||
<time>16:06:07</time>
|
||||
<license uri="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</license>
|
||||
<notes>
|
||||
GA release.
|
||||
</notes>
|
||||
</release>
|
||||
</changelog>
|
||||
</package>
|
||||
|
@ -55,39 +55,60 @@ static void add_to_table(HashTable* t, const void* def, void* value) {
|
||||
uint nIndex = (ulong)def & t->nTableMask;
|
||||
|
||||
zval* pDest = NULL;
|
||||
zend_hash_index_update(t, (zend_ulong)def, &value, sizeof(zval*), (void**)&pDest);
|
||||
php_proto_zend_hash_index_update(t, (zend_ulong)def, &value, sizeof(zval*),
|
||||
(void**)&pDest);
|
||||
}
|
||||
|
||||
static void* get_from_table(const HashTable* t, const void* def) {
|
||||
void** value;
|
||||
if (zend_hash_index_find(t, (zend_ulong)def, (void**)&value) == FAILURE) {
|
||||
if (php_proto_zend_hash_index_find(t, (zend_ulong)def, (void**)&value) ==
|
||||
FAILURE) {
|
||||
zend_error(E_ERROR, "PHP object not found for given definition.\n");
|
||||
return NULL;
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
static void add_to_list(HashTable* t, void* value) {
|
||||
zval* pDest = NULL;
|
||||
zend_hash_next_index_insert(t, &value, sizeof(void*), (void**)&pDest);
|
||||
static bool exist_in_table(const HashTable* t, const void* def) {
|
||||
void** value;
|
||||
return (php_proto_zend_hash_index_find(t, (zend_ulong)def, (void**)&value) ==
|
||||
SUCCESS);
|
||||
}
|
||||
|
||||
void add_def_obj(const void* def, zval* value) {
|
||||
static void add_to_list(HashTable* t, void* value) {
|
||||
zval* pDest = NULL;
|
||||
php_proto_zend_hash_next_index_insert(t, &value, sizeof(void*),
|
||||
(void**)&pDest);
|
||||
}
|
||||
|
||||
void add_def_obj(const void* def, PHP_PROTO_HASHTABLE_VALUE value) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
Z_ADDREF_P(value);
|
||||
#else
|
||||
++GC_REFCOUNT(value);
|
||||
#endif
|
||||
add_to_table(upb_def_to_php_obj_map, def, value);
|
||||
}
|
||||
|
||||
zval* get_def_obj(const void* def) {
|
||||
return (zval*)get_from_table(upb_def_to_php_obj_map, def);
|
||||
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);
|
||||
}
|
||||
|
||||
void add_ce_obj(const void* ce, zval* value) {
|
||||
void add_ce_obj(const void* ce, PHP_PROTO_HASHTABLE_VALUE value) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
Z_ADDREF_P(value);
|
||||
#else
|
||||
++GC_REFCOUNT(value);
|
||||
#endif
|
||||
add_to_table(ce_to_php_obj_map, ce, value);
|
||||
}
|
||||
|
||||
zval* get_ce_obj(const void* ce) {
|
||||
return (zval*)get_from_table(ce_to_php_obj_map, ce);
|
||||
PHP_PROTO_HASHTABLE_VALUE get_ce_obj(const void* ce) {
|
||||
return (PHP_PROTO_HASHTABLE_VALUE)get_from_table(ce_to_php_obj_map, ce);
|
||||
}
|
||||
|
||||
bool class_added(const void* ce) {
|
||||
return exist_in_table(ce_to_php_obj_map, ce);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -125,12 +146,23 @@ static PHP_GINIT_FUNCTION(protobuf) {
|
||||
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;
|
||||
if(--GC_REFCOUNT(object) == 0) {
|
||||
zend_objects_store_del(object);
|
||||
}
|
||||
efree(ptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static PHP_RINIT_FUNCTION(protobuf) {
|
||||
ALLOC_HASHTABLE(upb_def_to_php_obj_map);
|
||||
zend_hash_init(upb_def_to_php_obj_map, 16, NULL, ZVAL_PTR_DTOR, 0);
|
||||
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, ZVAL_PTR_DTOR, 0);
|
||||
zend_hash_init(ce_to_php_obj_map, 16, NULL, HASHTABLE_VALUE_DTOR, 0);
|
||||
|
||||
generated_pool = NULL;
|
||||
generated_pool_php = NULL;
|
||||
@ -145,10 +177,12 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) {
|
||||
zend_hash_destroy(ce_to_php_obj_map);
|
||||
FREE_HASHTABLE(ce_to_php_obj_map);
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
if (generated_pool_php != NULL) {
|
||||
zval_dtor(generated_pool_php);
|
||||
FREE_ZVAL(generated_pool_php);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -170,6 +204,7 @@ static PHP_MINIT_FUNCTION(protobuf) {
|
||||
static PHP_MSHUTDOWN_FUNCTION(protobuf) {
|
||||
PEFREE(message_handlers);
|
||||
PEFREE(repeated_field_handlers);
|
||||
PEFREE(repeated_field_iter_handlers);
|
||||
PEFREE(map_field_handlers);
|
||||
|
||||
return 0;
|
||||
|
@ -37,11 +37,328 @@
|
||||
#include "upb.h"
|
||||
|
||||
#define PHP_PROTOBUF_EXTNAME "protobuf"
|
||||
#define PHP_PROTOBUF_VERSION "3.2.0a1"
|
||||
#define PHP_PROTOBUF_VERSION "3.3.0"
|
||||
|
||||
#define MAX_LENGTH_OF_INT64 20
|
||||
#define SIZEOF_INT64 8
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// PHP7 Wrappers
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#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(ht, h, pData, nDataSize, pDest) \
|
||||
zend_hash_index_update(ht, h, pData, nDataSize, pDest)
|
||||
|
||||
#define php_proto_zend_hash_index_find(ht, h, pDest) \
|
||||
zend_hash_index_find(ht, h, pDest)
|
||||
|
||||
#define php_proto_zend_hash_next_index_insert(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_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \
|
||||
void LOWWERNAME##_init(TSRMLS_D) { \
|
||||
zend_class_entry class_type; \
|
||||
const char* class_name = CLASSNAME; \
|
||||
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); \
|
||||
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_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_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) (*VALUE)
|
||||
#define ZVAL_PTR_TO_CACHED_PTR(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(PROPERTIES, OFFSET) (PROPERTIES)->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 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)
|
||||
|
||||
#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(HashTable* ht, 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_index_find(const HashTable* ht, 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_next_index_insert(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_CLASS_START(CLASSNAME, CAMELNAME, LOWWERNAME) \
|
||||
void LOWWERNAME##_init(TSRMLS_D) { \
|
||||
zend_class_entry class_type; \
|
||||
const char* class_name = CLASSNAME; \
|
||||
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); \
|
||||
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_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_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) (VALUE)
|
||||
#define ZVAL_PTR_TO_CACHED_PTR(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 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_REFCOUNT(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;
|
||||
}
|
||||
|
||||
#endif // PHP_MAJOR_VERSION >= 7
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Forward Declaration
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -55,7 +372,8 @@ struct MessageHeader;
|
||||
struct MessageLayout;
|
||||
struct RepeatedField;
|
||||
struct RepeatedFieldIter;
|
||||
struct MapField;
|
||||
struct Map;
|
||||
struct Oneof;
|
||||
|
||||
typedef struct DescriptorPool DescriptorPool;
|
||||
typedef struct Descriptor Descriptor;
|
||||
@ -66,7 +384,8 @@ typedef struct MessageHeader MessageHeader;
|
||||
typedef struct MessageLayout MessageLayout;
|
||||
typedef struct RepeatedField RepeatedField;
|
||||
typedef struct RepeatedFieldIter RepeatedFieldIter;
|
||||
typedef struct MapField MapField;
|
||||
typedef struct Map Map;
|
||||
typedef struct Oneof Oneof;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Globals.
|
||||
@ -88,13 +407,14 @@ void message_init(TSRMLS_D);
|
||||
|
||||
// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor
|
||||
// instances.
|
||||
void add_def_obj(const void* def, zval* value);
|
||||
zval* get_def_obj(const void* def);
|
||||
void add_def_obj(const void* def, PHP_PROTO_HASHTABLE_VALUE value);
|
||||
PHP_PROTO_HASHTABLE_VALUE get_def_obj(const void* def);
|
||||
|
||||
// Global map from PHP class entries to wrapper Descriptor/EnumDescriptor
|
||||
// instances.
|
||||
void add_ce_obj(const void* ce, zval* value);
|
||||
zval* get_ce_obj(const void* ce);
|
||||
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);
|
||||
|
||||
extern zend_class_entry* map_field_type;
|
||||
extern zend_class_entry* repeated_field_type;
|
||||
@ -103,20 +423,25 @@ extern zend_class_entry* repeated_field_type;
|
||||
// Descriptor.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct DescriptorPool {
|
||||
zend_object std;
|
||||
PHP_PROTO_WRAP_OBJECT_START(DescriptorPool)
|
||||
upb_symtab* symtab;
|
||||
HashTable* pending_list;
|
||||
};
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
PHP_METHOD(DescriptorPool, getGeneratedPool);
|
||||
PHP_METHOD(DescriptorPool, internalAddGeneratedFile);
|
||||
|
||||
extern zval* generated_pool_php; // wrapper of generated pool
|
||||
// wrapper of generated pool
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
extern zval* generated_pool_php;
|
||||
void descriptor_pool_free(void* object TSRMLS_DC);
|
||||
#else
|
||||
extern zend_object *generated_pool_php;
|
||||
void descriptor_pool_free(zend_object* object);
|
||||
#endif
|
||||
extern DescriptorPool* generated_pool; // The actual generated pool
|
||||
|
||||
struct Descriptor {
|
||||
zend_object std;
|
||||
PHP_PROTO_WRAP_OBJECT_START(Descriptor)
|
||||
const upb_msgdef* msgdef;
|
||||
MessageLayout* layout;
|
||||
zend_class_entry* klass; // begins as NULL
|
||||
@ -126,23 +451,21 @@ struct Descriptor {
|
||||
const upb_handlers* pb_serialize_handlers;
|
||||
const upb_handlers* json_serialize_handlers;
|
||||
const upb_handlers* json_serialize_handlers_preserve;
|
||||
};
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
extern zend_class_entry* descriptor_type;
|
||||
|
||||
void descriptor_name_set(Descriptor *desc, const char *name);
|
||||
|
||||
struct FieldDescriptor {
|
||||
zend_object std;
|
||||
PHP_PROTO_WRAP_OBJECT_START(FieldDescriptor)
|
||||
const upb_fielddef* fielddef;
|
||||
};
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
struct EnumDescriptor {
|
||||
zend_object std;
|
||||
PHP_PROTO_WRAP_OBJECT_START(EnumDescriptor)
|
||||
const upb_enumdef* enumdef;
|
||||
zend_class_entry* klass; // begins as NULL
|
||||
// VALUE module; // begins as nil
|
||||
};
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
extern zend_class_entry* enum_descriptor_type;
|
||||
|
||||
@ -150,13 +473,15 @@ extern zend_class_entry* enum_descriptor_type;
|
||||
// Message class creation.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void* message_data(void* msg);
|
||||
void message_create_with_type(zend_class_entry* ce, zval** message TSRMLS_DC);
|
||||
void* message_data(MessageHeader* msg);
|
||||
void custom_data_init(const zend_class_entry* ce,
|
||||
MessageHeader* msg PHP_PROTO_TSRMLS_DC);
|
||||
|
||||
// Build PHP class for given descriptor. Instead of building from scratch, this
|
||||
// function modifies existing class which has been partially defined in PHP
|
||||
// code.
|
||||
void build_class_from_descriptor(zval* php_descriptor TSRMLS_DC);
|
||||
void build_class_from_descriptor(
|
||||
PHP_PROTO_HASHTABLE_VALUE php_descriptor TSRMLS_DC);
|
||||
|
||||
extern zend_object_handlers* message_handlers;
|
||||
|
||||
@ -227,18 +552,17 @@ struct MessageLayout {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct MessageHeader {
|
||||
zend_object std; // Stores properties table and class info of PHP instance.
|
||||
// This is needed for MessageHeader to be accessed via PHP.
|
||||
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.
|
||||
Descriptor* descriptor; // Kept alive by self.class.descriptor reference.
|
||||
// The real message data is appended after MessageHeader.
|
||||
};
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
MessageLayout* create_layout(const upb_msgdef* msgdef);
|
||||
void layout_init(MessageLayout* layout, void* storage,
|
||||
zval** properties_table TSRMLS_DC);
|
||||
CACHED_VALUE* properties_table PHP_PROTO_TSRMLS_DC);
|
||||
zval* layout_get(MessageLayout* layout, const void* storage,
|
||||
const upb_fielddef* field, zval** cache TSRMLS_DC);
|
||||
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,
|
||||
@ -308,7 +632,12 @@ PHP_METHOD(Util, checkRepeatedField);
|
||||
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);
|
||||
void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache);
|
||||
// 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);
|
||||
void native_slot_init(upb_fieldtype_t type, void* memory, void* 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
|
||||
@ -317,8 +646,13 @@ void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache);
|
||||
// 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,
|
||||
zval** cache TSRMLS_DC);
|
||||
void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC);
|
||||
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_default(upb_fieldtype_t type,
|
||||
CACHED_VALUE* cache TSRMLS_DC);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Map Field.
|
||||
@ -326,13 +660,12 @@ void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC);
|
||||
|
||||
extern zend_object_handlers* map_field_handlers;
|
||||
|
||||
typedef struct {
|
||||
zend_object std;
|
||||
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;
|
||||
} Map;
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
typedef struct {
|
||||
Map* self;
|
||||
@ -349,14 +682,14 @@ upb_value map_iter_value(MapIter* iter, int* len);
|
||||
const upb_fielddef* map_entry_key(const upb_msgdef* msgdef);
|
||||
const upb_fielddef* map_entry_value(const upb_msgdef* msgdef);
|
||||
|
||||
zend_object_value map_field_create(zend_class_entry *ce TSRMLS_DC);
|
||||
void map_field_create_with_field(zend_class_entry *ce, const upb_fielddef *field,
|
||||
zval **map_field TSRMLS_DC);
|
||||
void map_field_create_with_type(zend_class_entry *ce, upb_fieldtype_t key_type,
|
||||
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,
|
||||
zval **map_field TSRMLS_DC);
|
||||
void map_field_free(void* object TSRMLS_DC);
|
||||
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
|
||||
@ -382,33 +715,36 @@ PHP_METHOD(MapField, count);
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
extern zend_object_handlers* repeated_field_handlers;
|
||||
extern zend_object_handlers* repeated_field_iter_handlers;
|
||||
|
||||
struct RepeatedField {
|
||||
zend_object std;
|
||||
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
|
||||
|
||||
struct RepeatedFieldIter {
|
||||
zend_object std;
|
||||
PHP_PROTO_WRAP_OBJECT_START(RepeatedFieldIter)
|
||||
RepeatedField* repeated_field;
|
||||
long position;
|
||||
};
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
void repeated_field_create_with_field(zend_class_entry* ce,
|
||||
const upb_fielddef* field,
|
||||
zval** repeated_field TSRMLS_DC);
|
||||
void repeated_field_create_with_type(zend_class_entry* ce, upb_fieldtype_t type,
|
||||
const zend_class_entry* msg_ce,
|
||||
zval** repeated_field 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 TSRMLS_DC);
|
||||
void repeated_field_push_native(RepeatedField *intern, void *value);
|
||||
|
||||
PHP_METHOD(RepeatedField, __construct);
|
||||
PHP_METHOD(RepeatedField, append);
|
||||
@ -429,12 +765,11 @@ PHP_METHOD(RepeatedFieldIter, valid);
|
||||
// Oneof Field.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
typedef struct {
|
||||
zend_object std;
|
||||
PHP_PROTO_WRAP_OBJECT_START(Oneof)
|
||||
upb_oneofdef* oneofdef;
|
||||
int index; // Index of field in oneof. -1 if not set.
|
||||
char value[NATIVE_SLOT_MAX_SIZE];
|
||||
} Oneof;
|
||||
PHP_PROTO_WRAP_OBJECT_END
|
||||
|
||||
// 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
|
||||
@ -446,24 +781,13 @@ typedef struct {
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
upb_fieldtype_t to_fieldtype(upb_descriptortype_t type);
|
||||
const zend_class_entry *field_type_class(const upb_fielddef *field TSRMLS_DC);
|
||||
const zend_class_entry* field_type_class(
|
||||
const upb_fielddef* field PHP_PROTO_TSRMLS_DC);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Utilities.
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// PHP <-> C conversion.
|
||||
#define UNBOX(class_name, val) \
|
||||
(class_name*)zend_object_store_get_object(val TSRMLS_CC);
|
||||
|
||||
#define BOX(class_name, wrapper, intern, free_func) \
|
||||
MAKE_STD_ZVAL(wrapper); \
|
||||
Z_TYPE_P(wrapper) = IS_OBJECT; \
|
||||
Z_OBJVAL_P(wrapper) \
|
||||
.handle = \
|
||||
zend_objects_store_put(intern, NULL, free_func, NULL TSRMLS_CC); \
|
||||
Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers();
|
||||
|
||||
// Memory management
|
||||
#define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name))
|
||||
#define PEMALLOC(class_name) (class_name*) pemalloc(sizeof(class_name), 1)
|
||||
@ -471,19 +795,15 @@ const zend_class_entry *field_type_class(const upb_fielddef *field TSRMLS_DC);
|
||||
#define FREE(object) efree(object)
|
||||
#define PEFREE(object) pefree(object, 1)
|
||||
|
||||
// Create PHP internal instance.
|
||||
#define CREATE(class_name, intern, init_func) \
|
||||
intern = ALLOC(class_name); \
|
||||
memset(intern, 0, sizeof(class_name)); \
|
||||
init_func(intern TSRMLS_CC);
|
||||
|
||||
// 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
|
||||
|
||||
#endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__
|
||||
|
@ -57,7 +57,7 @@ size_t native_slot_size(upb_fieldtype_t type) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool native_slot_is_default(upb_fieldtype_t type, void* memory) {
|
||||
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: { \
|
||||
@ -75,15 +75,17 @@ static bool native_slot_is_default(upb_fieldtype_t type, void* memory) {
|
||||
#undef CASE_TYPE
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES:
|
||||
return Z_STRLEN_PP(DEREF(memory, zval**)) == 0;
|
||||
return Z_STRLEN_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) ==
|
||||
0;
|
||||
case UPB_TYPE_MESSAGE:
|
||||
return Z_TYPE_PP(DEREF(memory, zval**)) == IS_NULL;
|
||||
return Z_TYPE_P(CACHED_PTR_TO_ZVAL_PTR(DEREF(memory, CACHED_VALUE*))) ==
|
||||
IS_NULL;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass,
|
||||
void* memory, zval* value TSRMLS_DC) {
|
||||
void* memory, zval* value PHP_PROTO_TSRMLS_DC) {
|
||||
switch (type) {
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES: {
|
||||
@ -95,14 +97,14 @@ bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass,
|
||||
zend_error(E_USER_ERROR, "Given string is not UTF8 encoded.");
|
||||
return false;
|
||||
}
|
||||
if (*(zval**)memory != NULL) {
|
||||
|
||||
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);
|
||||
} else {
|
||||
// Handles repeated/map string field. Memory provided by
|
||||
// RepeatedField/Map is not initialized.
|
||||
MAKE_STD_ZVAL(DEREF(memory, zval*));
|
||||
ZVAL_STRINGL(DEREF(memory, zval*), Z_STRVAL_P(value), Z_STRLEN_P(value),
|
||||
1);
|
||||
#else
|
||||
zend_assign_to_variable(cached_zval, value, IS_CV);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -115,13 +117,18 @@ bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass,
|
||||
zend_error(E_USER_ERROR, "Given message does not have correct class.");
|
||||
return false;
|
||||
}
|
||||
if (EXPECTED(DEREF(memory, zval*) != value)) {
|
||||
if (DEREF(memory, zval*) != NULL) {
|
||||
zval_ptr_dtor((zval**)memory);
|
||||
}
|
||||
DEREF(memory, zval*) = value;
|
||||
Z_ADDREF_P(value);
|
||||
|
||||
zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
|
||||
if (EXPECTED(property_ptr != value)) {
|
||||
php_proto_zval_ptr_dtor(property_ptr);
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
DEREF(memory, zval*) = value;
|
||||
Z_ADDREF_P(value);
|
||||
#else
|
||||
ZVAL_ZVAL(property_ptr, value, 1, 0);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@ -151,7 +158,59 @@ bool native_slot_set(upb_fieldtype_t type, const zend_class_entry* klass,
|
||||
return true;
|
||||
}
|
||||
|
||||
void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache) {
|
||||
bool native_slot_set_by_array(upb_fieldtype_t type,
|
||||
const zend_class_entry* klass, void* memory,
|
||||
zval* value 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;
|
||||
}
|
||||
|
||||
// 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_dup(Z_STR_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_REFCOUNT(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, void* cache) {
|
||||
zval* tmp = NULL;
|
||||
switch (type) {
|
||||
case UPB_TYPE_FLOAT:
|
||||
@ -166,7 +225,7 @@ void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache) {
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES:
|
||||
case UPB_TYPE_MESSAGE:
|
||||
DEREF(memory, zval**) = cache;
|
||||
DEREF(memory, CACHED_VALUE*) = cache;
|
||||
break;
|
||||
case UPB_TYPE_ENUM:
|
||||
case UPB_TYPE_INT32:
|
||||
@ -187,38 +246,38 @@ void native_slot_init(upb_fieldtype_t type, void* memory, zval** cache) {
|
||||
}
|
||||
|
||||
void native_slot_get(upb_fieldtype_t type, const void* memory,
|
||||
zval** cache TSRMLS_DC) {
|
||||
CACHED_VALUE* cache TSRMLS_DC) {
|
||||
switch (type) {
|
||||
#define CASE(upb_type, php_type, c_type) \
|
||||
case UPB_TYPE_##upb_type: \
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache); \
|
||||
ZVAL_##php_type(*cache, DEREF(memory, c_type)); \
|
||||
return;
|
||||
#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)
|
||||
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: { \
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache); \
|
||||
char buffer[MAX_LENGTH_OF_INT64]; \
|
||||
sprintf(buffer, "%lld", DEREF(memory, c_type)); \
|
||||
ZVAL_STRING(*cache, buffer, 1); \
|
||||
return; \
|
||||
}
|
||||
#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: { \
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache); \
|
||||
ZVAL_LONG(*cache, DEREF(memory, c_type)); \
|
||||
return; \
|
||||
}
|
||||
#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)
|
||||
@ -227,32 +286,34 @@ CASE(INT64, int64_t)
|
||||
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.
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache);
|
||||
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(*cache, value);
|
||||
ZVAL_LONG(CACHED_PTR_TO_ZVAL_PTR(cache), value);
|
||||
return;
|
||||
}
|
||||
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES: {
|
||||
// For optional string/bytes fields, the cache is owned by the containing
|
||||
// message and should have been updated during setting/decoding. However,
|
||||
// for repeated string/bytes fields, the cache is provided by zend engine
|
||||
// and has not been updated.
|
||||
zval* value = DEREF(memory, zval*);
|
||||
if (*cache != value) {
|
||||
ZVAL_STRINGL(*cache, Z_STRVAL_P(value), Z_STRLEN_P(value), 1);
|
||||
// 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 = DEREF(memory, zval*);
|
||||
if (*cache != value) {
|
||||
ZVAL_ZVAL(*cache, value, 1, 0);
|
||||
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;
|
||||
}
|
||||
@ -261,12 +322,46 @@ CASE(INT64, int64_t)
|
||||
}
|
||||
}
|
||||
|
||||
void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC) {
|
||||
void native_slot_get_by_array(upb_fieldtype_t type, const void* memory,
|
||||
CACHED_VALUE* cache TSRMLS_DC) {
|
||||
switch (type) {
|
||||
#define CASE(upb_type, php_type) \
|
||||
case UPB_TYPE_##upb_type: \
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache); \
|
||||
ZVAL_##php_type(*cache, 0); \
|
||||
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
|
||||
++GC_REFCOUNT(*(zend_object**)memory);
|
||||
ZVAL_OBJ(cache, *(zend_object**)memory);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
default:
|
||||
native_slot_get(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)
|
||||
@ -279,19 +374,19 @@ void native_slot_get_default(upb_fieldtype_t type, zval** cache TSRMLS_DC) {
|
||||
#undef CASE
|
||||
|
||||
#if SIZEOF_LONG == 4
|
||||
#define CASE(upb_type) \
|
||||
case UPB_TYPE_##upb_type: { \
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache); \
|
||||
ZVAL_STRING(*cache, "0", 1); \
|
||||
return; \
|
||||
}
|
||||
#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: { \
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache); \
|
||||
ZVAL_LONG(*cache, 0); \
|
||||
return; \
|
||||
}
|
||||
#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)
|
||||
@ -299,13 +394,13 @@ CASE(INT64)
|
||||
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES: {
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache);
|
||||
ZVAL_STRINGL(*cache, "", 0, 1);
|
||||
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: {
|
||||
SEPARATE_ZVAL_IF_NOT_REF(cache);
|
||||
ZVAL_NULL(*cache);
|
||||
PHP_PROTO_SEPARATE_ZVAL_IF_NOT_REF(cache);
|
||||
ZVAL_NULL(CACHED_PTR_TO_ZVAL_PTR(cache));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
@ -359,14 +454,15 @@ const upb_fielddef* map_entry_value(const upb_msgdef* msgdef) {
|
||||
return value_field;
|
||||
}
|
||||
|
||||
const zend_class_entry* field_type_class(const upb_fielddef* field TSRMLS_DC) {
|
||||
const zend_class_entry* field_type_class(
|
||||
const upb_fielddef* field PHP_PROTO_TSRMLS_DC) {
|
||||
if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) {
|
||||
zval* desc_php = get_def_obj(upb_fielddef_subdef(field));
|
||||
Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC);
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(
|
||||
Descriptor, get_def_obj(upb_fielddef_subdef(field)));
|
||||
return desc->klass;
|
||||
} else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) {
|
||||
zval* desc_php = get_def_obj(upb_fielddef_subdef(field));
|
||||
EnumDescriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC);
|
||||
EnumDescriptor* desc = UNBOX_HASHTABLE_VALUE(
|
||||
EnumDescriptor, get_def_obj(upb_fielddef_subdef(field)));
|
||||
return desc->klass;
|
||||
}
|
||||
return NULL;
|
||||
@ -501,7 +597,7 @@ void free_layout(MessageLayout* layout) {
|
||||
}
|
||||
|
||||
void layout_init(MessageLayout* layout, void* storage,
|
||||
zval** properties_table TSRMLS_DC) {
|
||||
CACHED_VALUE* properties_table PHP_PROTO_TSRMLS_DC) {
|
||||
int i;
|
||||
upb_msg_field_iter it;
|
||||
for (upb_msg_field_begin(&it, layout->msgdef), i = 0; !upb_msg_field_done(&it);
|
||||
@ -510,20 +606,27 @@ void layout_init(MessageLayout* layout, void* storage,
|
||||
void* memory = slot_memory(layout, storage, field);
|
||||
uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
|
||||
int cache_index = slot_property_cache(layout, storage, field);
|
||||
zval** property_ptr = &properties_table[cache_index];
|
||||
CACHED_VALUE* property_ptr = &properties_table[cache_index];
|
||||
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
|
||||
*oneof_case = ONEOF_CASE_NONE;
|
||||
} else if (is_map_field(field)) {
|
||||
zval_ptr_dtor(property_ptr);
|
||||
map_field_create_with_field(map_field_type, field, property_ptr TSRMLS_CC);
|
||||
DEREF(memory, zval**) = property_ptr;
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
MAKE_STD_ZVAL(*property_ptr);
|
||||
#endif
|
||||
map_field_create_with_field(map_field_type, field,
|
||||
property_ptr PHP_PROTO_TSRMLS_CC);
|
||||
DEREF(memory, CACHED_VALUE*) = property_ptr;
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
zval_ptr_dtor(property_ptr);
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
MAKE_STD_ZVAL(*property_ptr);
|
||||
#endif
|
||||
repeated_field_create_with_field(repeated_field_type, field,
|
||||
property_ptr TSRMLS_CC);
|
||||
DEREF(memory, zval**) = property_ptr;
|
||||
property_ptr PHP_PROTO_TSRMLS_CC);
|
||||
DEREF(memory, CACHED_VALUE*) = property_ptr;
|
||||
} else {
|
||||
native_slot_init(upb_fielddef_type(field), memory, property_ptr);
|
||||
}
|
||||
@ -537,7 +640,7 @@ static void* value_memory(const upb_fielddef* field, void* memory) {
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES:
|
||||
case UPB_TYPE_MESSAGE:
|
||||
memory = DEREF(memory, zval**);
|
||||
memory = DEREF(memory, CACHED_VALUE*);
|
||||
break;
|
||||
default:
|
||||
// No operation
|
||||
@ -547,7 +650,7 @@ static void* value_memory(const upb_fielddef* field, void* memory) {
|
||||
}
|
||||
|
||||
zval* layout_get(MessageLayout* layout, const void* storage,
|
||||
const upb_fielddef* field, zval** cache TSRMLS_DC) {
|
||||
const upb_fielddef* field, CACHED_VALUE* cache TSRMLS_DC) {
|
||||
void* memory = slot_memory(layout, storage, field);
|
||||
uint32_t* oneof_case = slot_oneof_case(layout, storage, field);
|
||||
|
||||
@ -558,13 +661,13 @@ zval* layout_get(MessageLayout* layout, const void* storage,
|
||||
native_slot_get(upb_fielddef_type(field), value_memory(field, memory),
|
||||
cache TSRMLS_CC);
|
||||
}
|
||||
return *cache;
|
||||
return CACHED_PTR_TO_ZVAL_PTR(cache);
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
return *cache;
|
||||
return CACHED_PTR_TO_ZVAL_PTR(cache);
|
||||
} else {
|
||||
native_slot_get(upb_fielddef_type(field), value_memory(field, memory),
|
||||
cache TSRMLS_CC);
|
||||
return *cache;
|
||||
return CACHED_PTR_TO_ZVAL_PTR(cache);
|
||||
}
|
||||
}
|
||||
|
||||
@ -583,8 +686,7 @@ void layout_set(MessageLayout* layout, MessageHeader* header,
|
||||
switch (type) {
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
|
||||
zval* desc_php = get_def_obj(msg);
|
||||
Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC);
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
|
||||
ce = desc->klass;
|
||||
// Intentionally fall through.
|
||||
}
|
||||
@ -593,9 +695,9 @@ void layout_set(MessageLayout* layout, MessageHeader* header,
|
||||
int property_cache_index =
|
||||
header->descriptor->layout->fields[upb_fielddef_index(field)]
|
||||
.cache_index;
|
||||
DEREF(memory, zval**) =
|
||||
DEREF(memory, CACHED_VALUE*) =
|
||||
&(header->std.properties_table)[property_cache_index];
|
||||
memory = DEREF(memory, zval**);
|
||||
memory = DEREF(memory, CACHED_VALUE*);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -606,27 +708,130 @@ void layout_set(MessageLayout* layout, MessageHeader* header,
|
||||
*oneof_case = upb_fielddef_number(field);
|
||||
} else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
|
||||
// Works for both repeated and map fields
|
||||
memory = DEREF(memory, zval**);
|
||||
if (EXPECTED(DEREF(memory, zval*) != val)) {
|
||||
zval_ptr_dtor(memory);
|
||||
DEREF(memory, zval*) = val;
|
||||
Z_ADDREF_P(val);
|
||||
memory = DEREF(memory, void**);
|
||||
zval* property_ptr = CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory);
|
||||
|
||||
if (EXPECTED(property_ptr != val)) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
REPLACE_ZVAL_VALUE((zval**)memory, val, 1);
|
||||
#else
|
||||
php_proto_zval_ptr_dtor(property_ptr);
|
||||
ZVAL_ZVAL(property_ptr, val, 1, 0);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
zval* desc_php = get_def_obj(msg);
|
||||
Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC);
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
|
||||
ce = desc->klass;
|
||||
}
|
||||
native_slot_set(type, ce, value_memory(field, memory), val TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
|
||||
static 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, value_memory(field, to_memory),
|
||||
CACHED_PTR_TO_ZVAL_PTR(DEREF(
|
||||
from_memory, CACHED_VALUE*)) PHP_PROTO_TSRMLS_CC);
|
||||
break;
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
|
||||
ce = desc->klass;
|
||||
if (native_slot_is_default(type, to_memory)) {
|
||||
#if PHP_MAJOR_VERSION < 7
|
||||
SEPARATE_ZVAL_IF_NOT_REF((zval**)value_memory(field, to_memory));
|
||||
#endif
|
||||
CREATE_OBJ_ON_ALLOCATED_ZVAL_PTR(
|
||||
CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)), ce);
|
||||
MessageHeader* submsg =
|
||||
UNBOX(MessageHeader,
|
||||
CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)));
|
||||
custom_data_init(ce, submsg PHP_PROTO_TSRMLS_CC);
|
||||
}
|
||||
|
||||
MessageHeader* sub_from =
|
||||
UNBOX(MessageHeader,
|
||||
CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*)));
|
||||
MessageHeader* sub_to =
|
||||
UNBOX(MessageHeader,
|
||||
CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*)));
|
||||
|
||||
layout_merge(desc->layout, sub_from, sub_to PHP_PROTO_TSRMLS_CC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static 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: {
|
||||
const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
|
||||
Descriptor* desc = UNBOX_HASHTABLE_VALUE(Descriptor, get_def_obj(msg));
|
||||
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 TSRMLS_DC) {
|
||||
MessageHeader* to PHP_PROTO_TSRMLS_DC) {
|
||||
int i, j;
|
||||
upb_msg_field_iter it;
|
||||
|
||||
@ -639,11 +844,10 @@ void layout_merge(MessageLayout* layout, MessageHeader* from,
|
||||
|
||||
if (upb_fielddef_containingoneof(field)) {
|
||||
uint32_t oneof_case_offset =
|
||||
layout->fields[upb_fielddef_index(field)].case_offset +
|
||||
sizeof(MessageHeader);
|
||||
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(((uint8_t*)from + oneof_case_offset), uint32_t) !=
|
||||
if (DEREF((message_data(from) + oneof_case_offset), uint32_t) !=
|
||||
upb_fielddef_number(field)) {
|
||||
continue;
|
||||
}
|
||||
@ -658,7 +862,7 @@ void layout_merge(MessageLayout* layout, MessageHeader* from,
|
||||
case UPB_TYPE_BYTES: {
|
||||
int property_cache_index =
|
||||
layout->fields[upb_fielddef_index(field)].cache_index;
|
||||
DEREF(to_memory, zval**) =
|
||||
DEREF(to_memory, CACHED_VALUE*) =
|
||||
&(to->std.properties_table)[property_cache_index];
|
||||
break;
|
||||
}
|
||||
@ -676,141 +880,57 @@ void layout_merge(MessageLayout* layout, MessageHeader* from,
|
||||
int size, key_length, value_length;
|
||||
MapIter map_it;
|
||||
|
||||
zval* to_map_php = *DEREF(to_memory, zval**);
|
||||
zval* from_map_php = *DEREF(from_memory, zval**);
|
||||
Map* to_map = zend_object_store_get_object(to_map_php TSRMLS_CC);
|
||||
Map* from_map = zend_object_store_get_object(from_map_php TSRMLS_CC);
|
||||
zval* to_map_php =
|
||||
CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*));
|
||||
zval* from_map_php =
|
||||
CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*));
|
||||
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 value = map_iter_value(&map_it, &value_length);
|
||||
void* mem = upb_value_memory(&value);
|
||||
switch (to_map->value_type) {
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
zval* new_message;
|
||||
message_create_with_type(to_map->msg_ce, &new_message TSRMLS_CC);
|
||||
Z_ADDREF_P(new_message);
|
||||
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));
|
||||
|
||||
zval* subdesc_php = get_ce_obj(to_map->msg_ce);
|
||||
Descriptor* subdesc =
|
||||
zend_object_store_get_object(subdesc_php TSRMLS_CC);
|
||||
MessageHeader* sub_from =
|
||||
(MessageHeader*)zend_object_store_get_object(DEREF(mem, zval*)
|
||||
TSRMLS_CC);
|
||||
MessageHeader* sub_to =
|
||||
(MessageHeader*)zend_object_store_get_object(
|
||||
new_message TSRMLS_CC);
|
||||
layout_merge(subdesc->layout, sub_from, sub_to TSRMLS_CC);
|
||||
DEREF(mem, zval*) = new_message;
|
||||
break;
|
||||
}
|
||||
case UPB_TYPE_BYTES:
|
||||
case UPB_TYPE_STRING:
|
||||
Z_ADDREF_PP((zval**)mem);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
map_index_set(to_map, key, key_length, value);
|
||||
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) {
|
||||
zval* to_array_php = *DEREF(to_memory, zval**);
|
||||
zval* from_array_php = *DEREF(from_memory, zval**);
|
||||
RepeatedField* to_array =
|
||||
zend_object_store_get_object(to_array_php TSRMLS_CC);
|
||||
RepeatedField* from_array =
|
||||
zend_object_store_get_object(from_array_php TSRMLS_CC);
|
||||
zval* to_array_php = CACHED_PTR_TO_ZVAL_PTR(DEREF(to_memory, CACHED_VALUE*));
|
||||
zval* from_array_php = CACHED_PTR_TO_ZVAL_PTR(DEREF(from_memory, CACHED_VALUE*));
|
||||
RepeatedField* to_array = UNBOX(RepeatedField, to_array_php);
|
||||
RepeatedField* from_array = UNBOX(RepeatedField, from_array_php);
|
||||
|
||||
int size = zend_hash_num_elements(HASH_OF(from_array->array));
|
||||
int size = zend_hash_num_elements(PHP_PROTO_HASH_OF(from_array->array));
|
||||
if (size > 0) {
|
||||
for (j = 0; j < size; j++) {
|
||||
void* memory = NULL;
|
||||
zend_hash_index_find(HASH_OF(from_array->array), j, (void**)&memory);
|
||||
switch (to_array->type) {
|
||||
case UPB_TYPE_STRING:
|
||||
case UPB_TYPE_BYTES: {
|
||||
zval* str;
|
||||
MAKE_STD_ZVAL(str);
|
||||
ZVAL_STRINGL(str, Z_STRVAL_PP((zval**)memory),
|
||||
Z_STRLEN_PP((zval**)memory), 1);
|
||||
memory = &str;
|
||||
break;
|
||||
}
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
zval* new_message;
|
||||
message_create_with_type(from_array->msg_ce, &new_message TSRMLS_CC);
|
||||
Z_ADDREF_P(new_message);
|
||||
|
||||
zval* subdesc_php = get_ce_obj(from_array->msg_ce);
|
||||
Descriptor* subdesc =
|
||||
zend_object_store_get_object(subdesc_php TSRMLS_CC);
|
||||
MessageHeader* sub_from =
|
||||
(MessageHeader*)zend_object_store_get_object(
|
||||
DEREF(memory, zval*) TSRMLS_CC);
|
||||
MessageHeader* sub_to =
|
||||
(MessageHeader*)zend_object_store_get_object(
|
||||
new_message TSRMLS_CC);
|
||||
layout_merge(subdesc->layout, sub_from, sub_to TSRMLS_CC);
|
||||
|
||||
memory = &new_message;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
repeated_field_push_native(to_array, memory TSRMLS_CC);
|
||||
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)));
|
||||
php_proto_zend_hash_index_find(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 {
|
||||
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, value_memory(field, to_memory),
|
||||
*DEREF(from_memory, zval**) TSRMLS_CC);
|
||||
break;
|
||||
case UPB_TYPE_MESSAGE: {
|
||||
const upb_msgdef* msg = upb_fielddef_msgsubdef(field);
|
||||
zval* desc_php = get_def_obj(msg);
|
||||
Descriptor* desc = zend_object_store_get_object(desc_php TSRMLS_CC);
|
||||
ce = desc->klass;
|
||||
if (native_slot_is_default(type, to_memory)) {
|
||||
zval* new_message = NULL;
|
||||
message_create_with_type(ce, &new_message TSRMLS_CC);
|
||||
native_slot_set(type, ce, value_memory(field, to_memory),
|
||||
new_message TSRMLS_CC);
|
||||
}
|
||||
MessageHeader* sub_from =
|
||||
(MessageHeader*)zend_object_store_get_object(
|
||||
*DEREF(from_memory, zval**) TSRMLS_CC);
|
||||
MessageHeader* sub_to =
|
||||
(MessageHeader*)zend_object_store_get_object(
|
||||
*DEREF(to_memory, zval**) TSRMLS_CC);
|
||||
layout_merge(desc->layout, sub_from, sub_to TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
native_slot_merge(field, from_memory, to_memory PHP_PROTO_TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -325,9 +325,18 @@ CONVERT_TO_FLOAT(double);
|
||||
|
||||
bool protobuf_convert_to_bool(zval* from, int8_t* to) {
|
||||
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;
|
||||
@ -357,12 +366,16 @@ bool protobuf_convert_to_string(zval* 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: {
|
||||
int use_copy;
|
||||
zval tmp;
|
||||
zend_make_printable_zval(from, &tmp, &use_copy);
|
||||
php_proto_zend_make_printable_zval(from, &tmp);
|
||||
ZVAL_COPY_VALUE(from, &tmp);
|
||||
return true;
|
||||
}
|
||||
@ -417,34 +430,45 @@ PHP_METHOD(Util, checkMessage) {
|
||||
|
||||
PHP_METHOD(Util, checkRepeatedField) {
|
||||
zval* val;
|
||||
long type;
|
||||
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;
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
if (Z_ISREF_P(val)) {
|
||||
ZVAL_DEREF(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Z_TYPE_P(val) == IS_ARRAY) {
|
||||
HashTable* table = Z_ARRVAL_P(val);
|
||||
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);
|
||||
RepeatedField* intern =
|
||||
(RepeatedField*)zend_object_store_get_object(repeated_field TSRMLS_CC);
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(table, &pointer);
|
||||
zend_hash_get_current_data_ex(table, (void**)&memory, &pointer) ==
|
||||
SUCCESS;
|
||||
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(repeated_field, NULL,
|
||||
*(zval**)memory TSRMLS_CC);
|
||||
repeated_field_handlers->write_dimension(
|
||||
CACHED_TO_ZVAL_PTR(repeated_field), NULL,
|
||||
CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)memory) TSRMLS_CC);
|
||||
}
|
||||
|
||||
Z_DELREF_P(repeated_field);
|
||||
RETURN_ZVAL(repeated_field, 1, 0);
|
||||
Z_DELREF_P(CACHED_TO_ZVAL_PTR(repeated_field));
|
||||
RETURN_ZVAL(CACHED_TO_ZVAL_PTR(repeated_field), 1, 0);
|
||||
|
||||
} else if (Z_TYPE_P(val) == IS_OBJECT) {
|
||||
if (!instanceof_function(Z_OBJCE_P(val), repeated_field_type TSRMLS_CC)) {
|
||||
@ -452,8 +476,7 @@ PHP_METHOD(Util, checkRepeatedField) {
|
||||
repeated_field_type->name);
|
||||
return;
|
||||
}
|
||||
RepeatedField* intern =
|
||||
(RepeatedField*)zend_object_store_get_object(val TSRMLS_CC);
|
||||
RepeatedField* intern = UNBOX(RepeatedField, val);
|
||||
if (to_fieldtype(type) != intern->type) {
|
||||
zend_error(E_USER_ERROR, "Incorrect repeated field type.");
|
||||
return;
|
||||
@ -474,43 +497,55 @@ PHP_METHOD(Util, checkRepeatedField) {
|
||||
|
||||
PHP_METHOD(Util, checkMapField) {
|
||||
zval* val;
|
||||
long key_type, value_type;
|
||||
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;
|
||||
}
|
||||
|
||||
#if PHP_MAJOR_VERSION >= 7
|
||||
if (Z_ISREF_P(val)) {
|
||||
ZVAL_DEREF(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Z_TYPE_P(val) == IS_ARRAY) {
|
||||
HashTable* table = Z_ARRVAL_P(val);
|
||||
HashPosition pointer;
|
||||
zval key, *map_field;
|
||||
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);
|
||||
Map* intern =
|
||||
(Map*)zend_object_store_get_object(map_field TSRMLS_CC);
|
||||
|
||||
for (zend_hash_internal_pointer_reset_ex(table, &pointer);
|
||||
zend_hash_get_current_data_ex(table, (void**)&value, &pointer) ==
|
||||
SUCCESS;
|
||||
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(map_field, &key,
|
||||
*(zval**)value TSRMLS_CC);
|
||||
map_field_handlers->write_dimension(
|
||||
CACHED_TO_ZVAL_PTR(map_field), &key,
|
||||
CACHED_PTR_TO_ZVAL_PTR((CACHED_VALUE*)value) TSRMLS_CC);
|
||||
}
|
||||
|
||||
Z_DELREF_P(map_field);
|
||||
RETURN_ZVAL(map_field, 1, 0);
|
||||
Z_DELREF_P(CACHED_TO_ZVAL_PTR(map_field));
|
||||
RETURN_ZVAL(CACHED_TO_ZVAL_PTR(map_field), 1, 0);
|
||||
} else if (Z_TYPE_P(val) == IS_OBJECT) {
|
||||
if (!instanceof_function(Z_OBJCE_P(val), map_field_type TSRMLS_CC)) {
|
||||
zend_error(E_USER_ERROR, "Given value is not an instance of %s.",
|
||||
map_field_type->name);
|
||||
return;
|
||||
}
|
||||
Map* intern = (Map*)zend_object_store_get_object(val TSRMLS_CC);
|
||||
Map* intern = UNBOX(Map, val);
|
||||
if (to_fieldtype(key_type) != intern->key_type) {
|
||||
zend_error(E_USER_ERROR, "Incorrect map field key type.");
|
||||
return;
|
||||
|
@ -95,6 +95,9 @@ class DescriptorPool
|
||||
foreach ($descriptor->getNestedType() as $nested_type) {
|
||||
$this->addDescriptor($nested_type);
|
||||
}
|
||||
foreach ($descriptor->getEnumType() as $enum_type) {
|
||||
$this->addEnumDescriptor($enum_type);
|
||||
}
|
||||
}
|
||||
|
||||
public function addEnumDescriptor($descriptor)
|
||||
|
47
php/src/Google/Protobuf/Internal/GPBDecodeException.php
Normal file
47
php/src/Google/Protobuf/Internal/GPBDecodeException.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
// 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.
|
||||
|
||||
namespace Google\Protobuf\Internal;
|
||||
|
||||
class GPBDecodeException extends \Exception
|
||||
{
|
||||
public function __construct(
|
||||
$message,
|
||||
$code = 0,
|
||||
\Exception $previous = null)
|
||||
{
|
||||
parent::__construct(
|
||||
"Error occurred during parsing: " . $message,
|
||||
$code,
|
||||
$previous);
|
||||
}
|
||||
}
|
@ -330,6 +330,7 @@ class InputStream
|
||||
* passed unchanged to the corresponding call to popLimit().
|
||||
*
|
||||
* @param integer $byte_limit
|
||||
* @throws Exception Fail to push limit.
|
||||
*/
|
||||
public function pushLimit($byte_limit)
|
||||
{
|
||||
@ -339,19 +340,15 @@ class InputStream
|
||||
|
||||
// security: byte_limit is possibly evil, so check for negative values
|
||||
// and overflow.
|
||||
if ($byte_limit >= 0 && $byte_limit <= PHP_INT_MAX - $current_position) {
|
||||
if ($byte_limit >= 0 &&
|
||||
$byte_limit <= PHP_INT_MAX - $current_position &&
|
||||
$byte_limit <= $this->current_limit - $current_position) {
|
||||
$this->current_limit = $current_position + $byte_limit;
|
||||
$this->recomputeBufferLimits();
|
||||
} else {
|
||||
// Negative or overflow.
|
||||
$this->current_limit = PHP_INT_MAX;
|
||||
throw new GPBDecodeException("Fail to push limit.");
|
||||
}
|
||||
|
||||
// We need to enforce all limits, not just the new one, so if the previous
|
||||
// limit was before the new requested limit, we continue to enforce the
|
||||
// previous limit.
|
||||
$this->current_limit = min($this->current_limit, $old_limit);
|
||||
|
||||
$this->recomputeBufferLimits();
|
||||
return $old_limit;
|
||||
}
|
||||
|
||||
@ -370,7 +367,7 @@ class InputStream
|
||||
}
|
||||
|
||||
public function incrementRecursionDepthAndPushLimit(
|
||||
$byte_limit, &$old_limit, &$recursion_budget)
|
||||
$byte_limit, &$old_limit, &$recursion_budget)
|
||||
{
|
||||
$old_limit = $this->pushLimit($byte_limit);
|
||||
$recursion_limit = --$this->recursion_limit;
|
||||
|
@ -155,7 +155,6 @@ function checkKey($key_type, &$key)
|
||||
GPBUtil::checkString($key, true);
|
||||
break;
|
||||
default:
|
||||
var_dump($key_type);
|
||||
trigger_error(
|
||||
"Given type cannot be map key.",
|
||||
E_USER_ERROR);
|
||||
@ -284,6 +283,9 @@ class MapField implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
GPBUtil::checkString($value, true);
|
||||
break;
|
||||
case GPBType::MESSAGE:
|
||||
if (is_null($value)) {
|
||||
trigger_error("Map element cannot be null.", E_USER_ERROR);
|
||||
}
|
||||
GPBUtil::checkMessage($value, $this->klass);
|
||||
break;
|
||||
default:
|
||||
|
@ -224,48 +224,57 @@ class Message
|
||||
switch ($field->getType()) {
|
||||
case GPBType::DOUBLE:
|
||||
if (!GPBWire::readDouble($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside double field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::FLOAT:
|
||||
if (!GPBWire::readFloat($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside float field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::INT64:
|
||||
if (!GPBWire::readInt64($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside int64 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::UINT64:
|
||||
if (!GPBWire::readUint64($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside uint64 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::INT32:
|
||||
if (!GPBWire::readInt32($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside int32 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::FIXED64:
|
||||
if (!GPBWire::readFixed64($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside fixed64 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::FIXED32:
|
||||
if (!GPBWire::readFixed32($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside fixed32 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::BOOL:
|
||||
if (!GPBWire::readBool($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside bool field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::STRING:
|
||||
// TODO(teboring): Add utf-8 check.
|
||||
if (!GPBWire::readString($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside string field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::GROUP:
|
||||
@ -280,43 +289,51 @@ class Message
|
||||
$value = new $klass;
|
||||
}
|
||||
if (!GPBWire::readMessage($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside message.");
|
||||
}
|
||||
break;
|
||||
case GPBType::BYTES:
|
||||
if (!GPBWire::readString($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside bytes field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::UINT32:
|
||||
if (!GPBWire::readUint32($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside uint32 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::ENUM:
|
||||
// TODO(teboring): Check unknown enum value.
|
||||
if (!GPBWire::readInt32($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside enum field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::SFIXED32:
|
||||
if (!GPBWire::readSfixed32($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside sfixed32 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::SFIXED64:
|
||||
if (!GPBWire::readSfixed64($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside sfixed64 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::SINT32:
|
||||
if (!GPBWire::readSint32($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside sint32 field.");
|
||||
}
|
||||
break;
|
||||
case GPBType::SINT64:
|
||||
if (!GPBWire::readSint64($input, $value)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside sint64 field.");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -345,24 +362,21 @@ class Message
|
||||
}
|
||||
|
||||
if ($value_format === GPBWire::NORMAL_FORMAT) {
|
||||
if (!self::parseFieldFromStreamNoTag($input, $field, $value)) {
|
||||
return false;
|
||||
}
|
||||
self::parseFieldFromStreamNoTag($input, $field, $value);
|
||||
} elseif ($value_format === GPBWire::PACKED_FORMAT) {
|
||||
$length = 0;
|
||||
if (!GPBWire::readInt32($input, $length)) {
|
||||
return false;
|
||||
throw new GPBDecodeException(
|
||||
"Unexpected EOF inside packed length.");
|
||||
}
|
||||
$limit = $input->pushLimit($length);
|
||||
$getter = $field->getGetter();
|
||||
while ($input->bytesUntilLimit() > 0) {
|
||||
if (!self::parseFieldFromStreamNoTag($input, $field, $value)) {
|
||||
return false;
|
||||
}
|
||||
self::parseFieldFromStreamNoTag($input, $field, $value);
|
||||
$this->$getter()[] = $value;
|
||||
}
|
||||
$input->popLimit($limit);
|
||||
return true;
|
||||
return;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -377,8 +391,6 @@ class Message
|
||||
$setter = $field->getSetter();
|
||||
$this->$setter($value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -567,7 +579,8 @@ class Message
|
||||
* specified message.
|
||||
*
|
||||
* @param string $data Binary protobuf data.
|
||||
* @return bool Return true on success.
|
||||
* @return null.
|
||||
* @throws Exception Invalid data.
|
||||
*/
|
||||
public function mergeFromString($data)
|
||||
{
|
||||
@ -595,9 +608,7 @@ class Message
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->parseFieldFromStream($tag, $input, $field)) {
|
||||
return false;
|
||||
}
|
||||
$this->parseFieldFromStream($tag, $input, $field);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,10 @@ class RepeatedField implements \ArrayAccess, \IteratorAggregate, \Countable
|
||||
GPBUtil::checkString($value, true);
|
||||
break;
|
||||
case GPBType::MESSAGE:
|
||||
if (is_null($value)) {
|
||||
trigger_error("RepeatedField element cannot be null.",
|
||||
E_USER_ERROR);
|
||||
}
|
||||
GPBUtil::checkMessage($value, $this->klass);
|
||||
break;
|
||||
default:
|
||||
|
@ -210,6 +210,12 @@ class Descriptor
|
||||
$nested_proto, $file_proto, $message_name_without_package));
|
||||
}
|
||||
|
||||
// Handle nested enum.
|
||||
foreach ($proto->getEnumType() as $enum_proto) {
|
||||
$desc->addEnumType(EnumDescriptor::buildFromProto(
|
||||
$enum_proto, $file_proto, $message_name_without_package));
|
||||
}
|
||||
|
||||
// Handle oneof fields.
|
||||
foreach ($proto->getOneofDecl() as $oneof_proto) {
|
||||
$desc->addOneofDecl(
|
||||
@ -220,20 +226,36 @@ class Descriptor
|
||||
}
|
||||
}
|
||||
|
||||
function getClassNamePrefix(
|
||||
$classname,
|
||||
$file_proto)
|
||||
{
|
||||
$option = $file_proto->getOptions();
|
||||
$prefix = is_null($option) ? "" : $option->getPhpClassPrefix();
|
||||
if ($prefix !== "") {
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
$reserved_words = array("Empty");
|
||||
foreach ($reserved_words as $reserved_word) {
|
||||
if ($classname === $reserved_word) {
|
||||
if ($file_proto->getPackage() === "google.protobuf") {
|
||||
return "GPB";
|
||||
} else {
|
||||
return "PB";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function getClassNameWithoutPackage(
|
||||
$name,
|
||||
$file_proto)
|
||||
{
|
||||
if ($name === "Empty" && $file_proto->getPackage() === "google.protobuf") {
|
||||
return "GPBEmpty";
|
||||
} else {
|
||||
$option = $file_proto->getOptions();
|
||||
$prefix = is_null($option) ? "" : $option->getPhpClassPrefix();
|
||||
// Nested message class names are seperated by '_', and package names
|
||||
// are seperated by '\'.
|
||||
return $prefix . implode('_', array_map('ucwords',
|
||||
explode('.', $name)));
|
||||
}
|
||||
$classname = implode('_', array_map('ucwords', explode('.', $name)));
|
||||
return getClassNamePrefix($classname, $file_proto) . $classname;
|
||||
}
|
||||
|
||||
function getFullClassName(
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user