Compare commits

...
Sign in to create a new pull request.

163 commits
down ... master

Author SHA1 Message Date
Roman Kuznetsov
bda4bb9068 Put v3.3.0 at the top of master branch to simplify usage of this repository as submodule 2017-07-08 16:55:13 +03:00
Adam Cozzette
bd5ab154da Merge pull request #2482 from andreaseger/fix_ruby_timestamp_accuracy
[Ruby] fix floating point accuracy problem in Timestamp#to_f
2017-07-06 08:11:50 -07:00
MaDuo
6bd51a59df add Grpc Protobuf validation (#3311)
* add Grpc Protobuf validation
2017-07-05 11:31:32 -07:00
Thomas Van Lenten
e264b20e69 Merge pull request #3315 from thomasvl/mutate_unknowns
Expose the initializer for unknown fields.
2017-07-05 11:25:38 -04:00
Thomas Van Lenten
b30dee3ea6 Expose the initializer for unknown fields. 2017-07-05 11:16:34 -04:00
Jon Skeet
cdd524a0bd Ensure leaveOpen is true when writing to a buffer
Note that the compatibility tests have had to cahnge as well, to
cope with internal changes. (The test project has access to
internals in the main project.)

Fixes #3209.
2017-07-04 06:42:45 +01:00
Jon Skeet
62d7fe5697 Make Any easier to work with in C#
- Add a TryUnpack method which doesn't throw if the type is wrong
- Make GetTypeName public for easier determination of the message type

Fixes #3294.
2017-07-03 12:16:40 +01:00
Paul Yang
ecca6ea95d Add json encode/decode for php. (#3226)
* Add json encode/decode for php.

* Fix php conformance test on 32-bit machines.

* Fix conformance test for c extension.

* Fix comments
2017-06-30 12:14:09 -07:00
Thomas Van Lenten
5a52b3588d Merge pull request #3287 from sergiocampama/initialized
Add initialized as a reserved keyword as that's the actual property name
2017-06-29 11:52:37 -04:00
Sergio Campama
e55782fa95 Add initialized as a reserved keyword as that's the actual property name 2017-06-29 11:49:36 -04:00
Paul Yang
176bac6dac Add scripts to build python wheel for linux. (#2693)
* Add scripts to build python wheel for linux.
Followed PEP513.

* Fix dist check for new added files.

* Update README for usage example.
2017-06-28 15:22:19 -07:00
Brent Shaffer
12acbc2678 adds PHPDoc @return and @param for getters and setters respectively (#3131)
* adds PHPDoc @return and @param for getters and setters respectively

* addresses changes in PR review

* adds documentation tests

* Update php_generator:

- Prepend \ to names where required
- Remove <pre> tags
- Update protobuf field comments

* Updates class files with the protobuf changes

* Addresses review comments

* removes Protobuf Type line from PHP generated classes

* fixes phpdoc test

* adds array types to phpdoc
2017-06-27 16:28:28 -07:00
Feng Xiao
097bfb53d1 Merge pull request #3084 from lukaszx0/patch-1
Workaround the docker bug when compiling artifacts
2017-06-26 10:48:22 -07:00
Paul Yang
dd7265e1a2 Merge pull request #3264 from TeBoring/php-bug
Enusre public header and generated code have no implicit converion.
2017-06-24 12:20:57 -07:00
Bo Yang
e3c807d4e7 Fix more implicit type conversions in public headers and generated code. 2017-06-24 11:28:13 -07:00
Feng Xiao
1a7e49d462 Merge pull request #2968 from ngg/cpp-proper-fwd
C++: Do not forward-declare dependencies in generated .h files
2017-06-23 15:08:04 -07:00
Bo Yang
9c0b35cf62 Enusre public header and generated code have no implicit converion. 2017-06-23 11:58:05 -07:00
Feng Xiao
f752d816b7 Merge pull request #3266 from mbrickn/patch-1
Updated links to use https
2017-06-23 10:39:42 -07:00
Maxwell Paul Brickner
d07efbad91 Updated links to use https
Howdy!

I just updated some links to use https instead of http.

Thanks! ^ _ ^
2017-06-23 09:25:03 -04:00
Thomas Van Lenten
eca0f4ee91 Merge pull request #3261 from thomasvl/super_oddcase
If we fail to get a descriptor just super the method resolving.
2017-06-22 10:34:10 -04:00
Thomas Van Lenten
db45687a38 If we fail to get a descriptor just super the method resolving.
This should never happen, but if someone is swizzling or do other
hooking of methods, anything is possible, so this seems slighty
safer than they returning NO.
2017-06-22 10:18:00 -04:00
Ryan Gordon
703cd8e11c Switch to addEnumType to fix fatal error (#3225)
* Switch to addEnumType to fix fatal error

* Fixing more cases of HHVM incompatibility

* Updating tests to be hhvm compatible

* Fixing tests

* Fixing merge

* Don't use call_user_func, should hopefully fix tests

* Fixing spelling

* Fixing another misspelling in a test

* Fixing placement of append and kvUpdate functions

* Actually fix function helpers

* Remove double addEnumType. How did this ever work?

* Fixing a couple more tests

* Only use the setter if the return value isn't an object
2017-06-19 18:15:49 -07:00
Joshua Haberman
1325588982 Updated upb to fix JSON conformance issues. (#3206)
* Fixed a bunch of Ruby conformance errors.

* Fixed some more Ruby conformance errors in JSON.
2017-06-19 15:13:24 -07:00
Feng Xiao
c2fdef05cf Merge pull request #3243 from yjjnls/master
replenish missed header files in install step
2017-06-19 11:18:45 -07:00
Thomas Van Lenten
73b7cc0007 Merge pull request #3244 from thomasvl/complete_docs
ObjC: Document the exceptions on some of the writing apis.
2017-06-19 10:34:25 -04:00
Thomas Van Lenten
5fd71ce631 ObjC: Document the exceptions on some of the writing apis. 2017-06-19 10:33:45 -04:00
Thomas Van Lenten
72e293a28f Merge pull request #3240 from thomasvl/float_fun
Raise the number of digits used for floats.
2017-06-19 08:23:37 -04:00
yjjnls
8f367c0b2d replenish missed header files in install step
install 'generated_message_table_driven.h' and 'metadata_lite.h', they are included when compiling the files generated using protoc.exe 3.3.0
2017-06-19 14:15:54 +08:00
Jeff Ching
5729cf77f6 Remove inclusion of ext/json/php_json.h. (#3241)
That implementation of json is not being used - this extension is using
a json encoder/decoder provided by 'upb'.
2017-06-17 11:01:16 -07:00
Thomas Van Lenten
dd19b876d4 Raise the number of digits used for floats.
About 1.5% of all IEEE754 single-precision numbers require nine
decimal digits to represent accurately.
2017-06-16 15:24:33 -04:00
Feng Xiao
710543d915 Merge pull request #3237 from calder/patch-1
Qualify string in java_options.h
2017-06-16 11:39:11 -07:00
Feng Xiao
491b32041d Merge pull request #3236 from buchgr/bazel-links
bazel: add bazel symlinks to .gitignore
2017-06-16 11:38:15 -07:00
Feng Xiao
888e287e3b Merge pull request #3235 from buchgr/java-target
bazel: Make compiled jars java 6 binary compatible.
2017-06-16 11:37:48 -07:00
Calder Coalson
4b36d4006b Qualify string in java_options.h
Building the protobuf compiler with Bazel fails to resolve the unqualifed "string"s in java_options.h:

```
ERROR: .../external/com_google_protobuf/BUILD:248:1: C++ compilation of rule '@com_google_protobuf//:protoc_lib' failed: Process exited with status 1 [sandboxed].
In file included from external/com_google_protobuf/src/google/protobuf/compiler/java/java_context.h:41:0,
                 from external/com_google_protobuf/src/google/protobuf/compiler/java/java_enum_field_lite.cc:38:
external/com_google_protobuf/src/google/protobuf/compiler/java/java_options.h:59:3: error: 'string' does not name a type
   string annotation_list_file;
   ^
external/com_google_protobuf/src/google/protobuf/compiler/java/java_options.h:62:3: error: 'string' does not name a type
   string output_list_file;
   ^
Use --strategy=CppCompile=standalone to disable sandboxing for the failing actions.
INFO: Elapsed time: 41.487s, Critical Path: 6.20s
//interpreter:eval_test                                               NO STATUS

Executed 0 out of 1 test: 1 was skipped.
```
2017-06-16 07:06:09 -07:00
Jakob Buchgraber
36e63da632 bazel: Make compiled jars java 6 binary compatible.
See: https://github.com/bazelbuild/bazel/issues/3198
2017-06-16 12:50:35 +02:00
Jakob Buchgraber
d0e6f3b9ab bazel: add bazel symlinks to .gitignore 2017-06-16 12:39:32 +02:00
Paul Yang
91bf623aa1 Fix php jenkins test (#3233)
Update commit id to upload latest composer.
Compile php with bc-math for future json support.
2017-06-15 13:04:08 -07:00
michaelbausor
8d97b3d8b5 Fix incorrect function call (#3232) 2017-06-15 10:49:24 -07:00
Brent Shaffer
b9b34e9b11 Follows proper autoloading standards (#3123)
* Follows proper autoloading standards
 - Splits PHP classes in descriptor.php into separate files
 - Splits MapFieldIter and RepeatedFieldIter into separate files
 - Moves descriptor.php to Internal/functions.php
 - Moves all namespaced functions into Iternal/functions.php

* fixes Makefile.am for added php files

* [PHP] moves all functions to GPBUtil

* removes description.php from the makefile
2017-06-14 15:57:11 -07:00
Thomas Van Lenten
09d2994b1f Merge pull request #3228 from thomasvl/add_tvos_to_podspec
Add tvOS to the podspec.
2017-06-14 15:57:55 -04:00
Thomas Van Lenten
6ecf38f427 Add tvOS to the podspec.
Fixes https://github.com/google/protobuf/issues/3217
2017-06-14 15:56:41 -04:00
Feng Xiao
c722c3d294 Merge pull request #3216 from traversaro/patch-1
Export symbols used in inline functions
2017-06-12 10:26:57 -07:00
Silvio Traversaro
9094bf0f7e Export symbols used in inline functions
fixed_address_empty_string symbol is used in an inline function.
We have to export it to avoid undefined reference link errors.
2017-06-12 17:09:55 +02:00
Gergely Nagy
9ba7d1c038 C++: Do not forward-declare dependencies in generated .h files 2017-06-12 14:34:51 +02:00
Adam Cozzette
96095f3a85 Merge pull request #3176 from acozzette/fix-3114
Ensure that for Java, imports of .proto files with empty packages works
2017-06-07 15:15:34 -07:00
Feng Xiao
c202b06de9 Merge pull request #3196 from matt-kwong/kokoro
Add continuous testing config files for Kokoro
2017-06-07 11:09:37 -07:00
Matt Kwong
0871e6a808 Add continuous testing config files for Kokoro 2017-06-07 11:08:00 -07:00
Feng Xiao
d4d41af19b Merge pull request #3191 from matt-kwong/kokoro
Add MacOS and Linux tests to Kokoro
2017-06-06 16:44:30 -07:00
Matt Kwong
6156af10e8 Add MacOS and Linux tests to Kokoro 2017-06-06 15:09:02 -07:00
Thomas Van Lenten
d555775836 Merge pull request #3189 from thomasvl/objc_proto3_unknown_fields
ObjC: Preserve unknown fields in proto3 syntax files.
2017-06-06 15:31:20 -04:00
Feng Xiao
2aeb4ab9c7 Merge pull request #3160 from meteorcloudy/winbuild
Refactor cc options in BUILD file for Windows
2017-06-06 10:31:21 -07:00
Adam Cozzette
ddbe36003e Merge pull request #3159 from yeswalrus/new-generate
CMake: Add modern protobuf_generate
2017-06-06 09:13:31 -07:00
Thomas Van Lenten
1d0988b8ef ObjC: Preserve unknown fields in proto3 syntax files.
As announced: https://groups.google.com/forum/#!topic/protobuf/VX5qEmTW3y0

The ObjC side of https://github.com/google/protobuf/issues/272
2017-06-06 10:44:14 -04:00
Thomas Van Lenten
516a81a424 Merge pull request #3190 from thomasvl/objc_IllegalZeroFieldNum
Properly error on a tag with field number zero.
2017-06-06 10:41:04 -04:00
Thomas Van Lenten
ecc0f54127 Properly error on a tag with field number zero. 2017-06-06 10:14:41 -04:00
Adam Cozzette
656dedbf07 Merge pull request #3157 from yeswalrus/fix-version-check
Fix CMake version check
2017-06-05 14:19:23 -07:00
Paul Yang
6f325805c0 Add new file option php_namespace. (#3162)
* Add new file option php_namespace.

Use this option to change the namespace of php generated classes.
Default is empty. When this option is empty, the package name will be
used for determining the namespace.

* Uncomment commented tests

* Revert gdb test change

* Update csharp descriptor.

* Add test for empty php_namespace.
2017-06-05 00:10:18 -07:00
Walter Gray
df3f8cf6dd fix check_and_save_build_option not correctly exporting build options 2017-06-02 19:59:03 -07:00
Walter Gray
0336770801 add protobuf_generate function, allows use of target_sources where available 2017-06-02 19:57:08 -07:00
Adam Cozzette
e9c15d601e Ensure that for Java, imports of .proto files with empty packages works
This fixes a compiler bug that caused a Java syntax error when one .proto file
would import another one with an empty package and java_package. This fixes
issue #3114.
2017-06-02 13:45:57 -07:00
Thomas Van Lenten
fbaad3617f Merge pull request #3169 from dmaclach/master
Optimize GPBDictionary.m codegen to reduce size of library
2017-06-01 15:34:00 -04:00
Thomas Van Lenten
63a97289dc Merge pull request #3170 from thomasvl/int64_map_issue
Fix some cases of reading of 64bit map values.
2017-06-01 14:27:24 -04:00
Thomas Van Lenten
46f36d79a2 Fix some cases of reading of 64bit map values.
Fixes https://github.com/google/protobuf/issues/3164.
2017-06-01 14:25:45 -04:00
Dave MacLachlan
ea43e0c5e8 Optimize GPBDictionary.m codegen to reduce size of overall library by 46K per architecture. 2017-06-01 10:28:06 -07:00
Yun Peng
0b059a3d8a Refactor cc options in BUILD file for Windows
Don't put gcc warnings options in copts, so that protobuf is able to
build by MSVC toolchain without python wrappers.
2017-05-31 14:01:30 +02:00
Walter Gray
a183a0df61 Fix the check_and_save_build_option macro never evaluating to true 2017-05-30 15:04:11 -07:00
Walter Gray
faa53989cb fix check_and_save_build_option not correctly exporting build options 2017-05-30 15:04:11 -07:00
Walter Gray
ae85cb8ef3 Fix find module not working when no version number was given 2017-05-30 15:04:11 -07:00
Wayne Zhang
d6470abef1 not to use std::random_device for map.Seed(). (#3133)
* not to use std::random_device for map.Seed().

* remove include random
2017-05-30 11:18:23 -07:00
Adam Cozzette
e222997c5b Merge pull request #3149 from KarrokDC/master
Add headers as part of cmake project generation
2017-05-30 09:27:21 -07:00
Paul Yang
1e86ef4e9f Oneof field should be serialized even it's equal to default. (#3153) 2017-05-29 22:04:20 -07:00
Paul Yang
282fb9e68e Add ARRAY for reserved name (#3150) 2017-05-29 15:30:47 -07:00
Brent Shaffer
4d5daf4ef9 Adds fluent setters for PHP (#3130) 2017-05-29 10:39:14 -07:00
Dennis Cappendijk
4eb02fe31e Add headers as part of cmake project
tested only on windows with visual studio 2015 as generator
2017-05-29 17:34:08 +02:00
Adam Cozzette
4674cc7c07 Merge pull request #3113 from phst/master
Improve fix for https://github.com/google/protobuf/issues/295
2017-05-26 09:50:18 -07:00
John Brock
95749d5af6 update csharp README and fix .NET 3.5 build error 2017-05-25 20:20:31 +01:00
Jon Skeet
0b07d7eb9e Add IncludeSource in csproj as per review comments 2017-05-24 09:07:33 +01:00
Jon Skeet
f26e8c2ae0 Convert C# projects to MSBuild (csproj) format
This has one important packaging change: the netstandard version now
depends (implicitly) on netstandard1.6.1 rather than on individual
packages. This is the preferred style of dependency, and shouldn't
affect any users - see http://stackoverflow.com/questions/42946951
for details.

The tests are still NUnit, but NUnit doesn't support "dotnet test"
yet; the test project is now an executable using NUnitLite. (When
NUnit supports dotnet test, we can adapt to it.)

Note that the project will now only work in Visual Studio 2017 (and
Visual Studio Code, and from the command line with the .NET Core
1.0.0 SDK); Visual Studio 2015 does *not* support this project file
format.
2017-05-24 09:07:33 +01:00
brian-peloton
40da1ed572 Removing undefined behavior and compiler warnings (#1315)
* Comment out unused arguments.

These last few are all that's needed to compile with -Wunused-arguments.

* Fix missing struct field initializer.

With this fix, everything compiles with -Wmissing-field-initializers.

* Add support for disabling unaligned memory accesses on x86 too.

ubsan doesn't like these because they are technically undefined
behavior, so -DGOOGLE_PROTOBUF_DONT_USE_UNALIGNED will disable them easily.

* Avoid undefined integer overflow.

ubsan catches all of these.
2017-05-23 16:22:57 -07:00
Feng Xiao
ba987a7e2d Merge pull request #3126 from mbrukman/fix-readme-formatting
Fix Markdown formatting in README.
2017-05-23 14:04:08 -07:00
Feng Xiao
c5125f371d Merge pull request #3117 from KarrokDC/master
Show help if protoc is called without any arguments
2017-05-23 13:39:56 -07:00
Thomas Van Lenten
d2c1865374 Merge pull request #3103 from sergiocampama/perf
Adds serial and parallel parsing tests.
2017-05-23 15:14:08 -04:00
Sergio Campama
2465ae7e23 Adds serial and parallel parsing tests to check if parallel parsing is faster than serial parsing, which it should 2017-05-23 11:04:35 -04:00
Misha Brukman
677557009c Fix Markdown formatting in README.
Fix indentation to enable code formatting for sample command lines to set them
visually apart from the surrounding text, and make it easy to copy-paste.

Add code formatting for env vars, paths, binary and library names for
readability.

Hide URLs behind text for readability and conciseness.
2017-05-23 10:39:40 -04:00
Philipp Stephani
979107ec7a Improve fix for https://github.com/google/protobuf/issues/295
Requiring the legacy ‘cl’ library unconditionally pollutes the namespace.
Instead, require it only when compiling and in known-broken versions.

This is almost the same patch that opoplawski suggested, except that I removed
the test for ‘emacs-repository-version’, which isn’t defined in Emacs 24.3.
2017-05-23 15:27:29 +02:00
Dennis Cappendijk
3b227611d5 show help if protoc is called without any arguments, pre-empts -h and --help to show a useful message instead of just 'Missing input file.' 2017-05-22 16:21:48 +02:00
Thomas Van Lenten
8546620610 Merge pull request #3104 from thomasvl/ext_registry_copy
Fix ExtensionRegistry copying and add tests.
2017-05-17 15:05:20 -04:00
Thomas Van Lenten
49e4ba6098 Fix ExtensionRegistry copying and add tests.
- Fix up -copyWithZone: to not leave the two registries sharing
  some of the storage by using -addExtensions:.
- Improve -addExtensions: to clone the sub dict when there is
  nothing to merge into.
- A ExtensionRegistry unittests.
- Update project schemes to not have extra things in perf scheme.
2017-05-17 14:51:02 -04:00
Joshua Haberman
b28617b813 Merge pull request #2815 from devwout/ruby_json_emit_defaults
Ruby version optionally emits default values in JSON encoding.
2017-05-15 08:05:27 -07:00
Andreas Eger
78cb804063 change test for nanosecond accurate timestamps 2017-05-13 22:20:45 +02:00
Andreas Eger
ad203bcb2b fix floating point accuracy problem in Timestamp#to_f
`.quo` return the most exact devision which fixes accuracy problems for the
timestamp coercion
2017-05-13 21:38:15 +02:00
Łukasz Strzałkowski
82e50ba5c3 Workaround the docker bug when compiling artifacts
This is a workaround (https://github.com/moby/moby/issues/10180#issuecomment-190429512) the docker issue (https://github.com/moby/moby/issues/10180) which breaks protoc-artifacts build process with following error

```Rpmdb checksum is invalid: dCDPT(pkg checksums): devtoolset-1.1-elfutils.x86_64 0:0.154-6.el6 - u

The command '/bin/sh -c yum clean all && yum install -y devtoolset-1.1                    devtoolset-1.1-libstdc++-devel                    devtoolset-1.1-libstdc++-devel.i686' returned a non-zero code: 1```

https://github.com/moby/moby/issues/10180#issuecomment-190429512
2017-05-11 14:04:34 -07:00
Feng Xiao
455b61c6b0 Merge pull request #3062 from Oppen/master
Workaround gcc < 4.5.0 bug
2017-05-08 11:19:02 -07:00
Paul Yang
25abd7b7e7 Add compatibility test for php. (#3041)
* Add compatibility test for php.

* Revert API incompatible change.
2017-05-05 11:14:11 -07:00
Mario J. Rugiero
cd0efc0024 Workaround gcc < 4.5.0 bug
See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=189

Signed-off-by: Mario J. Rugiero <mrugiero@gmail.com>
2017-05-05 14:02:49 -03:00
Adam Cozzette
483396068d Merge pull request #3043 from acozzette/javascript
Removed mention of Buffer in byteSourceToUint8Array
2017-05-04 12:21:14 -07:00
Adam Cozzette
f00e06c95b Removed mention of Buffer in byteSourceToUint8Array
The Closure compiler complains about Buffer since that class exists only
in Node. That logic does not seem to be needed (unit tests and conformance
tests pass without it), so let's just remove it to solve the problem.
2017-05-02 17:25:54 -07:00
Adam Cozzette
a64497c709 Merge pull request #2873 from myitcv/fix_1562
Javascript: use goog.crypt.byteArrayToString instead of String.fromCharCode.apply
2017-05-02 16:57:34 -07:00
Paul Jolly
bcb3506641 Fix #1562 by using goog.crypt.byteArrayToString instead of String.fromCharCode.apply 2017-05-02 13:40:42 +01:00
Adam Cozzette
2f4489a3e5 Merge pull request #3024 from acozzette/merge-3.3-to-master
Merged 3.3.x branch to master
2017-05-01 10:58:38 -07:00
makdharma
286f059842 added "objectivec" build target (#3033)
This target will be used by gRPC iOS bazel build system.
2017-05-01 09:49:26 -07:00
Adam Cozzette
9053033a50 Merge remote-tracking branch 'remotes/google/3.3.x' into merge-3.3-to-master 2017-04-27 14:55:53 -07:00
Adam Cozzette
067b1eec3b Merge pull request #3023 from acozzette/min
Fully qualify min as std::min in wire_format_lite.cc
2017-04-27 13:56:27 -07:00
Adam Cozzette
07c284f86c Fully qualify min as std::min in wire_format_lite.cc 2017-04-27 11:35:59 -07:00
Paul Yang
a6189acd18 Add prefix to enum value with reserved name. (#3020) 2017-04-26 16:32:21 -07:00
Adam Cozzette
cbd08cb7d1 Merge pull request #3018 from acozzette/using-namespace-std
Remove "using namespace std" from stubs/common.h
2017-04-26 13:56:24 -07:00
Feng Xiao
54d1701f6c Merge pull request #3015 from buchgr/unused-consts
Remove unused constants.
2017-04-26 11:09:42 -07:00
Adam Cozzette
7c76ac1735 Remove "using namespace std" from stubs/common.h
This prevents the contents of the std namespace from being effectively
pulled into the top-level namespace in all translation units that
include common.h. I left in individual using statements for a few common
things like std::set and std::map, because it did not seem worth going
through the churn of updating the whole codebase to fix those right now.
2017-04-26 08:25:01 -07:00
Paul Yang
3c0855e94a Add a test case for nested enum, which was missed previously. (#3010) 2017-04-25 10:47:09 -07:00
Jakob Buchgraber
b1c75bc742 Remove unused constants.
When compiling with -Werror, -Wunused-const-variable the build fails due
to those two constants not being used.
2017-04-25 12:49:00 +02:00
Feng Xiao
4920e27a48 Merge pull request #3008 from postmasters/patch-1
Add a link to dart-lang/protobuf
2017-04-24 13:09:48 -07:00
Paul Yang
fba2acd72e Add nested enum descriptor in php rumtime. (#3009) 2017-04-24 12:40:37 -07:00
Paul Yang
e64b618b21 Update php version number to 3.3.0 (#3001) 2017-04-24 09:24:43 -07:00
postmasters
4777574a6c Add a link to dart-lang/protobuf 2017-04-24 08:46:56 -07:00
Paul Yang
6fff091c49 Throw exception when parsing invalid data. (#3000) 2017-04-21 15:00:00 -07:00
Feng Xiao
f418b9e3eb Merge pull request #2996 from xfxyjwf/3.3.x
Fix python3 issue.
2017-04-20 17:32:48 -07:00
Paul Yang
4523c9c233 Allow proto files to import descriptor.proto (#2995)
descriptor.proto uses proto2 syntax, which is not ready for external
usage. However, some proto3 files import descriptor.proto and cannot be
used. In this PR, all references (We cheated by only removing
extensions, which is enough for now. User should avoid using messages
defined in descriptor.proto as field type.) to content in
descriptor.proto are removed from generated files. Those that import
descriptor.proto can be used like other proto files.
2017-04-20 16:55:56 -07:00
Feng Xiao
478119fe77 Fix python3 issue. 2017-04-20 16:30:26 -07:00
Feng Xiao
14afc3fd41 Merge pull request #2992 from xiaogaozi/patch-1
Add gogoprotobuf to third-party add-ons list
2017-04-20 11:12:02 -07:00
Changjian Gao
f85eecb585 Add gogoprotobuf to third-party add-ons list 2017-04-20 19:53:11 +08:00
Paul Yang
4c57e8475f Prepend "PB" to generated classes whose name are reserved words. (#2990) 2017-04-20 01:19:03 -07:00
Paul Yang
b97cd573e4 Add test for nested enum for php (#2989) 2017-04-19 21:20:55 -07:00
Paul Yang
7be088202b Enum defined without package have incorrect class name. (#2988)
Fix the bug by sharing the code for generating class name for both
message and enum.
2017-04-19 20:03:34 -07:00
Paul Yang
190b5270c8 Make PHP c extension work with PHP7 (#2951) 2017-04-19 16:23:51 -07:00
Feng Xiao
357afc39de Merge pull request #2508 from yliu120/pass_default_env_to_protoc
add a key to ctx.action dict to prevent protoc losing the default env
2017-04-19 11:28:54 -07:00
Feng Xiao
0a93f67055 Merge pull request #2987 from konsumer/patch-1
Add node-protoc-plugin to "Other Utilities"
2017-04-19 10:30:42 -07:00
Adam Cozzette
594f810081 Merge pull request #2982 from mda000/issue2972
Simplify the Element dtor invocation when freeing elements in InternalDeallocate
2017-04-19 08:34:54 -07:00
David Konsumer
3055a02125 Add node-protoc-plugin to "Other Utilities" 2017-04-18 18:58:21 -07:00
Thomas Van Lenten
a3873cafae Merge pull request #2985 from thomasvl/class_check_tweaks
Tighten up class usage/checks.
2017-04-18 13:28:41 -04:00
Thomas Van Lenten
f5a01d1bbd Tighten up class usage/checks.
- Ensure extensions resolution/wiring is happening directly on the
  messageClass (incase someone is doing odd things our out classes).
- Make the extension message check match the other class checks in
  for mergeFrom/isEqual/etc.
2017-04-18 13:10:52 -04:00
Michael Allen
2240a785f9 Simplify the Element dtor invocation when freeing elements in
InternalDeallocate to avoid confusing the compiler when there's
a class named Element already defined in the global namespace.
2017-04-17 10:59:31 -07:00
Feng Xiao
8aa927f08f Merge pull request #2950 from anuraaga/dev_rag
Allow unknown values for Map put*Value methods just like every other …
2017-04-12 10:42:18 -07:00
Feng Xiao
43234828da Merge pull request #2967 from xfxyjwf/3.3.x
Fix map serialization
2017-04-11 16:52:06 -07:00
Feng Xiao
5777259273 Cherry-pick cl/152450543 2017-04-11 16:15:46 -07:00
Feng Xiao
cad0258d17 Cherry-pick cl/151775298 2017-04-11 16:14:00 -07:00
Feng Xiao
fc3ea97870 Merge pull request #2955 from xfxyjwf/3.3.x
Add include for INT_MAX
2017-04-11 16:13:32 -07:00
Jie Luo
899460c9cb cherrypick descriptor_pool.FindFileContainingSymbol by extensions (#2962)
* Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject()

* Cherrypick the fix descriptor_pool.FindFileContainingSymbol by extensions.
2017-04-10 16:37:57 -07:00
Feng Xiao
bfeeb98517 Add include for INT_MAX 2017-04-08 00:39:03 +00:00
Feng Xiao
e91caa1f19 Merge pull request #2949 from xfxyjwf/3.3.x
Cleanup reflection objects for map entry.
2017-04-07 11:30:40 -07:00
Anuraag Agrawal
bf483dfb99 Allow unknown values for Map put*Value methods just like every other enum mutation method. 2017-04-07 14:50:52 +09:00
Feng Xiao
ee9c7f17e9 Cleanup reflection objects for map entry. 2017-04-06 16:47:18 -07:00
Adam Cozzette
efec757104 Merge pull request #2937 from anuraaga/dev_rag2
Fix duplicate fields test and Any test. The repeated version is passing because nu…
2017-04-06 16:27:54 -07:00
Feng Xiao
18c13c93de Merge pull request #2942 from xfxyjwf/3.3.x
Update version number and changelog for 3.3.0
2017-04-06 11:46:51 -07:00
Feng Xiao
21b0b3ca36 Update generated code. 2017-04-05 17:45:21 -07:00
Feng Xiao
80f0c0ac40 Update version number and changelog for 3.3.0 2017-04-05 17:32:17 -07:00
Jie Luo
69bfde22b6 Merge pull request #2922 from anandolee/master
Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject()
2017-04-05 16:34:54 -07:00
Anuraag Agrawal
09328db1ff Fix test for unexpected type url when parsing Any. Currently, the test fails since TestAllTypes doesn't have field '@type', which is the same test as testUnknownFields. 2017-04-05 17:44:26 +09:00
Adam Cozzette
139fd0a1c5 Merge pull request #2933 from mharrend/patch-1
Adding default shell env to allow non-default compilers
2017-04-04 09:34:06 -07:00
Adam Cozzette
37c7b766b3 Merge pull request #2930 from anuraaga/dev_rag
Fix error message for int64 parse failure.
2017-04-04 09:31:14 -07:00
Anuraag Agrawal
662f97841e Fix duplicate fields test. The repeated version is passing because null values in a repeated field are rejected and not testing what it wanted to. Also adds a oneof version that verifies the case of oneof fields of different names (currently only same name check seems to be tested).
Also fix spelling of a test.
2017-04-04 17:27:53 +09:00
Adam Cozzette
cc3fa2ec80 Merge pull request #2676 from acozzette/js-compatibility-tests
JS compatibility tests
2017-04-03 14:39:26 -07:00
Adam Cozzette
10ea25133d Added compatibility tests for version 3.0.0 2017-04-03 12:55:20 -07:00
Adam Cozzette
7e5f980508 Split test protos into two groups 2017-04-03 12:55:20 -07:00
Marco A. Harrendorf
dd04ffb923 Adding default shell env
I am adding default shell environment, so that protobuf compilation makes use of set
LD_LIBRARY_PATH and so on.
In this way, also non-default gcc installations (e.g. not in /usr/lib) can be used to compile protobuf.
This would fix the following issue:
https://github.com/bazelbuild/bazel/issues/2515
2017-04-03 17:01:36 +02:00
Anuraag Agrawal
58373fa160 Fix error message for int64 parse error. 2017-04-03 17:35:42 +09:00
Anuraag Agrawal
11c902ea2e Add IntelliJ project to gitignore for java project. 2017-04-03 17:32:08 +09:00
Feng Xiao
bd74319107 Update Java conformance failure list. 2017-03-31 15:59:48 -07:00
Feng Xiao
32ad5a3e0d Use "git reset --hard" to actually reset the code. 2017-03-31 14:04:29 -07:00
Feng Xiao
b7c813fb67 Update jenkins Java dependencies. 2017-03-31 11:13:28 -07:00
Jie Luo
c348d46a9b Use PyUnicode_AsEncodedString() instead of PyUnicode_AsEncodedObject() 2017-03-29 15:54:06 -07:00
Ewout
aec0711075 Ruby tests compare parsed JSON instead of raw JSON 2017-03-17 10:28:17 +01:00
Ewout
008dc92c9d Ruby version optionally emits default values in JSON encoding.
Usage: Message.encode_json(m, emit_defaults: true)
Message fields that are nil will still not appear in the encoded JSON.
2017-03-09 20:47:56 +01:00
Yunlong Liu
ef61a9d313 add a key to ctx.action dict to prevent protoc losing the default env 2016-12-16 00:46:21 -05:00
78 changed files with 3277 additions and 1447 deletions

3
.gitignore vendored
View file

@ -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

View file

@ -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

View file

@ -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() thats 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 doesnt 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 didnt 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 libcs 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

View file

@ -646,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 \
@ -656,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 \

View file

@ -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'

View file

@ -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])

View file

@ -32,7 +32,6 @@ Recommended.JsonInput.StringFieldSingleQuoteValue
Recommended.JsonInput.StringFieldSurrogateInWrongOrder
Recommended.JsonInput.StringFieldUnpairedHighSurrogate
Recommended.JsonInput.StringFieldUnpairedLowSurrogate
Recommended.JsonInput.StringFieldUppercaseEscapeLetter
Recommended.JsonInput.Uint32MapFieldKeyNotQuoted
Recommended.JsonInput.Uint64MapFieldKeyNotQuoted
Required.JsonInput.EnumFieldNotQuoted

View file

@ -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

View file

@ -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>

View file

@ -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." ],

View file

@ -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

View file

@ -129,7 +129,7 @@ ENV MVN mvn --batch-mode
RUN cd /tmp && \
git clone https://github.com/google/protobuf.git && \
cd protobuf && \
git reset 057a2851e41e9a0ad95d2cd76aba8bc39ba2e6e3 && \
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

View file

@ -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

View file

@ -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": [

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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>

View file

@ -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;

View file

@ -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__

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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)

View 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);
}
}

View file

@ -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;

View file

@ -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:

View file

@ -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);
}
}

View file

@ -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:

View file

@ -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(

View file

@ -751,23 +751,13 @@ class RepeatedFieldTest extends PHPUnit_Framework_TestCase
$arr []= $sub_m;
$this->assertSame(1, $arr[0]->getA());
$null = null;
$arr []= $null;
$this->assertNull($arr[1]);
$this->assertEquals(2, count($arr));
for ($i = 0; $i < count($arr); $i++) {
$arr[$i] = $null;
$this->assertNull($arr[$i]);
}
$this->assertEquals(1, count($arr));
// Test set.
$sub_m = new TestMessage_Sub();
$sub_m->setA(2);
$arr [0]= $sub_m;
$this->assertSame(1, $arr[0]->getA());
$arr [1]= $null;
$this->assertNull($arr[1]);
$this->assertSame(2, $arr[0]->getA());
}
/**
@ -817,6 +807,27 @@ class RepeatedFieldTest extends PHPUnit_Framework_TestCase
$arr []= new TestMessage;
}
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testMessageAppendNullFail()
{
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class);
$null = null;
$arr []= $null;
}
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testMessageSetNullFail()
{
$arr = new RepeatedField(GPBType::MESSAGE, TestMessage_Sub::class);
$arr []= new TestMessage_Sub();
$null = null;
$arr[0] = $null;
}
#########################################################
# Test offset type
#########################################################

View file

@ -211,6 +211,204 @@ class EncodeDecodeTest extends TestBase
$this->assertEquals(-1, $m->getOptionalInt32());
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidInt32()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('08'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidSubMessage()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('9A010108'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidInt64()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('10'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidUInt32()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('18'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidUInt64()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('20'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidSInt32()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('28'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidSInt64()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('30'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidFixed32()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('3D'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidFixed64()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('41'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidSFixed32()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('4D'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidSFixed64()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('51'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidFloat()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('5D'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidDouble()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('61'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidBool()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('68'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidStringLengthMiss()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('72'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidStringDataMiss()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('7201'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidBytesLengthMiss()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('7A'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidBytesDataMiss()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('7A01'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidEnum()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('8001'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidMessageLengthMiss()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('8A01'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidMessageDataMiss()
{
$m = new TestMessage();
$m->mergeFromString(hex2bin('8A0101'));
}
/**
* @expectedException Exception
*/
public function testDecodeInvalidPackedMessageLength()
{
$m = new TestPackedMessage();
$m->mergeFromString(hex2bin('D205'));
}
# TODO(teboring): Add test back when php implementation is ready for json
# encode/decode.
# public function testJsonEncode()

View file

@ -3,10 +3,8 @@
# gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so `which
# phpunit` --bootstrap autoload.php tmp_test.php
#
gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so `which phpunit` --bootstrap autoload.php array_test.php
gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so `which phpunit` --bootstrap autoload.php well_known_test.php
#
# # gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so
# memory_leak_test.php
# gdb --args php -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php
#
# # USE_ZEND_ALLOC=0 valgrind --leak-check=yes php
# -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php
# USE_ZEND_ALLOC=0 valgrind --leak-check=yes php -dextension=../ext/google/protobuf/modules/protobuf.so memory_leak_test.php

View file

@ -1,7 +1,7 @@
<?php
require_once('generated/NoNameSpaceEnum.php');
require_once('generated/NoNameSpaceMessage.php');
require_once('generated/NoNamespaceEnum.php');
require_once('generated/NoNamespaceMessage.php');
require_once('test_base.php');
require_once('test_util.php');
@ -295,6 +295,12 @@ class GeneratedClassTest extends TestBase
$this->assertEquals(TestEnum::ONE, $m->getOptionalEnum());
}
public function testNestedEnum()
{
$m = new TestMessage();
$m->setOptionalNestedEnum(\Foo\TestMessage_NestedEnum::ZERO);
}
#########################################################
# Test float field.
#########################################################
@ -832,12 +838,20 @@ class GeneratedClassTest extends TestBase
public function testMessageWithoutNamespace()
{
$m = new NoNameSpaceMessage();
$m = new TestMessage();
$sub = new NoNameSpaceMessage();
$m->setOptionalNoNamespaceMessage($sub);
$m->getRepeatedNoNamespaceMessage()[] = new NoNameSpaceMessage();
$n = new NoNamespaceMessage();
$n->setB(NoNamespaceMessage_NestedEnum::ZERO);
}
public function testEnumWithoutNamespace()
{
$m = new NoNameSpaceEnum();
$m = new TestMessage();
$m->setOptionalNoNamespaceEnum(NoNameSpaceEnum::VALUE_A);
$m->getRepeatedNoNamespaceEnum()[] = NoNameSpaceEnum::VALUE_A;
}
#########################################################
@ -852,4 +866,15 @@ class GeneratedClassTest extends TestBase
$m->setPrefixMessage($n);
$this->assertSame(1, $m->getPrefixMessage()->getA());
}
#########################################################
# Test prefix for reserved words.
#########################################################
public function testPrefixForReservedWords()
{
$m = new \Foo\TestMessage_Empty();
$m = new \Foo\PBEmpty();
$m = new \PrefixEmpty();
}
}

View file

@ -616,11 +616,7 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
$arr[0] = $sub_m;
$this->assertSame(1, $arr[0]->getA());
$null = NULL;
$arr[1] = $null;
$this->assertNull($arr[1]);
$this->assertEquals(2, count($arr));
$this->assertEquals(1, count($arr));
}
/**
@ -653,6 +649,17 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
$arr[0] = new TestMessage_Sub();
}
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testMessageSetNullFail()
{
$arr =
new MapField(GPBType::INT32, GPBType::MESSAGE, TestMessage::class);
$null = NULL;
$arr[0] = $null;
}
#########################################################
# Test memory leak
#########################################################

View file

@ -2,17 +2,25 @@
# phpunit has memory leak by itself. Thus, it cannot be used to test memory leak.
require_once('generated/NoNamespaceEnum.php');
require_once('generated/NoNamespaceMessage.php');
require_once('generated/NoNamespaceMessage_NestedEnum.php');
require_once('generated/PrefixEmpty.php');
require_once('generated/PrefixTestPrefix.php');
require_once('generated/Bar/TestInclude.php');
require_once('generated/Foo/PBEmpty.php');
require_once('generated/Foo/TestEnum.php');
require_once('generated/Foo/TestIncludePrefixMessage.php');
require_once('generated/Foo/TestMessage.php');
require_once('generated/Foo/TestMessage_Empty.php');
require_once('generated/Foo/TestMessage_NestedEnum.php');
require_once('generated/Foo/TestMessage_Sub.php');
require_once('generated/Foo/TestPackedMessage.php');
require_once('generated/Foo/TestPhpDoc.php');
require_once('generated/Foo/TestUnpackedMessage.php');
require_once('generated/GPBMetadata/Proto/Test.php');
require_once('generated/GPBMetadata/Proto/TestInclude.php');
require_once('generated/GPBMetadata/Proto/TestNoNamespace.php');
require_once('generated/GPBMetadata/Proto/TestPrefix.php');
require_once('test_util.php');
@ -83,7 +91,8 @@ $n = new TestMessage();
$n->mergeFromString($data);
assert(1 === $n->getOneofMessage()->getA());
$from = new TestMessage();
$to = new TestMessage();
TestUtil::setTestMessage($from);
$to->mergeFrom($from);
# $from = new TestMessage();
# $to = new TestMessage();
# TestUtil::setTestMessage($from);
# $to->mergeFrom($from);
# TestUtil::assertTestMessage($to);

View file

@ -1,6 +1,7 @@
syntax = "proto3";
import 'proto/test_include.proto';
import 'proto/test_no_namespace.proto';
import 'proto/test_prefix.proto';
package foo;
@ -96,12 +97,34 @@ message TestMessage {
// Reserved for non-existing field test.
// int32 non_exist = 89;
NoNamespaceMessage optional_no_namespace_message = 91;
NoNamespaceEnum optional_no_namespace_enum = 92;
repeated NoNamespaceMessage repeated_no_namespace_message = 93;
repeated NoNamespaceEnum repeated_no_namespace_enum = 94;
enum NestedEnum {
ZERO = 0;
}
NestedEnum optional_nested_enum = 101;
// Test prefix for reserved words.
message Empty {
int32 a = 1;
}
}
enum TestEnum {
ZERO = 0;
ONE = 1;
TWO = 2;
ECHO = 3; // Test reserved name.
}
// Test prefix for reserved words.
message Empty {
int32 a = 1;
}
message TestPackedMessage {

View file

@ -0,0 +1,14 @@
syntax = "proto3";
import "google/protobuf/descriptor.proto";
message TestImportDescriptorProto {
extend google.protobuf.MethodOptions {
int32 a = 72295727;
}
}
extend google.protobuf.MethodOptions {
int32 a = 72295728;
}

View file

@ -1,10 +1,16 @@
syntax = "proto3";
message NoNameSpaceMessage {
message NoNamespaceMessage {
int32 a = 1;
enum NestedEnum {
ZERO = 0;
}
NestedEnum b = 2;
repeated NestedEnum c = 3;
}
enum NoNameSpaceEnum {
enum NoNamespaceEnum {
VALUE_A = 0;
VALUE_B = 1;
}

View file

@ -5,3 +5,8 @@ option php_class_prefix = "Prefix";
message TestPrefix {
int32 a = 1;
}
// Test prefix for reserved words.
message Empty {
int32 a = 1;
}

View file

@ -51,8 +51,6 @@ class TestUtil
public static function setTestMessage(TestMessage $m)
{
$sub = new TestMessage_Sub();
$m->setOptionalInt32(-42);
$m->setOptionalInt64(-43);
$m->setOptionalUint32(42);
@ -69,6 +67,7 @@ class TestUtil
$m->setOptionalString('a');
$m->setOptionalBytes('b');
$m->setOptionalEnum(TestEnum::ONE);
$sub = new TestMessage_Sub();
$m->setOptionalMessage($sub);
$m->getOptionalMessage()->SetA(33);

View file

@ -4,8 +4,14 @@ use Google\Protobuf\GPBEmpty;
class WellKnownTest extends PHPUnit_Framework_TestCase {
public function testNone() {
$msg = new GPBEmpty();
public function testNone()
{
$msg = new GPBEmpty();
}
public function testImportDescriptorProto()
{
$msg = new TestImportDescriptorProto();
}
}

View file

@ -10,7 +10,7 @@
</parent>
<groupId>com.google.protobuf</groupId>
<artifactId>protoc</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<packaging>pom</packaging>
<name>Protobuf Compiler</name>
<description>

View file

@ -30,7 +30,7 @@
# Copyright 2007 Google Inc. All Rights Reserved.
__version__ = '3.2.0'
__version__ = '3.3.0'
if __name__ != '__main__':
try:

View file

@ -127,6 +127,9 @@ class DescriptorPool(object):
self._service_descriptors = {}
self._file_descriptors = {}
self._toplevel_extensions = {}
# TODO(jieluo): Remove _file_desc_by_toplevel_extension when
# FieldDescriptor.file is added in code gen.
self._file_desc_by_toplevel_extension = {}
# We store extensions in two two-level mappings: The first key is the
# descriptor of the message being extended, the second key is the extension
# full name or its tag number.
@ -170,7 +173,7 @@ class DescriptorPool(object):
raise TypeError('Expected instance of descriptor.Descriptor.')
self._descriptors[desc.full_name] = desc
self.AddFileDescriptor(desc.file)
self._AddFileDescriptor(desc.file)
def AddEnumDescriptor(self, enum_desc):
"""Adds an EnumDescriptor to the pool.
@ -185,7 +188,7 @@ class DescriptorPool(object):
raise TypeError('Expected instance of descriptor.EnumDescriptor.')
self._enum_descriptors[enum_desc.full_name] = enum_desc
self.AddFileDescriptor(enum_desc.file)
self._AddFileDescriptor(enum_desc.file)
def AddServiceDescriptor(self, service_desc):
"""Adds a ServiceDescriptor to the pool.
@ -251,6 +254,23 @@ class DescriptorPool(object):
file_desc: A FileDescriptor.
"""
self._AddFileDescriptor(file_desc)
# TODO(jieluo): This is a temporary solution for FieldDescriptor.file.
# Remove it when FieldDescriptor.file is added in code gen.
for extension in file_desc.extensions_by_name.values():
self._file_desc_by_toplevel_extension[
extension.full_name] = file_desc
def _AddFileDescriptor(self, file_desc):
"""Adds a FileDescriptor to the pool, non-recursively.
If the FileDescriptor contains messages or enums, the caller must explicitly
register them.
Args:
file_desc: A FileDescriptor.
"""
if not isinstance(file_desc, descriptor.FileDescriptor):
raise TypeError('Expected instance of descriptor.FileDescriptor.')
self._file_descriptors[file_desc.name] = file_desc
@ -313,12 +333,18 @@ class DescriptorPool(object):
except KeyError:
pass
try:
return self._file_desc_by_toplevel_extension[symbol]
except KeyError:
pass
# Try nested extensions inside a message.
message_name, _, extension_name = symbol.rpartition('.')
try:
scope = self.FindMessageTypeByName(message_name)
assert scope.extensions_by_name[extension_name]
return scope.file
message = self.FindMessageTypeByName(message_name)
assert message.extensions_by_name[extension_name]
return message.file
except KeyError:
raise KeyError('Cannot find a file containing %s' % symbol)

View file

@ -63,6 +63,9 @@ from google.protobuf import symbol_database
class DescriptorPoolTest(unittest.TestCase):
def setUp(self):
# TODO(jieluo): Should make the pool which is created by
# serialized_pb same with generated pool.
# TODO(jieluo): More test coverage for the generated pool.
self.pool = descriptor_pool.DescriptorPool()
self.factory_test1_fd = descriptor_pb2.FileDescriptorProto.FromString(
factory_test1_pb2.DESCRIPTOR.serialized_pb)
@ -128,6 +131,12 @@ class DescriptorPoolTest(unittest.TestCase):
self.assertEqual('google/protobuf/internal/factory_test2.proto',
file_desc4.name)
# Tests the generated pool.
assert descriptor_pool.Default().FindFileContainingSymbol(
'google.protobuf.python.internal.Factory2Message.one_more_field')
assert descriptor_pool.Default().FindFileContainingSymbol(
'google.protobuf.python.internal.another_field')
def testFindFileContainingSymbolFailure(self):
with self.assertRaises(KeyError):
self.pool.FindFileContainingSymbol('Does not exist')

View file

@ -779,7 +779,7 @@ PyObject* CheckString(PyObject* arg, const FieldDescriptor* descriptor) {
encoded_string = arg; // Already encoded.
Py_INCREF(encoded_string);
} else {
encoded_string = PyUnicode_AsEncodedObject(arg, "utf-8", NULL);
encoded_string = PyUnicode_AsEncodedString(arg, "utf-8", NULL);
}
} else {
// In this case field type is "bytes".

View file

@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "google-protobuf"
s.version = "3.2.0.1"
s.version = "3.3.0"
s.licenses = ["BSD-3-Clause"]
s.summary = "Protocol Buffers"
s.description = "Protocol Buffers are Google's data interchange format."

View file

@ -184,7 +184,7 @@ nobase_include_HEADERS = \
lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
libprotobuf_lite_la_LIBADD = $(PTHREAD_LIBS)
libprotobuf_lite_la_LDFLAGS = -version-info 12:0:0 -export-dynamic -no-undefined
libprotobuf_lite_la_LDFLAGS = -version-info 13:0:0 -export-dynamic -no-undefined
if HAVE_LD_VERSION_SCRIPT
libprotobuf_lite_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libprotobuf-lite.map
EXTRA_libprotobuf_lite_la_DEPENDENCIES = libprotobuf-lite.map
@ -229,7 +229,7 @@ libprotobuf_lite_la_SOURCES = \
google/protobuf/io/zero_copy_stream_impl_lite.cc
libprotobuf_la_LIBADD = $(PTHREAD_LIBS)
libprotobuf_la_LDFLAGS = -version-info 12:0:0 -export-dynamic -no-undefined
libprotobuf_la_LDFLAGS = -version-info 13:0:0 -export-dynamic -no-undefined
if HAVE_LD_VERSION_SCRIPT
libprotobuf_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libprotobuf.map
EXTRA_libprotobuf_la_DEPENDENCIES = libprotobuf.map
@ -318,7 +318,7 @@ libprotobuf_la_SOURCES = \
nodist_libprotobuf_la_SOURCES = $(nodist_libprotobuf_lite_la_SOURCES)
libprotoc_la_LIBADD = $(PTHREAD_LIBS) libprotobuf.la
libprotoc_la_LDFLAGS = -version-info 12:0:0 -export-dynamic -no-undefined
libprotoc_la_LDFLAGS = -version-info 13:0:0 -export-dynamic -no-undefined
if HAVE_LD_VERSION_SCRIPT
libprotoc_la_LDFLAGS += -Wl,--version-script=$(srcdir)/libprotoc.map
EXTRA_libprotoc_la_DEPENDENCIES = libprotoc.map

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -751,6 +751,15 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) {
message_generators_[i]->GenerateShutdownCode(printer);
}
if (HasDescriptorMethods(file_, options_)) {
for (int i = 0; i < message_generators_.size(); i++) {
if (!IsMapEntryMessage(message_generators_[i]->descriptor_)) continue;
printer->Print(
"delete file_level_metadata[$index$].reflection;\n",
"index", SimpleItoa(i));
}
}
printer->Outdent();
printer->Print(
"}\n\n");

View file

@ -49,6 +49,8 @@ const std::string kDescriptorMetadataFile =
"GPBMetadata/Google/Protobuf/Internal/Descriptor.php";
const std::string kDescriptorDirName = "Google/Protobuf/Internal";
const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
const char* const kReservedNames[] = {"Empty", "ECHO"};
const int kReservedNamesSize = 2;
namespace google {
namespace protobuf {
@ -84,33 +86,6 @@ std::string RenameEmpty(const std::string& name) {
}
}
std::string MessagePrefix(const Descriptor* message) {
// Empty cannot be php class name.
if (message->name() == "Empty" &&
message->file()->package() == "google.protobuf") {
return "GPB";
} else {
return (message->file()->options()).php_class_prefix();
}
}
std::string MessageName(const Descriptor* message, bool is_descriptor) {
string message_name = message->name();
const Descriptor* descriptor = message->containing_type();
while (descriptor != NULL) {
message_name = descriptor->name() + '_' + message_name;
descriptor = descriptor->containing_type();
}
message_name = MessagePrefix(message) + message_name;
if (message->file()->package() == "") {
return message_name;
} else {
return PhpName(message->file()->package(), is_descriptor) + '\\' +
message_name;
}
}
std::string MessageFullName(const Descriptor* message, bool is_descriptor) {
if (is_descriptor) {
return StringReplace(message->full_name(),
@ -131,19 +106,51 @@ std::string EnumFullName(const EnumDescriptor* envm, bool is_descriptor) {
}
}
std::string EnumClassName(const EnumDescriptor* envm) {
string enum_class_name = envm->name();
const Descriptor* descriptor = envm->containing_type();
while (descriptor != NULL) {
enum_class_name = descriptor->name() + '_' + enum_class_name;
descriptor = descriptor->containing_type();
template <typename DescriptorType>
std::string ClassNamePrefix(const string& classname,
const DescriptorType* desc) {
const string& prefix = (desc->file()->options()).php_class_prefix();
if (prefix != "") {
return prefix;
}
return enum_class_name;
bool is_reserved = false;
for (int i = 0; i < kReservedNamesSize; i++) {
if (classname == kReservedNames[i]) {
is_reserved = true;
break;
}
}
if (is_reserved) {
if (desc->file()->package() == "google.protobuf") {
return "GPB";
} else {
return "PB";
}
}
return "";
}
std::string EnumName(const EnumDescriptor* envm, bool is_descriptor) {
string enum_name = EnumClassName(envm);
return PhpName(envm->file()->package(), is_descriptor) + '\\' + enum_name;
template <typename DescriptorType>
std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
string classname = desc->name();
const Descriptor* containing = desc->containing_type();
while (containing != NULL) {
classname = containing->name() + '_' + classname;
containing = containing->containing_type();
}
classname = ClassNamePrefix(classname, desc) + classname;
if (desc->file()->package() == "") {
return classname;
} else {
return PhpName(desc->file()->package(), is_descriptor) + '\\' +
classname;
}
}
std::string PhpName(const std::string& full_name, bool is_descriptor) {
@ -231,7 +238,7 @@ std::string GeneratedMetadataFileName(const std::string& proto_file,
std::string GeneratedMessageFileName(const Descriptor* message,
bool is_descriptor) {
std::string result = MessageName(message, is_descriptor);
std::string result = FullClassName(message, is_descriptor);
for (int i = 0; i < result.size(); i++) {
if (result[i] == '\\') {
result[i] = '/';
@ -242,7 +249,7 @@ std::string GeneratedMessageFileName(const Descriptor* message,
std::string GeneratedEnumFileName(const EnumDescriptor* en,
bool is_descriptor) {
std::string result = EnumName(en, is_descriptor);
std::string result = FullClassName(en, is_descriptor);
for (int i = 0; i < result.size(); i++) {
if (result[i] == '\\') {
result[i] = '/';
@ -456,12 +463,12 @@ void GenerateFieldAccessor(const FieldDescriptor* field, bool is_descriptor,
printer->Print(
", \\^class_name^);\n",
"class_name",
MessageName(value->message_type(), is_descriptor) + "::class");
FullClassName(value->message_type(), is_descriptor) + "::class");
} else if (value->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
printer->Print(
", ^class_name^);\n",
", \\^class_name^);\n",
"class_name",
EnumName(value->enum_type(), is_descriptor) + "::class");
FullClassName(value->enum_type(), is_descriptor) + "::class");
} else {
printer->Print(");\n");
}
@ -474,23 +481,23 @@ void GenerateFieldAccessor(const FieldDescriptor* field, bool is_descriptor,
printer->Print(
", \\^class_name^);\n",
"class_name",
MessageName(field->message_type(), is_descriptor) + "::class");
FullClassName(field->message_type(), is_descriptor) + "::class");
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
printer->Print(
", ^class_name^);\n",
", \\^class_name^);\n",
"class_name",
EnumName(field->enum_type(), is_descriptor) + "::class");
FullClassName(field->enum_type(), is_descriptor) + "::class");
} else {
printer->Print(");\n");
}
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
printer->Print(
"GPBUtil::checkMessage($var, \\^class_name^::class);\n",
"class_name", MessageName(field->message_type(), is_descriptor));
"class_name", FullClassName(field->message_type(), is_descriptor));
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
printer->Print(
"GPBUtil::checkEnum($var, \\^class_name^::class);\n",
"class_name", EnumName(field->enum_type(), is_descriptor));
"class_name", FullClassName(field->enum_type(), is_descriptor));
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
printer->Print(
"GPBUtil::checkString($var, ^utf8^);\n",
@ -552,7 +559,7 @@ void GenerateEnumToPool(const EnumDescriptor* en, io::Printer* printer) {
const EnumValueDescriptor* value = en->value(i);
printer->Print(
"->value(\"^name^\", ^number^)\n",
"name", value->name(),
"name", ClassNamePrefix(value->name(), en) + value->name(),
"number", IntToString(value->number()));
}
printer->Print("->finalizeToPool();\n\n");
@ -667,6 +674,12 @@ void GenerateAddFileToPool(const FileDescriptor* file, bool is_descriptor,
} else {
for (int i = 0; i < file->dependency_count(); i++) {
const std::string& name = file->dependency(i)->name();
// Currently, descriptor.proto is not ready for external usage. Skip to
// import it for now, so that its dependencies can still work as long as
// they don't use protos defined in descriptor.proto.
if (name == kDescriptorFile) {
continue;
}
std::string dependency_filename =
GeneratedMetadataFileName(name, is_descriptor);
printer->Print(
@ -678,6 +691,26 @@ void GenerateAddFileToPool(const FileDescriptor* file, bool is_descriptor,
FileDescriptorSet files;
FileDescriptorProto* file_proto = files.add_file();
file->CopyTo(file_proto);
// Filter out descriptor.proto as it cannot be depended on for now.
RepeatedPtrField<string>* dependency = file_proto->mutable_dependency();
for (RepeatedPtrField<string>::iterator it = dependency->begin();
it != dependency->end(); ++it) {
if (*it != kDescriptorFile) {
dependency->erase(it);
break;
}
}
// Filter out all extensions, since we do not support extension yet.
file_proto->clear_extension();
RepeatedPtrField<DescriptorProto>* message_type =
file_proto->mutable_message_type();
for (RepeatedPtrField<DescriptorProto>::iterator it = message_type->begin();
it != message_type->end(); ++it) {
it->clear_extension();
}
string files_data;
files.SerializeToString(&files_data);
@ -812,7 +845,7 @@ void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
const EnumValueDescriptor* value = en->value(i);
GenerateEnumValueDocComment(&printer, value);
printer.Print("const ^name^ = ^number^;\n",
"name", value->name(),
"name", ClassNamePrefix(value->name(), en) + value->name(),
"number", IntToString(value->number()));
}

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -445,8 +445,6 @@ void Generator::PrintFileDescriptor() const {
printer_->Outdent();
printer_->Print(")\n");
printer_->Print("_sym_db.RegisterFileDescriptor($name$)\n", "name",
kDescriptorKey);
printer_->Print("\n");
}
@ -999,6 +997,10 @@ void Generator::FixForeignFieldsInDescriptors() const {
for (int i = 0; i < file_->extension_count(); ++i) {
AddExtensionToFileDescriptor(*file_->extension(i));
}
// TODO(jieluo): Move this register to PrintFileDescriptor() when
// FieldDescriptor.file is added in generated file.
printer_->Print("_sym_db.RegisterFileDescriptor($name$)\n", "name",
kDescriptorKey);
printer_->Print("\n");
}

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -39,6 +39,7 @@
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
#include <assert.h>
#include <climits>
#include <string>
#include <google/protobuf/stubs/logging.h>

View file

@ -67,6 +67,13 @@ size_t MapFieldBase::SpaceUsedExcludingSelfNoLock() const {
}
}
bool MapFieldBase::IsMapValid() const {
// "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get
// executed before state_ is checked.
Atomic32 state = google::protobuf::internal::Acquire_Load(&state_);
return state != STATE_MODIFIED_REPEATED;
}
void MapFieldBase::SetMapDirty() { state_ = STATE_MODIFIED_MAP; }
void MapFieldBase::SetRepeatedDirty() { state_ = STATE_MODIFIED_REPEATED; }
@ -359,6 +366,13 @@ void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const {
GOOGLE_LOG(FATAL) << "Can't get here.";
break;
}
// Remove existing map value with same key.
Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
if (iter != map->end()) {
iter->second.DeleteData();
}
MapValueRef& map_val = (*map)[map_key];
map_val.SetType(val_des->cpp_type());
switch (val_des->cpp_type()) {

View file

@ -86,6 +86,8 @@ class LIBPROTOBUF_EXPORT MapFieldBase {
virtual bool ContainsMapKey(const MapKey& map_key) const = 0;
virtual bool InsertOrLookupMapValue(
const MapKey& map_key, MapValueRef* val) = 0;
// Insures operations after won't get executed before calling this.
bool IsMapValid() const;
virtual bool DeleteMapValue(const MapKey& map_key) = 0;
virtual bool EqualIterator(const MapIterator& a,
const MapIterator& b) const = 0;

View file

@ -975,6 +975,11 @@ static int Int(const string& value) {
class MapFieldReflectionTest : public testing::Test {
protected:
typedef FieldDescriptor FD;
int MapSize(const Reflection* reflection, const FieldDescriptor* field,
const Message& message) {
return reflection->MapSize(message, field);
}
};
TEST_F(MapFieldReflectionTest, RegularFields) {
@ -1782,6 +1787,50 @@ TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) {
// TODO(teboring): add test for duplicated key
}
TEST_F(MapFieldReflectionTest, MapSizeWithDuplicatedKey) {
// Dynamic Message
{
DynamicMessageFactory factory;
google::protobuf::scoped_ptr<Message> message(
factory.GetPrototype(unittest::TestMap::descriptor())->New());
const Reflection* reflection = message->GetReflection();
const FieldDescriptor* field =
unittest::TestMap::descriptor()->FindFieldByName("map_int32_int32");
Message* entry1 = reflection->AddMessage(message.get(), field);
Message* entry2 = reflection->AddMessage(message.get(), field);
const Reflection* entry_reflection = entry1->GetReflection();
const FieldDescriptor* key_field =
entry1->GetDescriptor()->FindFieldByName("key");
entry_reflection->SetInt32(entry1, key_field, 1);
entry_reflection->SetInt32(entry2, key_field, 1);
EXPECT_EQ(2, reflection->FieldSize(*message, field));
EXPECT_EQ(1, MapSize(reflection, field, *message));
}
// Generated Message
{
unittest::TestMap message;
const Reflection* reflection = message.GetReflection();
const FieldDescriptor* field =
message.GetDescriptor()->FindFieldByName("map_int32_int32");
Message* entry1 = reflection->AddMessage(&message, field);
Message* entry2 = reflection->AddMessage(&message, field);
const Reflection* entry_reflection = entry1->GetReflection();
const FieldDescriptor* key_field =
entry1->GetDescriptor()->FindFieldByName("key");
entry_reflection->SetInt32(entry1, key_field, 1);
entry_reflection->SetInt32(entry2, key_field, 1);
EXPECT_EQ(2, reflection->FieldSize(message, field));
EXPECT_EQ(1, MapSize(reflection, field, message));
}
}
// Generated Message Test ===========================================
TEST(GeneratedMapFieldTest, Accessors) {
@ -2689,6 +2738,69 @@ TEST_F(MapFieldInDynamicMessageTest, RecursiveMap) {
ASSERT_TRUE(to->ParseFromString(data));
}
TEST_F(MapFieldInDynamicMessageTest, MapValueReferernceValidAfterSerialize) {
google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
MapReflectionTester reflection_tester(map_descriptor_);
reflection_tester.SetMapFieldsViaMapReflection(message.get());
// Get value reference before serialization, so that we know the value is from
// map.
MapKey map_key;
MapValueRef map_val;
map_key.SetInt32Value(0);
reflection_tester.GetMapValueViaMapReflection(
message.get(), "map_int32_foreign_message", map_key, &map_val);
Message* submsg = map_val.MutableMessageValue();
// In previous implementation, calling SerializeToString will cause syncing
// from map to repeated field, which will invalidate the submsg we previously
// got.
string data;
message->SerializeToString(&data);
const Reflection* submsg_reflection = submsg->GetReflection();
const Descriptor* submsg_desc = submsg->GetDescriptor();
const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
submsg_reflection->SetInt32(submsg, submsg_field, 128);
message->SerializeToString(&data);
TestMap to;
to.ParseFromString(data);
EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
}
TEST_F(MapFieldInDynamicMessageTest, MapEntryReferernceValidAfterSerialize) {
google::protobuf::scoped_ptr<Message> message(map_prototype_->New());
MapReflectionTester reflection_tester(map_descriptor_);
reflection_tester.SetMapFieldsViaReflection(message.get());
// Get map entry before serialization, so that we know the it is from
// repeated field.
Message* map_entry = reflection_tester.GetMapEntryViaReflection(
message.get(), "map_int32_foreign_message", 0);
const Reflection* map_entry_reflection = map_entry->GetReflection();
const Descriptor* map_entry_desc = map_entry->GetDescriptor();
const FieldDescriptor* value_field = map_entry_desc->FindFieldByName("value");
Message* submsg =
map_entry_reflection->MutableMessage(map_entry, value_field);
// In previous implementation, calling SerializeToString will cause syncing
// from repeated field to map, which will invalidate the map_entry we
// previously got.
string data;
message->SerializeToString(&data);
const Reflection* submsg_reflection = submsg->GetReflection();
const Descriptor* submsg_desc = submsg->GetDescriptor();
const FieldDescriptor* submsg_field = submsg_desc->FindFieldByName("c");
submsg_reflection->SetInt32(submsg, submsg_field, 128);
message->SerializeToString(&data);
TestMap to;
to.ParseFromString(data);
EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
}
// ReflectionOps Test ===============================================
TEST(ReflectionOpsForMapFieldTest, MapSanityCheck) {
@ -2751,6 +2863,20 @@ TEST(ReflectionOpsForMapFieldTest, MapDiscardUnknownFields) {
GetUnknownFields(message).field_count());
}
TEST(ReflectionOpsForMapFieldTest, IsInitialized) {
unittest::TestRequiredMessageMap map_message;
// Add an uninitialized message.
(*map_message.mutable_map_field())[0];
EXPECT_FALSE(ReflectionOps::IsInitialized(map_message));
// Initialize uninitialized message
(*map_message.mutable_map_field())[0].set_a(0);
(*map_message.mutable_map_field())[0].set_b(0);
(*map_message.mutable_map_field())[0].set_c(0);
EXPECT_TRUE(ReflectionOps::IsInitialized(map_message));
}
// Wire Format Test =================================================
TEST(WireFormatForMapFieldTest, ParseMap) {
@ -2811,6 +2937,33 @@ TEST(WireFormatForMapFieldTest, SerializeMap) {
EXPECT_TRUE(dynamic_data == generated_data);
}
TEST(WireFormatForMapFieldTest, SerializeMapDynamicMessage) {
DynamicMessageFactory factory;
google::protobuf::scoped_ptr<Message> dynamic_message;
dynamic_message.reset(
factory.GetPrototype(unittest::TestMap::descriptor())->New());
MapReflectionTester reflection_tester(
unittest::TestMap::descriptor());
reflection_tester.SetMapFieldsViaReflection(dynamic_message.get());
reflection_tester.ExpectMapFieldsSetViaReflection(*dynamic_message);
unittest::TestMap generated_message;
MapTestUtil::SetMapFields(&generated_message);
MapTestUtil::ExpectMapFieldsSet(generated_message);
string generated_data;
string dynamic_data;
// Serialize.
generated_message.SerializeToString(&generated_data);
dynamic_message->SerializeToString(&dynamic_data);
// Because map serialization doesn't guarantee order, we just compare
// serialized size here. This is enough to tell dynamic message doesn't miss
// anything in serialization.
EXPECT_TRUE(dynamic_data.size() == generated_data.size());
}
TEST(WireFormatForMapFieldTest, MapParseHelpers) {
string data;
@ -3062,7 +3215,7 @@ TEST(ArenaTest, ParsingAndSerializingNoHeapAllocation) {
}
// Use text format parsing and serializing to test reflection api.
TEST(ArenaTest, RelfectionInTextFormat) {
TEST(ArenaTest, ReflectionInTextFormat) {
Arena arena;
string data;

View file

@ -744,6 +744,22 @@ void MapReflectionTester::SetMapFieldsViaMapReflection(
sub_foreign_message, foreign_c_, 1);
}
void MapReflectionTester::GetMapValueViaMapReflection(Message* message,
const string& field_name,
const MapKey& map_key,
MapValueRef* map_val) {
const Reflection* reflection = message->GetReflection();
EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name),
map_key, map_val));
}
Message* MapReflectionTester::GetMapEntryViaReflection(Message* message,
const string& field_name,
int index) {
const Reflection* reflection = message->GetReflection();
return reflection->MutableRepeatedMessage(message, F(field_name), index);
}
void MapReflectionTester::ClearMapFieldsViaReflection(
Message* message) {
const Reflection* reflection = message->GetReflection();

View file

@ -106,6 +106,11 @@ class MapReflectionTester {
void ExpectClearViaReflection(const Message& message);
void ExpectClearViaReflectionIterator(Message* message);
void ExpectMapEntryClearViaReflection(Message* message);
void GetMapValueViaMapReflection(Message* message,
const string& field_name,
const MapKey& map_key, MapValueRef* map_val);
Message* GetMapEntryViaReflection(Message* message, const string& field_name,
int index);
private:
const FieldDescriptor* F(const string& name);

View file

@ -154,6 +154,13 @@ class MapReflectionFriend; // scalar_map_container.h
}
namespace internal {
class ReflectionOps; // reflection_ops.h
class MapKeySorter; // wire_format.cc
class WireFormat; // wire_format.h
class MapFieldReflectionTest; // map_test.cc
}
template<typename T>
class RepeatedField; // repeated_field.h
@ -936,6 +943,10 @@ class LIBPROTOBUF_EXPORT Reflection {
template<typename T, typename Enable>
friend class MutableRepeatedFieldRef;
friend class ::google::protobuf::python::MapReflectionFriend;
friend class internal::MapFieldReflectionTest;
friend class internal::MapKeySorter;
friend class internal::WireFormat;
friend class internal::ReflectionOps;
// Special version for specialized implementations of string. We can't call
// MutableRawRepeatedField directly here because we don't have access to

View file

@ -38,6 +38,7 @@
#include <google/protobuf/reflection_ops.h>
#include <google/protobuf/descriptor.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/map_field.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/stubs/strutil.h>
@ -158,6 +159,27 @@ bool ReflectionOps::IsInitialized(const Message& message) {
const FieldDescriptor* field = fields[i];
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
if (field->is_map()) {
const FieldDescriptor* value_field = field->message_type()->field(1);
if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
MapFieldBase* map_field =
reflection->MapData(const_cast<Message*>(&message), field);
if (map_field->IsMapValid()) {
MapIterator iter(const_cast<Message*>(&message), field);
MapIterator end(const_cast<Message*>(&message), field);
for (map_field->MapBegin(&iter), map_field->MapEnd(&end);
iter != end; ++iter) {
if (!iter.GetValueRef().GetMessageValue().IsInitialized()) {
return false;
}
}
continue;
}
} else {
continue;
}
}
if (field->is_repeated()) {
int size = reflection->FieldSize(message, field);

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -133,6 +133,7 @@ void TableStruct::Shutdown() {
delete file_level_metadata[2].reflection;
_ListValue_default_instance_.Shutdown();
delete file_level_metadata[3].reflection;
delete file_level_metadata[0].reflection;
}
void TableStruct::InitDefaultsImpl() {

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -96,27 +96,27 @@ namespace internal {
// The current version, represented as a single integer to make comparison
// easier: major * 10^6 + minor * 10^3 + micro
#define GOOGLE_PROTOBUF_VERSION 3002000
#define GOOGLE_PROTOBUF_VERSION 3003000
// A suffix string for alpha, beta or rc releases. Empty for stable releases.
#define GOOGLE_PROTOBUF_VERSION_SUFFIX ""
// The minimum library version which works with the current version of the
// headers.
#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3002000
#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3003000
// The minimum header version which works with the current version of
// the library. This constant should only be used by protoc's C++ code
// generator.
static const int kMinHeaderVersionForLibrary = 3002000;
static const int kMinHeaderVersionForLibrary = 3003000;
// The minimum protoc version which works with the current version of the
// headers.
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3002000
#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3003000
// The minimum header version which works with the current version of
// protoc. This constant should only be used in VerifyVersion().
static const int kMinHeaderVersionForProtoc = 3002000;
static const int kMinHeaderVersionForProtoc = 3003000;
// Verifies that the headers and libraries are compatible. Use the macro
// below to call this.

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

View file

@ -54,9 +54,17 @@
namespace google {
const size_t kMapEntryTagByteSize = 2;
namespace protobuf {
namespace internal {
// Forward declare static functions
static size_t MapKeyDataOnlyByteSize(const FieldDescriptor* field,
const MapKey& value);
static size_t MapValueRefDataOnlyByteSize(const FieldDescriptor* field,
const MapValueRef& value);
// ===================================================================
bool UnknownFieldSetFieldSkipper::SkipField(
@ -797,7 +805,16 @@ void WireFormat::SerializeWithCachedSizes(
int expected_endpoint = output->ByteCount() + size;
std::vector<const FieldDescriptor*> fields;
message_reflection->ListFields(message, &fields);
// Fields of map entry should always be serialized.
if (descriptor->options().map_entry()) {
for (int i = 0; i < descriptor->field_count(); i++) {
fields.push_back(descriptor->field(i));
}
} else {
message_reflection->ListFields(message, &fields);
}
for (int i = 0; i < fields.size(); i++) {
SerializeFieldWithCachedSizes(fields[i], message, output);
}
@ -816,6 +833,129 @@ void WireFormat::SerializeWithCachedSizes(
"during serialization?";
}
static void SerializeMapKeyWithCachedSizes(const FieldDescriptor* field,
const MapKey& value,
io::CodedOutputStream* output) {
switch (field->type()) {
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_ENUM:
GOOGLE_LOG(FATAL) << "Unsupported";
break;
#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
case FieldDescriptor::TYPE_##FieldType: \
WireFormatLite::Write##CamelFieldType(1, value.Get##CamelCppType##Value(), \
output); \
break;
CASE_TYPE(INT64, Int64, Int64)
CASE_TYPE(UINT64, UInt64, UInt64)
CASE_TYPE(INT32, Int32, Int32)
CASE_TYPE(FIXED64, Fixed64, UInt64)
CASE_TYPE(FIXED32, Fixed32, UInt32)
CASE_TYPE(BOOL, Bool, Bool)
CASE_TYPE(UINT32, UInt32, UInt32)
CASE_TYPE(SFIXED32, SFixed32, Int32)
CASE_TYPE(SFIXED64, SFixed64, Int64)
CASE_TYPE(SINT32, SInt32, Int32)
CASE_TYPE(SINT64, SInt64, Int64)
CASE_TYPE(STRING, String, String)
#undef CASE_TYPE
}
}
static void SerializeMapValueRefWithCachedSizes(const FieldDescriptor* field,
const MapValueRef& value,
io::CodedOutputStream* output) {
switch (field->type()) {
#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
case FieldDescriptor::TYPE_##FieldType: \
WireFormatLite::Write##CamelFieldType(2, value.Get##CamelCppType##Value(), \
output); \
break;
CASE_TYPE(INT64, Int64, Int64)
CASE_TYPE(UINT64, UInt64, UInt64)
CASE_TYPE(INT32, Int32, Int32)
CASE_TYPE(FIXED64, Fixed64, UInt64)
CASE_TYPE(FIXED32, Fixed32, UInt32)
CASE_TYPE(BOOL, Bool, Bool)
CASE_TYPE(UINT32, UInt32, UInt32)
CASE_TYPE(SFIXED32, SFixed32, Int32)
CASE_TYPE(SFIXED64, SFixed64, Int64)
CASE_TYPE(SINT32, SInt32, Int32)
CASE_TYPE(SINT64, SInt64, Int64)
CASE_TYPE(ENUM, Enum, Enum)
CASE_TYPE(DOUBLE, Double, Double)
CASE_TYPE(FLOAT, Float, Float)
CASE_TYPE(STRING, String, String)
CASE_TYPE(BYTES, Bytes, String)
CASE_TYPE(MESSAGE, Message, Message)
CASE_TYPE(GROUP, Group, Message)
#undef CASE_TYPE
}
}
class MapKeySorter {
public:
static std::vector<MapKey> SortKey(const Message& message,
const Reflection* reflection,
const FieldDescriptor* field) {
std::vector<MapKey> sorted_key_list;
for (MapIterator it =
reflection->MapBegin(const_cast<Message*>(&message), field);
it != reflection->MapEnd(const_cast<Message*>(&message), field);
++it) {
sorted_key_list.push_back(it.GetKey());
}
MapKeyComparator comparator;
std::sort(sorted_key_list.begin(), sorted_key_list.end(), comparator);
return sorted_key_list;
}
private:
class MapKeyComparator {
public:
bool operator()(const MapKey& a, const MapKey& b) const {
GOOGLE_DCHECK(a.type() == b.type());
switch (a.type()) {
#define CASE_TYPE(CppType, CamelCppType) \
case FieldDescriptor::CPPTYPE_##CppType: { \
return a.Get##CamelCppType##Value() < b.Get##CamelCppType##Value(); \
}
CASE_TYPE(STRING, String)
CASE_TYPE(INT64, Int64)
CASE_TYPE(INT32, Int32)
CASE_TYPE(UINT64, UInt64)
CASE_TYPE(UINT32, UInt32)
CASE_TYPE(BOOL, Bool)
#undef CASE_TYPE
default:
GOOGLE_LOG(DFATAL) << "Invalid key for map field.";
return true;
}
}
};
};
static void SerializeMapEntry(const FieldDescriptor* field, const MapKey& key,
const MapValueRef& value,
io::CodedOutputStream* output) {
const FieldDescriptor* key_field = field->message_type()->field(0);
const FieldDescriptor* value_field = field->message_type()->field(1);
WireFormatLite::WriteTag(field->number(),
WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
size_t size = kMapEntryTagByteSize;
size += MapKeyDataOnlyByteSize(key_field, key);
size += MapValueRefDataOnlyByteSize(value_field, value);
output->WriteVarint32(size);
SerializeMapKeyWithCachedSizes(key_field, key, output);
SerializeMapValueRefWithCachedSizes(value_field, value, output);
}
void WireFormat::SerializeFieldWithCachedSizes(
const FieldDescriptor* field,
const Message& message,
@ -830,10 +970,55 @@ void WireFormat::SerializeFieldWithCachedSizes(
return;
}
// For map fields, we can use either repeated field reflection or map
// reflection. Our choice has some subtle effects. If we use repeated field
// reflection here, then the repeated field representation becomes
// authoritative for this field: any existing references that came from map
// reflection remain valid for reading, but mutations to them are lost and
// will be overwritten next time we call map reflection!
//
// So far this mainly affects Python, which keeps long-term references to map
// values around, and always uses map reflection. See: b/35918691
//
// Here we choose to use map reflection API as long as the internal
// map is valid. In this way, the serialization doesn't change map field's
// internal state and existing references that came from map reflection remain
// valid for both reading and writing.
if (field->is_map()) {
MapFieldBase* map_field =
message_reflection->MapData(const_cast<Message*>(&message), field);
if (map_field->IsMapValid()) {
if (output->IsSerializationDeterministic()) {
std::vector<MapKey> sorted_key_list =
MapKeySorter::SortKey(message, message_reflection, field);
for (std::vector<MapKey>::iterator it = sorted_key_list.begin();
it != sorted_key_list.end(); ++it) {
MapValueRef map_value;
message_reflection->InsertOrLookupMapValue(
const_cast<Message*>(&message), field, *it, &map_value);
SerializeMapEntry(field, *it, map_value, output);
}
} else {
for (MapIterator it = message_reflection->MapBegin(
const_cast<Message*>(&message), field);
it !=
message_reflection->MapEnd(const_cast<Message*>(&message), field);
++it) {
SerializeMapEntry(field, it.GetKey(), it.GetValueRef(), output);
}
}
return;
}
}
int count = 0;
if (field->is_repeated()) {
count = message_reflection->FieldSize(message, field);
} else if (field->containing_type()->options().map_entry()) {
// Map entry fields always need to be serialized.
count = 1;
} else if (message_reflection->HasField(message, field)) {
count = 1;
}
@ -984,7 +1169,16 @@ size_t WireFormat::ByteSize(const Message& message) {
size_t our_size = 0;
std::vector<const FieldDescriptor*> fields;
message_reflection->ListFields(message, &fields);
// Fields of map entry should always be serialized.
if (descriptor->options().map_entry()) {
for (int i = 0; i < descriptor->field_count(); i++) {
fields.push_back(descriptor->field(i));
}
} else {
message_reflection->ListFields(message, &fields);
}
for (int i = 0; i < fields.size(); i++) {
our_size += FieldByteSize(fields[i], message);
}
@ -1015,6 +1209,9 @@ size_t WireFormat::FieldByteSize(
size_t count = 0;
if (field->is_repeated()) {
count = FromIntSize(message_reflection->FieldSize(message, field));
} else if (field->containing_type()->options().map_entry()) {
// Map entry fields always need to be serialized.
count = 1;
} else if (message_reflection->HasField(message, field)) {
count = 1;
}
@ -1035,20 +1232,124 @@ size_t WireFormat::FieldByteSize(
return our_size;
}
static size_t MapKeyDataOnlyByteSize(const FieldDescriptor* field,
const MapKey& value) {
GOOGLE_DCHECK_EQ(FieldDescriptor::TypeToCppType(field->type()), value.type());
switch (field->type()) {
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_ENUM:
GOOGLE_LOG(FATAL) << "Unsupported";
return 0;
#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
case FieldDescriptor::TYPE_##FieldType: \
return WireFormatLite::CamelFieldType##Size( \
value.Get##CamelCppType##Value());
#define FIXED_CASE_TYPE(FieldType, CamelFieldType) \
case FieldDescriptor::TYPE_##FieldType: \
return WireFormatLite::k##CamelFieldType##Size;
CASE_TYPE(INT32, Int32, Int32);
CASE_TYPE(INT64, Int64, Int64);
CASE_TYPE(UINT32, UInt32, UInt32);
CASE_TYPE(UINT64, UInt64, UInt64);
CASE_TYPE(SINT32, SInt32, Int32);
CASE_TYPE(SINT64, SInt64, Int64);
CASE_TYPE(STRING, String, String);
FIXED_CASE_TYPE(FIXED32, Fixed32);
FIXED_CASE_TYPE(FIXED64, Fixed64);
FIXED_CASE_TYPE(SFIXED32, SFixed32);
FIXED_CASE_TYPE(SFIXED64, SFixed64);
FIXED_CASE_TYPE(BOOL, Bool);
#undef CASE_TYPE
#undef FIXED_CASE_TYPE
}
GOOGLE_LOG(FATAL) << "Cannot get here";
return 0;
}
static size_t MapValueRefDataOnlyByteSize(const FieldDescriptor* field,
const MapValueRef& value) {
switch (field->type()) {
case FieldDescriptor::TYPE_GROUP:
GOOGLE_LOG(FATAL) << "Unsupported";
return 0;
#define CASE_TYPE(FieldType, CamelFieldType, CamelCppType) \
case FieldDescriptor::TYPE_##FieldType: \
return WireFormatLite::CamelFieldType##Size( \
value.Get##CamelCppType##Value());
#define FIXED_CASE_TYPE(FieldType, CamelFieldType) \
case FieldDescriptor::TYPE_##FieldType: \
return WireFormatLite::k##CamelFieldType##Size;
CASE_TYPE(INT32, Int32, Int32);
CASE_TYPE(INT64, Int64, Int64);
CASE_TYPE(UINT32, UInt32, UInt32);
CASE_TYPE(UINT64, UInt64, UInt64);
CASE_TYPE(SINT32, SInt32, Int32);
CASE_TYPE(SINT64, SInt64, Int64);
CASE_TYPE(STRING, String, String);
CASE_TYPE(BYTES, Bytes, String);
CASE_TYPE(ENUM, Enum, Enum);
CASE_TYPE(MESSAGE, Message, Message);
FIXED_CASE_TYPE(FIXED32, Fixed32);
FIXED_CASE_TYPE(FIXED64, Fixed64);
FIXED_CASE_TYPE(SFIXED32, SFixed32);
FIXED_CASE_TYPE(SFIXED64, SFixed64);
FIXED_CASE_TYPE(DOUBLE, Double);
FIXED_CASE_TYPE(FLOAT, Float);
FIXED_CASE_TYPE(BOOL, Bool);
#undef CASE_TYPE
#undef FIXED_CASE_TYPE
}
GOOGLE_LOG(FATAL) << "Cannot get here";
return 0;
}
size_t WireFormat::FieldDataOnlyByteSize(
const FieldDescriptor* field,
const Message& message) {
const Reflection* message_reflection = message.GetReflection();
size_t data_size = 0;
if (field->is_map()) {
MapFieldBase* map_field =
message_reflection->MapData(const_cast<Message*>(&message), field);
if (map_field->IsMapValid()) {
MapIterator iter(const_cast<Message*>(&message), field);
MapIterator end(const_cast<Message*>(&message), field);
const FieldDescriptor* key_field = field->message_type()->field(0);
const FieldDescriptor* value_field = field->message_type()->field(1);
for (map_field->MapBegin(&iter), map_field->MapEnd(&end); iter != end;
++iter) {
size_t size = kMapEntryTagByteSize;
size += MapKeyDataOnlyByteSize(key_field, iter.GetKey());
size += MapValueRefDataOnlyByteSize(value_field, iter.GetValueRef());
data_size += WireFormatLite::LengthDelimitedSize(size);
}
return data_size;
}
}
size_t count = 0;
if (field->is_repeated()) {
count =
internal::FromIntSize(message_reflection->FieldSize(message, field));
} else if (field->containing_type()->options().map_entry()) {
// Map entry fields always need to be serialized.
count = 1;
} else if (message_reflection->HasField(message, field)) {
count = 1;
}
size_t data_size = 0;
switch (field->type()) {
#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \
case FieldDescriptor::TYPE_##TYPE: \

View file

@ -8,12 +8,12 @@
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 3002000
#if GOOGLE_PROTOBUF_VERSION < 3003000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 3002000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#if 3003000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.

126
tests.sh
View file

@ -362,6 +362,7 @@ generate_php_test_proto() {
../../src/protoc --php_out=generated proto/test.proto proto/test_include.proto proto/test_no_namespace.proto proto/test_prefix.proto
pushd ../../src
./protoc --php_out=../php/tests/generated google/protobuf/empty.proto
./protoc --php_out=../php/tests/generated -I../php/tests -I. ../php/tests/proto/test_import_descriptor_proto.proto
popd
popd
}
@ -371,12 +372,9 @@ use_php() {
PHP=`which php`
PHP_CONFIG=`which php-config`
PHPIZE=`which phpize`
rm $PHP
rm $PHP_CONFIG
rm $PHPIZE
cp "/usr/bin/php$VERSION" $PHP
cp "/usr/bin/php-config$VERSION" $PHP_CONFIG
cp "/usr/bin/phpize$VERSION" $PHPIZE
ln -sfn "/usr/local/php-${VERSION}/bin/php" $PHP
ln -sfn "/usr/local/php-${VERSION}/bin/php-config" $PHP_CONFIG
ln -sfn "/usr/local/php-${VERSION}/bin/phpize" $PHPIZE
generate_php_test_proto
}
@ -403,18 +401,13 @@ use_php_bc() {
}
build_php5.5() {
PHP=`which php`
PHP_CONFIG=`which php-config`
PHPIZE=`which phpize`
ln -sfn "/usr/local/php-5.5/bin/php" $PHP
ln -sfn "/usr/local/php-5.5/bin/php-config" $PHP_CONFIG
ln -sfn "/usr/local/php-5.5/bin/phpize" $PHPIZE
generate_php_test_proto
use_php 5.5
pushd php
rm -rf vendor
cp -r /usr/local/vendor-5.5 vendor
./vendor/bin/phpunit
wget https://phar.phpunit.de/phpunit-4.8.0.phar -O /usr/bin/phpunit
phpunit
popd
pushd conformance
# TODO(teboring): Add it back
@ -423,51 +416,21 @@ build_php5.5() {
}
build_php5.5_c() {
PHP=`which php`
PHP_CONFIG=`which php-config`
PHPIZE=`which phpize`
ln -sfn "/usr/local/php-5.5/bin/php" $PHP
ln -sfn "/usr/local/php-5.5/bin/php-config" $PHP_CONFIG
ln -sfn "/usr/local/php-5.5/bin/phpize" $PHPIZE
generate_php_test_proto
wget https://phar.phpunit.de/phpunit-old.phar -O /usr/bin/phpunit
use_php 5.5
wget https://phar.phpunit.de/phpunit-4.8.0.phar -O /usr/bin/phpunit
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
make test_php_c
# make test_php_c
popd
}
build_php5.5_zts_c() {
use_php_zts 5.5
wget https://phar.phpunit.de/phpunit-old.phar -O /usr/bin/phpunit
wget https://phar.phpunit.de/phpunit-4.8.0.phar -O /usr/bin/phpunit
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
make test_php_c
popd
}
build_php5.5_32() {
use_php_bc 5.5
pushd php
rm -rf vendor
cp -r /usr/local/vendor-5.5 vendor
./vendor/bin/phpunit
popd
# TODO(teboring): Add conformance test.
# pushd conformance
# make test_php
# popd
}
build_php5.5_c_32() {
use_php_bc 5.5
wget https://phar.phpunit.de/phpunit-old.phar -O /usr/bin/phpunit
cd php/tests && /bin/bash ./test.sh && cd ../..
# TODO(teboring): Add conformance test.
# pushd conformance
# make test_php_c
# popd
popd
}
build_php5.6() {
@ -475,7 +438,8 @@ build_php5.6() {
pushd php
rm -rf vendor
cp -r /usr/local/vendor-5.6 vendor
./vendor/bin/phpunit
wget https://phar.phpunit.de/phpunit-5.7.0.phar -O /usr/bin/phpunit
phpunit
popd
pushd conformance
# TODO(teboring): Add it back
@ -485,9 +449,19 @@ build_php5.6() {
build_php5.6_c() {
use_php 5.6
wget https://phar.phpunit.de/phpunit-5.7.0.phar -O /usr/bin/phpunit
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
make test_php_c
# make test_php_c
popd
}
build_php5.6_zts_c() {
use_php_zts 5.6
wget https://phar.phpunit.de/phpunit-5.7.0.phar -O /usr/bin/phpunit
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
# make test_php_c
popd
}
@ -511,7 +485,7 @@ build_php5.6_mac() {
# Test
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
make test_php_c
# make test_php_c
popd
}
@ -520,7 +494,8 @@ build_php7.0() {
pushd php
rm -rf vendor
cp -r /usr/local/vendor-7.0 vendor
./vendor/bin/phpunit
wget https://phar.phpunit.de/phpunit-5.6.0.phar -O /usr/bin/phpunit
phpunit
popd
pushd conformance
# TODO(teboring): Add it back
@ -530,9 +505,43 @@ build_php7.0() {
build_php7.0_c() {
use_php 7.0
wget https://phar.phpunit.de/phpunit-5.6.0.phar -O /usr/bin/phpunit
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
make test_php_c
# make test_php_c
popd
}
build_php7.0_zts_c() {
use_php_zts 7.0
wget https://phar.phpunit.de/phpunit-5.6.0.phar -O /usr/bin/phpunit
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
# make test_php_c
popd
}
build_php7.0_mac() {
generate_php_test_proto
# Install PHP
curl -s https://php-osx.liip.ch/install.sh | bash -s 7.0
PHP_FOLDER=`find /usr/local -type d -name "php7-7.0*"` # The folder name may change upon time
export PATH="$PHP_FOLDER/bin:$PATH"
# Install phpunit
curl https://phar.phpunit.de/phpunit-5.6.0.phar -L -o phpunit.phar
chmod +x phpunit.phar
sudo mv phpunit.phar /usr/local/bin/phpunit
# Install valgrind
echo "#! /bin/bash" > valgrind
chmod ug+x valgrind
sudo mv valgrind /usr/local/bin/valgrind
# Test
cd php/tests && /bin/bash ./test.sh && cd ../..
pushd conformance
# make test_php_c
popd
}
@ -542,13 +551,10 @@ build_php_all() {
build_php7.0
build_php5.5_c
build_php5.6_c
# build_php7.0_c
build_php7.0_c
build_php5.5_zts_c
}
build_php_all_32() {
build_php5.5_32
build_php5.5_c_32
build_php5.6_zts_c
build_php7.0_zts_c
}
# Note: travis currently does not support testing more than one language so the