Merge branch 'master' into down-integrate-with-msvc-fix

pull/2386/head
Adam Cozzette 8 years ago
commit 5d63097fc2
  1. 8
      BUILD
  2. 3
      Makefile.am
  3. 2
      cmake/extract_includes.bat.in
  4. 3
      composer.json
  5. 8
      conformance/failure_list_csharp.txt
  6. 12
      csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs
  7. 2
      csharp/src/Google.Protobuf.Test/project.json
  8. 2
      csharp/src/Google.Protobuf/InvalidProtocolBufferException.cs
  9. 84
      csharp/src/Google.Protobuf/JsonFormatter.cs
  10. 2
      csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs
  11. 10
      csharp/src/Google.Protobuf/WellKnownTypes/FieldMaskPartial.cs
  12. 1
      docs/third_party.md
  13. 2
      java/compatibility_tests/v2.5.0/protos/pom.xml
  14. 29
      java/core/pom.xml
  15. 50
      java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
  16. 2
      java/core/src/main/java/com/google/protobuf/MapFieldLite.java
  17. 32
      java/lite/pom.xml
  18. 2
      java/pom.xml
  19. 18
      java/util/pom.xml
  20. 4
      javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
  21. 2
      javanano/src/main/java/com/google/protobuf/nano/InvalidProtocolBufferNanoException.java
  22. 2
      jenkins/buildcmds/pull_request_32.sh
  23. 1
      jenkins/docker/Dockerfile
  24. 5
      jenkins/docker32/Dockerfile
  25. 37
      js/binary/decoder.js
  26. 23
      js/binary/decoder_test.js
  27. 21
      js/binary/encoder.js
  28. 2
      js/package.json
  29. 21
      objectivec/GPBCodedInputStream.h
  30. 8
      objectivec/GPBCodedInputStream.m
  31. 9
      objectivec/GPBMessage.h
  32. 2
      objectivec/README.md
  33. 127
      php/ext/google/protobuf/array.c
  34. 43
      php/ext/google/protobuf/def.c
  35. 4
      php/ext/google/protobuf/message.c
  36. 1
      php/ext/google/protobuf/protobuf.c
  37. 19
      php/ext/google/protobuf/protobuf.h
  38. 24
      php/ext/google/protobuf/storage.c
  39. 139
      php/ext/google/protobuf/type_check.c
  40. 37
      php/src/Google/Protobuf/Internal/GPBUtil.php
  41. 47
      php/src/Google/Protobuf/Internal/GPBWire.php
  42. 64
      php/src/Google/Protobuf/Internal/InputStream.php
  43. 15
      php/src/Google/Protobuf/Internal/Message.php
  44. 49
      php/src/Google/Protobuf/Internal/OutputStream.php
  45. 175
      php/src/Google/Protobuf/Internal/Type.php
  46. 19
      php/src/Google/Protobuf/descriptor.php
  47. 116
      php/tests/array_test.php
  48. 60
      php/tests/generated_class_test.php
  49. 28
      php/tests/google/protobuf/empty.pb.php
  50. 52
      php/tests/map_field_test.php
  51. 148
      php/tests/php_implementation_test.php
  52. 5
      php/tests/test.sh
  53. 38
      php/tests/test_base.php
  54. 34
      php/tests/test_no_namespace.pb.php
  55. 5
      php/tests/test_no_namespace.proto
  56. 119
      php/tests/test_util.php
  57. 13
      php/tests/well_known_test.php
  58. 1
      phpunit.xml
  59. 24
      protobuf.bzl
  60. 2
      python/README.md
  61. 4
      python/google/protobuf/pyext/message.cc
  62. 44
      ruby/ext/google/protobuf_c/message.c
  63. 10
      ruby/tests/basic.rb
  64. 2
      ruby/travis-test.sh
  65. 2
      src/Makefile.am
  66. 1
      src/google/protobuf/arena.h
  67. 47
      src/google/protobuf/compiler/command_line_interface.cc
  68. 25
      src/google/protobuf/compiler/command_line_interface.h
  69. 38
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  70. 8
      src/google/protobuf/compiler/mock_code_generator.cc
  71. 18
      src/google/protobuf/compiler/php/php_generator.cc
  72. 3
      src/google/protobuf/repeated_field.h
  73. 10
      src/google/protobuf/stubs/atomicops.h
  74. 6
      src/google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h
  75. 10
      src/google/protobuf/stubs/atomicops_internals_generic_gcc.h
  76. 4
      src/google/protobuf/stubs/platform_macros.h
  77. 10
      src/google/protobuf/stubs/type_traits.h
  78. 8
      src/google/protobuf/util/internal/constants.h
  79. 8
      src/google/protobuf/util/internal/protostream_objectsource.cc
  80. 8
      src/google/protobuf/util/internal/protostream_objectwriter.cc
  81. 19
      src/google/protobuf/util/internal/utility.cc
  82. 31
      tests.sh

@ -577,7 +577,7 @@ py_library(
)
cc_binary(
name = "internal/_api_implementation.so",
name = "python/google/protobuf/internal/_api_implementation.so",
srcs = ["python/google/protobuf/internal/api_implementation.cc"],
copts = COPTS + [
"-DPYTHON_PROTO2_CPP_IMPL_V2",
@ -591,7 +591,7 @@ cc_binary(
)
cc_binary(
name = "pyext/_message.so",
name = "python/google/protobuf/pyext/_message.so",
srcs = glob([
"python/google/protobuf/pyext/*.cc",
"python/google/protobuf/pyext/*.h",
@ -653,8 +653,8 @@ py_proto_library(
data = select({
"//conditions:default": [],
":use_fast_cpp_protos": [
":internal/_api_implementation.so",
":pyext/_message.so",
":python/google/protobuf/internal/_api_implementation.so",
":python/google/protobuf/pyext/_message.so",
],
}),
default_runtime = "",

@ -577,7 +577,6 @@ php_EXTRA_DIST= \
php/src/Google/Protobuf/Internal/DescriptorPool.php \
php/src/Google/Protobuf/Internal/OneofField.php \
php/src/Google/Protobuf/Internal/MapEntry.php \
php/src/Google/Protobuf/Internal/Type.php \
php/src/Google/Protobuf/Internal/InputStream.php \
php/src/Google/Protobuf/Internal/OutputStream.php \
php/src/Google/Protobuf/Internal/MessageBuilderContext.php \
@ -600,6 +599,8 @@ php_EXTRA_DIST= \
php/tests/test_include.pb.php \
php/tests/map_field_test.php \
php/tests/test_base.php \
php/tests/test_no_namespace.proto \
php/tests/test_no_namespace.pb.php \
php/tests/test_util.php \
php/tests/test.proto \
php/tests/test.pb.php \

@ -80,10 +80,10 @@ copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_intern
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_gcc.h include\google\protobuf\stubs\atomicops_internals_arm_gcc.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_arm_qnx.h include\google\protobuf\stubs\atomicops_internals_arm_qnx.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_atomicword_compat.h include\google\protobuf\stubs\atomicops_internals_atomicword_compat.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_generic_c11_atomic.h include\google\protobuf\stubs\atomicops_internals_generic_c11_atomic.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_generic_gcc.h include\google\protobuf\stubs\atomicops_internals_generic_gcc.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_macosx.h include\google\protobuf\stubs\atomicops_internals_macosx.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_mips_gcc.h include\google\protobuf\stubs\atomicops_internals_mips_gcc.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_pnacl.h include\google\protobuf\stubs\atomicops_internals_pnacl.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_power.h include\google\protobuf\stubs\atomicops_internals_power.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_ppc_gcc.h include\google\protobuf\stubs\atomicops_internals_ppc_gcc.h
copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\stubs\atomicops_internals_solaris.h include\google\protobuf\stubs\atomicops_internals_solaris.h

@ -17,8 +17,7 @@
},
"files": [
"php/src/Google/Protobuf/descriptor.php",
"php/src/Google/Protobuf/descriptor_internal.pb.php",
"php/src/Google/Protobuf/Internal/Type.php"
"php/src/Google/Protobuf/descriptor_internal.pb.php"
]
}
}

@ -1,6 +1,6 @@
Recommended.JsonInput.FieldNameWithDoubleUnderscores.JsonOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.ProtobufOutput
Recommended.JsonInput.FieldNameWithDoubleUnderscores.Validator
Required.JsonInput.FieldNameInLowerCamelCase.Validator
Required.JsonInput.FieldNameInSnakeCase.JsonOutput
Required.JsonInput.FieldNameWithMixedCases.JsonOutput
Required.JsonInput.FieldNameWithMixedCases.ProtobufOutput
Required.JsonInput.FieldNameWithMixedCases.Validator
Required.JsonInput.OriginalProtoFieldName.JsonOutput
Required.JsonInput.FieldNameInSnakeCase.ProtobufOutput

@ -229,16 +229,16 @@ namespace Google.Protobuf
[Test]
[TestCase("foo_bar", "fooBar")]
[TestCase("bananaBanana", "bananaBanana")]
[TestCase("BANANABanana", "bananaBanana")]
[TestCase("BANANABanana", "BANANABanana")]
[TestCase("simple", "simple")]
[TestCase("ACTION_AND_ADVENTURE", "actionAndAdventure")]
[TestCase("ACTION_AND_ADVENTURE", "ACTIONANDADVENTURE")]
[TestCase("action_and_adventure", "actionAndAdventure")]
[TestCase("kFoo", "kFoo")]
[TestCase("HTTPServer", "httpServer")]
[TestCase("CLIENT", "client")]
public void ToCamelCase(string original, string expected)
[TestCase("HTTPServer", "HTTPServer")]
[TestCase("CLIENT", "CLIENT")]
public void ToJsonName(string original, string expected)
{
Assert.AreEqual(expected, JsonFormatter.ToCamelCase(original));
Assert.AreEqual(expected, JsonFormatter.ToJsonName(original));
}
[Test]

@ -21,7 +21,7 @@
"dependencies": {
"Google.Protobuf": { "target": "project" },
"NUnit": "3.4.0",
"dotnet-test-nunit": "3.4.0-alpha-2",
"dotnet-test-nunit": "3.4.0-alpha-2"
},
"testRunner": "nunit",

@ -61,7 +61,7 @@ namespace Google.Protobuf
{
return new InvalidProtocolBufferException(
"While parsing a protocol message, the input ended unexpectedly " +
"in the middle of a field. This could mean either than the " +
"in the middle of a field. This could mean either that the " +
"input has been truncated or that an embedded message " +
"misreported its own length.");
}

@ -248,87 +248,25 @@ namespace Google.Protobuf
return !first;
}
/// <summary>
/// Camel-case converter with added strictness for field mask formatting.
/// </summary>
/// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
private static string ToCamelCaseForFieldMask(string input)
{
for (int i = 0; i < input.Length; i++)
{
char c = input[i];
if (c >= 'A' && c <= 'Z')
{
throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
}
if (c == '_' && i < input.Length - 1)
{
char next = input[i + 1];
if (next < 'a' || next > 'z')
{
throw new InvalidOperationException($"Invalid field mask to be converted to JSON: {input}");
}
}
}
return ToCamelCase(input);
}
// Converted from src/google/protobuf/util/internal/utility.cc ToCamelCase
internal static string ToCamelCase(string input)
{
bool capitalizeNext = false;
bool wasCap = true;
bool isCap = false;
bool firstWord = true;
StringBuilder result = new StringBuilder(input.Length);
for (int i = 0; i < input.Length; i++, wasCap = isCap)
{
isCap = char.IsUpper(input[i]);
if (input[i] == '_')
// Converted from java/core/src/main/java/com/google/protobuf/Descriptors.java
internal static string ToJsonName(string name)
{
capitalizeNext = true;
if (result.Length != 0)
StringBuilder result = new StringBuilder(name.Length);
bool isNextUpperCase = false;
foreach (char ch in name)
{
firstWord = false;
}
continue;
}
else if (firstWord)
{
// Consider when the current character B is capitalized,
// first word ends when:
// 1) following a lowercase: "...aB..."
// 2) followed by a lowercase: "...ABc..."
if (result.Length != 0 && isCap &&
(!wasCap || (i + 1 < input.Length && char.IsLower(input[i + 1]))))
{
firstWord = false;
result.Append(input[i]);
}
else
{
result.Append(char.ToLowerInvariant(input[i]));
continue;
}
}
else if (capitalizeNext)
{
capitalizeNext = false;
if (char.IsLower(input[i]))
if (ch == '_')
{
result.Append(char.ToUpperInvariant(input[i]));
continue;
isNextUpperCase = true;
}
else
else if (isNextUpperCase)
{
result.Append(input[i]);
continue;
}
result.Append(char.ToUpperInvariant(ch));
isNextUpperCase = false;
}
else
{
result.Append(char.ToLowerInvariant(input[i]));
result.Append(ch);
}
}
return result.ToString();

@ -97,7 +97,7 @@ namespace Google.Protobuf.Reflection
// We could trust the generated code and check whether the type of the property is
// a MapField, but that feels a tad nasty.
this.propertyName = propertyName;
JsonName = Proto.JsonName == "" ? JsonFormatter.ToCamelCase(Proto.Name) : Proto.JsonName;
JsonName = Proto.JsonName == "" ? JsonFormatter.ToJsonName(Proto.Name) : Proto.JsonName;
}

@ -52,7 +52,7 @@ namespace Google.Protobuf.WellKnownTypes
/// </remarks>
/// <param name="paths">Paths in the field mask</param>
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
/// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
/// <exception cref="InvalidOperationException">The represented field mask is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
internal static string ToJson(IList<string> paths, bool diagnosticOnly)
{
var firstInvalid = paths.FirstOrDefault(p => !ValidatePath(p));
@ -60,10 +60,10 @@ namespace Google.Protobuf.WellKnownTypes
{
var writer = new StringWriter();
#if DOTNET35
var query = paths.Select(JsonFormatter.ToCamelCase);
var query = paths.Select(JsonFormatter.ToJsonName);
JsonFormatter.WriteString(writer, string.Join(",", query.ToArray()));
#else
JsonFormatter.WriteString(writer, string.Join(",", paths.Select(JsonFormatter.ToCamelCase)));
JsonFormatter.WriteString(writer, string.Join(",", paths.Select(JsonFormatter.ToJsonName)));
#endif
return writer.ToString();
}
@ -85,9 +85,9 @@ namespace Google.Protobuf.WellKnownTypes
}
/// <summary>
/// Camel-case converter with added strictness for field mask formatting.
/// Checks whether the given path is valid for a field mask.
/// </summary>
/// <exception cref="InvalidOperationException">The field mask is invalid for JSON representation</exception>
/// <returns>true if the path is valid; false otherwise</returns>
private static bool ValidatePath(string input)
{
for (int i = 0; i < input.Length; i++)

@ -83,6 +83,7 @@ These are projects we know about implementing Protocol Buffers for other program
* Scala: https://github.com/SandroGrzicic/ScalaBuff
* Scala: http://trueaccord.github.io/ScalaPB/
* Swift: https://github.com/alexeyxo/protobuf-swift
* Swift: https://github.com/apple/swift-protobuf/
* Vala: https://launchpad.net/protobuf-vala
* Visual Basic: http://code.google.com/p/protobuf-net/

@ -28,7 +28,7 @@
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<version>3.6.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>

@ -92,11 +92,34 @@
<!-- Add the generated sources to the build -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-generated-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${generated.sources.dir}</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-generated-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory>
<generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
<sources>
<source>${generated.testsources.dir}</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<!-- OSGI bundle configuration -->

@ -33,11 +33,12 @@ package com.google.protobuf;
import static java.lang.Math.max;
import static java.lang.Math.min;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
/**
* Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s.
@ -74,6 +75,12 @@ final class ByteBufferWriter {
private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
new ThreadLocal<SoftReference<byte[]>>();
/**
* This is a hack for GAE, where {@code FileOutputStream} is unavailable.
*/
private static final Class<?> FILE_OUTPUT_STREAM_CLASS = safeGetClass("java.io.FileOutputStream");
private static final long CHANNEL_FIELD_OFFSET = getChannelFieldOffset(FILE_OUTPUT_STREAM_CLASS);
/**
* For testing purposes only. Clears the cached buffer to force a new allocation on the next
* invocation.
@ -93,10 +100,7 @@ final class ByteBufferWriter {
// Optimized write for array-backed buffers.
// Note that we're taking the risk that a malicious OutputStream could modify the array.
output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
} else if (output instanceof FileOutputStream) {
// Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
((FileOutputStream) output).getChannel().write(buffer);
} else {
} else if (!writeToChannel(buffer, output)){
// Read all of the data from the buffer to an array.
// TODO(nathanmittler): Consider performance improvements for other "known" stream types.
final byte[] array = getOrCreateBuffer(buffer.remaining());
@ -142,4 +146,40 @@ final class ByteBufferWriter {
private static void setBuffer(byte[] value) {
BUFFER.set(new SoftReference<byte[]>(value));
}
private static boolean writeToChannel(ByteBuffer buffer, OutputStream output) throws IOException {
if (CHANNEL_FIELD_OFFSET >= 0 && FILE_OUTPUT_STREAM_CLASS.isInstance(output)) {
// Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
WritableByteChannel channel = null;
try {
channel = (WritableByteChannel) UnsafeUtil.getObject(output, CHANNEL_FIELD_OFFSET);
} catch (ClassCastException e) {
// Absorb.
}
if (channel != null) {
channel.write(buffer);
return true;
}
}
return false;
}
private static Class<?> safeGetClass(String className) {
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
return null;
}
}
private static long getChannelFieldOffset(Class<?> clazz) {
try {
if (clazz != null && UnsafeUtil.hasUnsafeArrayOperations()) {
Field field = clazz.getDeclaredField("channel");
return UnsafeUtil.objectFieldOffset(field);
}
} catch (Throwable e) {
// Absorb
}
return -1;
}
}

@ -58,7 +58,7 @@ public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
}
@SuppressWarnings({"rawtypes", "unchecked"})
private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite(Collections.emptyMap());
private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite();
static {
EMPTY_MAP_FIELD.makeImmutable();
}

@ -75,11 +75,39 @@
</plugin>
<!-- Only compile a subset of the files -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-generated-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${generated.sources.lite.dir}</source>
</sources>
</configuration>
</execution>
<execution>
<id>add-generated-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<sources>
<source>${generated.testsources.lite.dir}</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<generatedSourcesDirectory>${generated.sources.lite.dir}</generatedSourcesDirectory>
<generatedTestSourcesDirectory>${generated.testsources.lite.dir}</generatedTestSourcesDirectory>
<includes>
<include>**/AbstractMessageLite.java</include>
<include>**/AbstractParser.java</include>

@ -94,7 +94,7 @@
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<version>3.6.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>

@ -79,12 +79,24 @@
</executions>
</plugin>
<!-- Add the generated test sources to the build -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-generated-test-sources</id>
<phase>generate-test-sources</phase>
<goals>
<goal>add-test-source</goal>
</goals>
<configuration>
<!-- Add the generated test sources to the build -->
<generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory>
<sources>
<source>${generated.testsources.dir}</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
<!-- Configure the OSGI bundle -->

@ -67,8 +67,8 @@ public final class InternalNano {
public static final int TYPE_SINT32 = 17;
public static final int TYPE_SINT64 = 18;
protected static final Charset UTF_8 = Charset.forName("UTF-8");
protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
static final Charset UTF_8 = Charset.forName("UTF-8");
static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
private InternalNano() {}

@ -48,7 +48,7 @@ public class InvalidProtocolBufferNanoException extends IOException {
static InvalidProtocolBufferNanoException truncatedMessage() {
return new InvalidProtocolBufferNanoException(
"While parsing a protocol message, the input ended unexpectedly " +
"in the middle of a field. This could mean either than the " +
"in the middle of a field. This could mean either that the " +
"input has been truncated or that an embedded message " +
"misreported its own length.");
}

@ -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"
export TEST_SET="php_all_32"
./jenkins/build_and_run_docker.sh

@ -113,6 +113,7 @@ ENV MVN mvn --batch-mode
RUN cd /tmp && \
git clone https://github.com/google/protobuf.git && \
cd protobuf && \
git reset bf379715c93b581eeb078cec1f0dd8a7d79df431 && \
./autogen.sh && \
./configure && \
make -j6 && \

@ -64,6 +64,7 @@ RUN php -r "unlink('composer-setup.php');"
RUN cd /tmp && \
git clone https://github.com/google/protobuf.git && \
cd protobuf && \
git reset 734930f9197b7bc97c3c794c7a949fee2a08c280 && \
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 && \
@ -83,7 +84,9 @@ 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 && make install && make clean && cd ..
RUN cd php-5.5.38 && ./configure --enable-bcmath --prefix=/usr/local/php-5.5-bc && \
make && make install && make clean && cd ..
##################
# Python dependencies

@ -941,11 +941,9 @@ jspb.BinaryDecoder.prototype.readEnum = function() {
/**
* Reads and parses a UTF-8 encoded unicode string from the stream.
* The code is inspired by maps.vectortown.parse.StreamedDataViewReader, with
* the exception that the implementation here does not get confused if it
* encounters characters longer than three bytes. These characters are ignored
* though, as they are extremely rare: three UTF-8 bytes cover virtually all
* characters in common use (http://en.wikipedia.org/wiki/UTF-8).
* The code is inspired by maps.vectortown.parse.StreamedDataViewReader.
* Supports codepoints from U+0000 up to U+10FFFF.
* (http://en.wikipedia.org/wiki/UTF-8).
* @param {number} length The length of the string to read.
* @return {string} The decoded string.
*/
@ -953,30 +951,45 @@ jspb.BinaryDecoder.prototype.readString = function(length) {
var bytes = this.bytes_;
var cursor = this.cursor_;
var end = cursor + length;
var chars = [];
var codeUnits = [];
while (cursor < end) {
var c = bytes[cursor++];
if (c < 128) { // Regular 7-bit ASCII.
chars.push(c);
codeUnits.push(c);
} else if (c < 192) {
// UTF-8 continuation mark. We are out of sync. This
// might happen if we attempted to read a character
// with more than three bytes.
// with more than four bytes.
continue;
} else if (c < 224) { // UTF-8 with two bytes.
var c2 = bytes[cursor++];
chars.push(((c & 31) << 6) | (c2 & 63));
codeUnits.push(((c & 31) << 6) | (c2 & 63));
} else if (c < 240) { // UTF-8 with three bytes.
var c2 = bytes[cursor++];
var c3 = bytes[cursor++];
chars.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
codeUnits.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
} else if (c < 248) { // UTF-8 with 4 bytes.
var c2 = bytes[cursor++];
var c3 = bytes[cursor++];
var c4 = bytes[cursor++];
// Characters written on 4 bytes have 21 bits for a codepoint.
// We can't fit that on 16bit characters, so we use surrogates.
var codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63);
// Surrogates formula from wikipedia.
// 1. Subtract 0x10000 from codepoint
codepoint -= 0x10000;
// 2. Split this into the high 10-bit value and the low 10-bit value
// 3. Add 0xD800 to the high value to form the high surrogate
// 4. Add 0xDC00 to the low value to form the low surrogate:
var low = (codepoint & 1023) + 0xDC00;
var high = ((codepoint >> 10) & 1023) + 0xD800;
codeUnits.push(high, low)
}
}
// String.fromCharCode.apply is faster than manually appending characters on
// Chrome 25+, and generates no additional cons string garbage.
var result = String.fromCharCode.apply(null, chars);
var result = String.fromCharCode.apply(null, codeUnits);
this.cursor_ = cursor;
return result;
};

@ -210,6 +210,29 @@ describe('binaryDecoderTest', function() {
assertEquals(hashD, decoder.readFixedHash64());
});
/**
* Test encoding and decoding utf-8.
*/
it('testUtf8', function() {
var encoder = new jspb.BinaryEncoder();
var ascii = "ASCII should work in 3, 2, 1..."
var utf8_two_bytes = "©";
var utf8_three_bytes = "❄";
var utf8_four_bytes = "😁";
encoder.writeString(ascii);
encoder.writeString(utf8_two_bytes);
encoder.writeString(utf8_three_bytes);
encoder.writeString(utf8_four_bytes);
var decoder = jspb.BinaryDecoder.alloc(encoder.end());
assertEquals(ascii, decoder.readString(ascii.length));
assertEquals(utf8_two_bytes, decoder.readString(utf8_two_bytes.length));
assertEquals(utf8_three_bytes, decoder.readString(utf8_three_bytes.length));
assertEquals(utf8_four_bytes, decoder.readString(utf8_four_bytes.length));
});
/**
* Verifies that misuse of the decoder class triggers assertions.

@ -453,20 +453,37 @@ jspb.BinaryEncoder.prototype.writeFixedHash64 = function(hash) {
jspb.BinaryEncoder.prototype.writeString = function(value) {
var oldLength = this.buffer_.length;
// UTF16 to UTF8 conversion loop swiped from goog.crypt.stringToUtf8ByteArray.
for (var i = 0; i < value.length; i++) {
var c = value.charCodeAt(i);
if (c < 128) {
this.buffer_.push(c);
} else if (c < 2048) {
this.buffer_.push((c >> 6) | 192);
this.buffer_.push((c & 63) | 128);
} else {
} else if (c < 65536) {
// Look for surrogates
if (c >= 0xD800 && c <= 0xDBFF && i + 1 < value.length) {
var second = value.charCodeAt(i + 1);
if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
c = (c - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
this.buffer_.push((c >> 18) | 240);
this.buffer_.push(((c >> 12) & 63 ) | 128);
this.buffer_.push(((c >> 6) & 63) | 128);
this.buffer_.push((c & 63) | 128);
i++;
}
}
else {
this.buffer_.push((c >> 12) | 224);
this.buffer_.push(((c >> 6) & 63) | 128);
this.buffer_.push((c & 63) | 128);
}
}
}
var length = this.buffer_.length - oldLength;
return length;

@ -22,5 +22,5 @@
"url": "https://github.com/google/protobuf/tree/master/js"
},
"author": "Google Protocol Buffers Team",
"license": "Apache-2.0"
"license" : "BSD-3-Clause"
}

@ -217,6 +217,27 @@ CF_EXTERN_C_END
**/
- (size_t)position;
/**
* Moves the limit to the given byte offset starting at the current location.
*
* @exception GPBCodedInputStreamException If the requested bytes exceeed the
* current limit.
*
* @param byteLimit The number of bytes to move the limit, offset to the current
* location.
*
* @return The limit offset before moving the new limit.
*/
- (size_t)pushLimit:(size_t)byteLimit;
/**
* Moves the limit back to the offset as it was before calling pushLimit:.
*
* @param oldLimit The number of bytes to move the current limit. Usually this
* is the value returned by the pushLimit: method.
*/
- (void)popLimit:(size_t)oldLimit;
/**
* Verifies that the last call to -readTag returned the given tag value. This
* is used to verify that a nested group ended with the correct end tag.

@ -400,6 +400,14 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state,
return state_.bufferPos;
}
- (size_t)pushLimit:(size_t)byteLimit {
return GPBCodedInputStreamPushLimit(&state_, byteLimit);
}
- (void)popLimit:(size_t)oldLimit {
GPBCodedInputStreamPopLimit(&state_, oldLimit);
}
- (double)readDouble {
return GPBCodedInputStreamReadDouble(&state_);
}

@ -65,6 +65,15 @@ CF_EXTERN_C_END
/**
* Base class that each generated message subclasses from.
*
* @note While the class support NSSecureCoding, if the message has any
* extensions, they will end up reloaded in @c unknownFields as there is
* no way for the @c NSCoding plumbing to pass through a
* @c GPBExtensionRegistry. To support extensions, instead of passing the
* calls off to the Message, simple store the result of @c data, and then
* when loading, fetch the data and use
* @c +parseFromData:extensionRegistry:error: to provide an extension
* registry.
**/
@interface GPBMessage : NSObject<NSSecureCoding, NSCopying>

@ -44,7 +44,7 @@ Add `objectivec/\*.h` & `objectivec/\*.m` except for
If the target is using ARC, remember to turn off ARC (`-fno-objc-arc`) for the
`.m` files.
The files generated by `protoc` for the `*.proto` files (`\*.pbobjc.h' and
The files generated by `protoc` for the `*.proto` files (`\*.pbobjc.h` and
`\*.pbobjc.m`) are then also added to the target.
Usage

@ -54,6 +54,16 @@ static zend_function_entry repeated_field_methods[] = {
PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedField, count, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedField, getIterator, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static zend_function_entry repeated_field_iter_methods[] = {
PHP_ME(RepeatedFieldIter, rewind, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedFieldIter, current, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedFieldIter, key, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedFieldIter, next, arginfo_void, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedFieldIter, valid, arginfo_void, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
@ -70,11 +80,15 @@ static int repeated_field_has_dimension(zval *object, zval *offset TSRMLS_DC);
static HashTable *repeated_field_get_gc(zval *object, zval ***table,
int *n 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);
// -----------------------------------------------------------------------------
// RepeatedField creation/desctruction
// -----------------------------------------------------------------------------
zend_class_entry* repeated_field_type;
zend_class_entry* repeated_field_iter_type;
zend_object_handlers* repeated_field_handlers;
void repeated_field_init(TSRMLS_D) {
@ -86,8 +100,8 @@ void repeated_field_init(TSRMLS_D) {
repeated_field_type = zend_register_internal_class(&class_type TSRMLS_CC);
repeated_field_type->create_object = repeated_field_create;
zend_class_implements(repeated_field_type TSRMLS_CC, 2, spl_ce_ArrayAccess,
spl_ce_Countable);
zend_class_implements(repeated_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess,
zend_ce_aggregate, spl_ce_Countable);
repeated_field_handlers = PEMALLOC(zend_object_handlers);
memcpy(repeated_field_handlers, zend_get_std_object_handlers(),
@ -386,3 +400,112 @@ PHP_METHOD(RepeatedField, count) {
RETURN_LONG(zend_hash_num_elements(HASH_OF(intern->array)));
}
/**
* Return the beginning iterator.
* This will also be called for: foreach($arr)
* @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);
RepeatedField *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
RepeatedFieldIter *iter = zend_object_store_get_object(iter_php TSRMLS_CC);
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);
repeated_field_iter_type =
zend_register_internal_class(&class_type TSRMLS_CC);
repeated_field_iter_type->create_object = repeated_field_iter_create;
zend_class_implements(repeated_field_iter_type TSRMLS_CC, 1,
zend_ce_iterator);
}
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);
}
// -----------------------------------------------------------------------------
// PHP RepeatedFieldIter Methods
// -----------------------------------------------------------------------------
PHP_METHOD(RepeatedFieldIter, rewind) {
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
intern->position = 0;
}
PHP_METHOD(RepeatedFieldIter, current) {
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
RepeatedField *repeated_field = intern->repeated_field;
long index;
void *memory;
HashTable *table = HASH_OF(repeated_field->array);
if (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);
}
PHP_METHOD(RepeatedFieldIter, key) {
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
RETURN_LONG(intern->position);
}
PHP_METHOD(RepeatedFieldIter, next) {
RepeatedFieldIter *intern = zend_object_store_get_object(getThis() TSRMLS_CC);
++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);
}

@ -250,28 +250,41 @@ PHP_METHOD(DescriptorPool, getGeneratedPool) {
RETURN_ZVAL(generated_pool_php, 1, 0);
}
static void convert_to_class_name_inplace(char *proto_name,
size_t pkg_name_len) {
static void convert_to_class_name_inplace(char *class_name,
const char* fullname,
const char* package_name) {
size_t i;
bool first_char = false;
size_t pkg_name_len = package_name == NULL ? 0 : strlen(package_name);
// In php, class name cannot be Empty.
if (strcmp("google.protobuf.Empty", fullname) == 0) {
fullname = "google.protobuf.GPBEmpty";
}
if (pkg_name_len == 0) {
strcpy(class_name, fullname);
} else {
class_name[0] = '.';
strcpy(&class_name[1], fullname);
for (i = 0; i <= pkg_name_len + 1; i++) {
// PHP package uses camel case.
if (!first_char && proto_name[i] != '.') {
if (!first_char && class_name[i] != '.') {
first_char = true;
proto_name[i] += 'A' - 'a';
class_name[i] += 'A' - 'a';
}
// php packages are divided by '\'.
if (proto_name[i] == '.') {
if (class_name[i] == '.') {
first_char = false;
proto_name[i] = '\\';
class_name[i] = '\\';
}
}
}
// Submessage is concatenated with its containing messages by '_'.
for (i = pkg_name_len; i < strlen(proto_name); i++) {
if (proto_name[i] == '.') {
proto_name[i] = '_';
for (i = pkg_name_len; i < strlen(class_name); i++) {
if (class_name[i] == '.') {
class_name[i] = '_';
}
}
}
@ -322,13 +335,13 @@ PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
upb_msgdef_mapentry(upb_downcast_msgdef(def))) { \
break; \
} \
/* Prepend '.' to package name to make it absolute. */ \
/* 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); \
char *klass_name = ecalloc(sizeof(char), 2 + strlen(fullname)); \
klass_name[0] = '.'; \
strcpy(&klass_name[1], fullname); \
size_t pkg_name_len = strlen(upb_filedef_package(files[0])); \
convert_to_class_name_inplace(klass_name, pkg_name_len); \
char *klass_name = ecalloc(sizeof(char), 5 + strlen(fullname)); \
convert_to_class_name_inplace(klass_name, fullname, \
upb_filedef_package(files[0])); \
zend_class_entry **pce; \
if (zend_lookup_class(klass_name, strlen(klass_name), &pce TSRMLS_CC) == \
FAILURE) { \

@ -177,8 +177,8 @@ static zend_object_value message_create(zend_class_entry* ce TSRMLS_DC) {
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);
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,

@ -156,6 +156,7 @@ static PHP_RSHUTDOWN_FUNCTION(protobuf) {
static PHP_MINIT_FUNCTION(protobuf) {
map_field_init(TSRMLS_C);
repeated_field_init(TSRMLS_C);
repeated_field_iter_init(TSRMLS_C);
gpb_type_init(TSRMLS_C);
message_init(TSRMLS_C);
descriptor_pool_init(TSRMLS_C);

@ -39,6 +39,9 @@
#define PHP_PROTOBUF_EXTNAME "protobuf"
#define PHP_PROTOBUF_VERSION "3.1.0a1"
#define MAX_LENGTH_OF_INT64 20
#define SIZEOF_INT64 8
// -----------------------------------------------------------------------------
// Forward Declaration
// ----------------------------------------------------------------------------
@ -51,6 +54,7 @@ struct MessageField;
struct MessageHeader;
struct MessageLayout;
struct RepeatedField;
struct RepeatedFieldIter;
struct MapField;
typedef struct DescriptorPool DescriptorPool;
@ -61,6 +65,7 @@ typedef struct MessageField MessageField;
typedef struct MessageHeader MessageHeader;
typedef struct MessageLayout MessageLayout;
typedef struct RepeatedField RepeatedField;
typedef struct RepeatedFieldIter RepeatedFieldIter;
typedef struct MapField MapField;
// -----------------------------------------------------------------------------
@ -77,6 +82,7 @@ void descriptor_pool_init(TSRMLS_D);
void gpb_type_init(TSRMLS_D);
void map_field_init(TSRMLS_D);
void repeated_field_init(TSRMLS_D);
void repeated_field_iter_init(TSRMLS_D);
void util_init(TSRMLS_D);
void message_init(TSRMLS_D);
@ -366,6 +372,12 @@ struct RepeatedField {
// (for message field only).
};
struct RepeatedFieldIter {
zend_object std;
RepeatedField* repeated_field;
long position;
};
void repeated_field_create_with_type(zend_class_entry* ce,
const upb_fielddef* field,
zval** repeated_field TSRMLS_DC);
@ -383,6 +395,13 @@ PHP_METHOD(RepeatedField, offsetGet);
PHP_METHOD(RepeatedField, offsetSet);
PHP_METHOD(RepeatedField, offsetUnset);
PHP_METHOD(RepeatedField, count);
PHP_METHOD(RepeatedField, getIterator);
PHP_METHOD(RepeatedFieldIter, rewind);
PHP_METHOD(RepeatedFieldIter, current);
PHP_METHOD(RepeatedFieldIter, key);
PHP_METHOD(RepeatedFieldIter, next);
PHP_METHOD(RepeatedFieldIter, valid);
// -----------------------------------------------------------------------------
// Oneof Field.

@ -174,11 +174,31 @@ CASE(FLOAT, DOUBLE, float)
CASE(DOUBLE, DOUBLE, double)
CASE(BOOL, BOOL, int8_t)
CASE(INT32, LONG, int32_t)
CASE(INT64, LONG, int64_t)
CASE(UINT64, LONG, uint64_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; \
}
#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; \
}
#endif
CASE(UINT64, uint64_t)
CASE(INT64, int64_t)
#undef CASE
case UPB_TYPE_UINT32: {
// Prepend bit-1 for negative numbers, so that uint32 value will be
// consistent on both 32-bit and 64-bit architectures.

@ -34,6 +34,7 @@
#include "utf8.h"
static zend_class_entry* util_type;
static const char int64_min_digits[] = "9223372036854775808";
ZEND_BEGIN_ARG_INFO_EX(arg_check_optional, 0, 0, 1)
ZEND_ARG_INFO(1, val)
@ -78,8 +79,128 @@ void util_init(TSRMLS_D) {
// Type checking/conversion.
// -----------------------------------------------------------------------------
// This is modified from is_numeric_string in zend_operators.h. The behavior of
// this function is the same as is_numeric_string, except that this takes
// int64_t as input instead of long.
static zend_uchar convert_numeric_string(
const char *str, int length, int64_t *lval, double *dval) {
const char *ptr;
int base = 10, digits = 0, dp_or_e = 0;
double local_dval = 0.0;
zend_uchar type;
if (length == 0) {
return IS_NULL;
}
while (*str == ' ' || *str == '\t' || *str == '\n' ||
*str == '\r' || *str == '\v' || *str == '\f') {
str++;
length--;
}
ptr = str;
if (*ptr == '-' || *ptr == '+') {
ptr++;
}
if (ZEND_IS_DIGIT(*ptr)) {
// Handle hex numbers
// str is used instead of ptr to disallow signs and keep old behavior.
if (length > 2 && *str == '0' && (str[1] == 'x' || str[1] == 'X')) {
base = 16;
ptr += 2;
}
// Skip any leading 0s.
while (*ptr == '0') {
ptr++;
}
// Count the number of digits. If a decimal point/exponent is found,
// it's a double. Otherwise, if there's a dval or no need to check for
// a full match, stop when there are too many digits for a int64 */
for (type = IS_LONG;
!(digits >= MAX_LENGTH_OF_INT64 && dval);
digits++, ptr++) {
check_digits:
if (ZEND_IS_DIGIT(*ptr) || (base == 16 && ZEND_IS_XDIGIT(*ptr))) {
continue;
} else if (base == 10) {
if (*ptr == '.' && dp_or_e < 1) {
goto process_double;
} else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
const char *e = ptr + 1;
if (*e == '-' || *e == '+') {
ptr = e++;
}
if (ZEND_IS_DIGIT(*e)) {
goto process_double;
}
}
}
break;
}
if (base == 10) {
if (digits >= MAX_LENGTH_OF_INT64) {
dp_or_e = -1;
goto process_double;
}
} else if (!(digits < SIZEOF_INT64 * 2 ||
(digits == SIZEOF_INT64 * 2 && ptr[-digits] <= '7'))) {
if (dval) {
local_dval = zend_hex_strtod(str, &ptr);
}
type = IS_DOUBLE;
}
} else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
process_double:
type = IS_DOUBLE;
// If there's a dval, do the conversion; else continue checking
// the digits if we need to check for a full match.
if (dval) {
local_dval = zend_strtod(str, &ptr);
} else if (dp_or_e != -1) {
dp_or_e = (*ptr++ == '.') ? 1 : 2;
goto check_digits;
}
} else {
return IS_NULL;
}
if (ptr != str + length) {
zend_error(E_NOTICE, "A non well formed numeric value encountered");
return 0;
}
if (type == IS_LONG) {
if (digits == MAX_LENGTH_OF_INT64 - 1) {
int cmp = strcmp(&ptr[-digits], int64_min_digits);
if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
if (dval) {
*dval = zend_strtod(str, NULL);
}
return IS_DOUBLE;
}
}
if (lval) {
*lval = strtoll(str, NULL, base);
}
return IS_LONG;
} else {
if (dval) {
*dval = local_dval;
}
return IS_DOUBLE;
}
}
#define CONVERT_TO_INTEGER(type) \
static bool convert_long_to_##type(long val, type##_t* type##_value) { \
static bool convert_int64_to_##type(int64_t val, type##_t* type##_value) { \
*type##_value = (type##_t)val; \
return true; \
} \
@ -91,15 +212,15 @@ void util_init(TSRMLS_D) {
\
static bool convert_string_to_##type(const char* val, int len, \
type##_t* type##_value) { \
long lval; \
int64_t lval; \
double dval; \
\
switch (is_numeric_string(val, len, &lval, &dval, 0)) { \
switch (convert_numeric_string(val, len, &lval, &dval)) { \
case IS_DOUBLE: { \
return convert_double_to_##type(dval, type##_value); \
} \
case IS_LONG: { \
return convert_long_to_##type(lval, type##_value); \
return convert_int64_to_##type(lval, type##_value); \
} \
default: \
zend_error(E_USER_ERROR, \
@ -111,7 +232,7 @@ void util_init(TSRMLS_D) {
bool protobuf_convert_to_##type(zval* from, type##_t* to) { \
switch (Z_TYPE_P(from)) { \
case IS_LONG: { \
return convert_long_to_##type(Z_LVAL_P(from), to); \
return convert_int64_to_##type(Z_LVAL_P(from), to); \
} \
case IS_DOUBLE: { \
return convert_double_to_##type(Z_DVAL_P(from), to); \
@ -137,7 +258,7 @@ CONVERT_TO_INTEGER(uint64);
#undef CONVERT_TO_INTEGER
#define CONVERT_TO_FLOAT(type) \
static bool convert_long_to_##type(long val, type* type##_value) { \
static bool convert_int64_to_##type(int64_t val, type* type##_value) { \
*type##_value = (type)val; \
return true; \
} \
@ -149,10 +270,10 @@ CONVERT_TO_INTEGER(uint64);
\
static bool convert_string_to_##type(const char* val, int len, \
type* type##_value) { \
long lval; \
int64_t lval; \
double dval; \
\
switch (is_numeric_string(val, len, &lval, &dval, 0)) { \
switch (convert_numeric_string(val, len, &lval, &dval)) { \
case IS_DOUBLE: { \
*type##_value = (type)dval; \
return true; \
@ -171,7 +292,7 @@ CONVERT_TO_INTEGER(uint64);
bool protobuf_convert_to_##type(zval* from, type* to) { \
switch (Z_TYPE_P(from)) { \
case IS_LONG: { \
return convert_long_to_##type(Z_LVAL_P(from), to); \
return convert_int64_to_##type(Z_LVAL_P(from), to); \
} \
case IS_DOUBLE: { \
return convert_double_to_##type(Z_DVAL_P(from), to); \

@ -37,6 +37,28 @@ use Google\Protobuf\Internal\RepeatedField;
class GPBUtil
{
public function divideInt64ToInt32($value, &$high, &$low, $trim = false)
{
$isNeg = (bccomp($value, 0) < 0);
if ($isNeg) {
$value = bcsub(0, $value);
}
$high = (int) bcdiv(bcadd($value, 1), 4294967296);
$low = (int) bcmod($value, 4294967296);
if ($isNeg) {
$high = ~$high;
$low = ~$low;
$low++;
if (!$low) {
$high++;
}
}
if ($trim) {
$high = 0;
}
}
public static function checkString(&$var, $check_utf8)
{
@ -70,9 +92,14 @@ class GPBUtil
public static function checkUint32(&$var)
{
if (is_numeric($var)) {
$var = intval($var);
if (PHP_INT_SIZE === 8) {
$var = intval($var);
$var |= ((-(($var >> 31) & 0x1)) & ~0xFFFFFFFF);
} else {
if (bccomp($var, 0x7FFFFFFF) > 0) {
$var = bcsub($var, "4294967296");
}
$var = (int) $var;
}
} else {
trigger_error("Expect integer.", E_USER_ERROR);
@ -82,7 +109,11 @@ class GPBUtil
public static function checkInt64(&$var)
{
if (is_numeric($var)) {
if (PHP_INT_SIZE == 8) {
$var = intval($var);
} else {
$var = bcdiv($var, 1, 0);
}
} else {
trigger_error("Expect integer.", E_USER_ERROR);
}
@ -91,7 +122,11 @@ class GPBUtil
public static function checkUint64(&$var)
{
if (is_numeric($var)) {
if (PHP_INT_SIZE == 8) {
$var = intval($var);
} else {
$var = bcdiv($var, 1, 0);
}
} else {
trigger_error("Expect integer.", E_USER_ERROR);
}

@ -32,10 +32,6 @@
namespace Google\Protobuf\Internal;
use Google\Protobuf\Internal\GPBUtil;
use Google\Protobuf\Internal\Int64;
use Google\Protobuf\Internal\Uint64;
class GPBWire
{
@ -150,20 +146,28 @@ class GPBWire
public static function zigZagEncode64($int64)
{
$a = $int64->copy()->leftShift(1);
$b = $int64->copy()->rightShift(63);
$result = $a->bitXor($b);
$uint64 = Uint64::newValue($result->high, $result->low);
return $uint64;
if (PHP_INT_SIZE == 4) {
if (bccomp($int64, 0) >= 0) {
return bcmul($int64, 2);
} else {
return bcsub(bcmul(bcsub(0, $int64), 2), 1);
}
} else {
return ($int64 << 1) ^ ($int64 >> 63);
}
}
public static function zigZagDecode64($uint64)
{
$a = $uint64->copy()->rightShift(1);
$b = $uint64->oddMask();
$result = $a->bitXor($b);
$int64 = Int64::newValue($result->high, $result->low);
return $int64;
if (PHP_INT_SIZE == 4) {
if (bcmod($uint64, 2) == 0) {
return bcdiv($uint64, 2, 0);
} else {
return bcsub(0, bcdiv(bcadd($uint64, 1), 2, 0));
}
} else {
return (($uint64 >> 1) & 0x7FFFFFFFFFFFFFFF) ^ (-($uint64 & 1));
}
}
public static function readInt32(&$input, &$value)
@ -227,11 +231,7 @@ class GPBWire
public static function readSfixed64(&$input, &$value)
{
if (!self::readFixed64($input, $value)) {
return false;
}
$value = Int64::newValue($value->high, $value->low);
return true;
return $input->readLittleEndian64($value);
}
public static function readFloat(&$input, &$value)
@ -259,7 +259,7 @@ class GPBWire
if (!$input->readVarint64($value)) {
return false;
}
if ($value->high === 0 && $value->low === 0) {
if ($value == 0) {
$value = false;
} else {
$value = true;
@ -324,8 +324,8 @@ class GPBWire
public static function writeSint64(&$output, $value)
{
$value = GPBWire::zigZagEncode64(GPBUtil::Int64($value));
return $output->writeVarint64($value->toInteger());
$value = GPBWire::zigZagEncode64($value);
return $output->writeVarint64($value);
}
public static function writeFixed32(&$output, $value)
@ -431,9 +431,8 @@ class GPBWire
public static function sint64Size($value)
{
$value = GPBUtil::Int64($value);
$value = self::zigZagEncode64($value);
return self::varint64Size($value->toInteger());
return self::varint64Size($value);
}
public static function varint64Size($value)

@ -34,6 +34,24 @@ namespace Google\Protobuf\Internal;
use Google\Protobuf\Internal\Uint64;
function combineInt32ToInt64($high, $low)
{
$isNeg = $high < 0;
if ($isNeg) {
$high = ~$high;
$low = ~$low;
$low++;
if (!$low) {
$high++;
}
}
$result = bcadd(bcmul($high, 4294967296), $low);
if ($isNeg) {
$result = bcsub(0, $result);
}
return $result;
}
class InputStream
{
@ -116,11 +134,23 @@ class InputStream
if (!$this->readVarint64($var)) {
return false;
}
$var = $var->toInteger() & 0xFFFFFFFF;
if (PHP_INT_SIZE == 4) {
$var = bcmod($var, 4294967296);
} else {
$var &= 0xFFFFFFFF;
}
// Convert large uint32 to int32.
if (PHP_INT_SIZE === 8 && ($var > 0x7FFFFFFF)) {
if ($var > 0x7FFFFFFF) {
if (PHP_INT_SIZE === 8) {
$var = $var | (0xFFFFFFFF << 32);
} else {
$var = bcsub($var, 4294967296);
}
}
$var = intval($var);
return true;
}
@ -130,7 +160,8 @@ class InputStream
*/
public function readVarint64(&$var)
{
$result = new Uint64(0);
$high = 0;
$low = 0;
$count = 0;
$b = 0;
@ -142,12 +173,27 @@ class InputStream
return false;
}
$b = ord($this->buffer[$this->current]);
$result->bitOr((new Uint64($b & 0x7F))->leftShift(7 * $count));
$bits = 7 * $count;
if ($bits >= 32) {
$high |= (($b & 0x7F) << ($bits - 32));
} else if ($bits > 25){
$high_bits = $bits - 25;
$low = ($low | (($b & 0x7F) << $bits)) & (int) 0xFFFFFFFF;
$high = $b & ((0x1 << $high_bits) -1);
} else {
$low |= (($b & 0x7F) << $bits);
}
$this->advance(1);
$count += 1;
} while ($b & 0x80);
$var = $result;
if (PHP_INT_SIZE == 4) {
$var = combineInt32ToInt64($high, $low);
} else {
$var = ($high & 0xFFFFFFFF) << 32 |
($low & 0xFFFFFFFF);
}
return true;
}
@ -161,7 +207,7 @@ class InputStream
if (!$this->readVarint64($var)) {
return false;
}
$var = $var->toInteger();
$var = (int)$var;
return true;
}
@ -197,7 +243,11 @@ class InputStream
return false;
}
$high = unpack('V', $data)[1];
$var = Uint64::newValue($high, $low);
if (PHP_INT_SIZE == 4) {
$var = combineInt32ToInt64($high, $low);
} else {
$var = ($high << 32) | $low;
}
return true;
}

@ -125,6 +125,16 @@ class Message
$oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
$oneof_name = $oneof->getName();
$this->$oneof_name = new OneofField($oneof);
} else if ($field->getLabel() === GPBLabel::OPTIONAL &&
PHP_INT_SIZE == 4) {
switch ($field->getType()) {
case GPBType::INT64:
case GPBType::UINT64:
case GPBType::FIXED64:
case GPBType::SFIXED64:
case GPBType::SINT64:
$this->$setter("0");
}
}
}
}
@ -210,13 +220,11 @@ class Message
if (!GPBWire::readInt64($input, $value)) {
return false;
}
$value = $value->toInteger();
break;
case GPBType::UINT64:
if (!GPBWire::readUint64($input, $value)) {
return false;
}
$value = $value->toInteger();
break;
case GPBType::INT32:
if (!GPBWire::readInt32($input, $value)) {
@ -227,7 +235,6 @@ class Message
if (!GPBWire::readFixed64($input, $value)) {
return false;
}
$value = $value->toInteger();
break;
case GPBType::FIXED32:
if (!GPBWire::readFixed32($input, $value)) {
@ -285,7 +292,6 @@ class Message
if (!GPBWire::readSfixed64($input, $value)) {
return false;
}
$value = $value->toInteger();
break;
case GPBType::SINT32:
if (!GPBWire::readSint32($input, $value)) {
@ -296,7 +302,6 @@ class Message
if (!GPBWire::readSint64($input, $value)) {
return false;
}
$value = $value->toInteger();
break;
default:
user_error("Unsupported type.");

@ -90,8 +90,6 @@ class OutputStream
public function writeRaw($data, $size)
{
if ($this->buffer_size < $size) {
var_dump($this->buffer_size);
var_dump($size);
trigger_error("Output stream doesn't have enough buffer.");
return false;
}
@ -107,15 +105,28 @@ class OutputStream
private static function writeVarintToArray($value, &$buffer, $trim = false)
{
$current = 0;
$high = 0;
$low = 0;
if (PHP_INT_SIZE == 4) {
GPBUtil::divideInt64ToInt32($value, $high, $low, $trim);
} else {
if ($trim) {
$value &= 0xFFFFFFFF;
$low = $value & 0xFFFFFFFF;
} else {
$low = $value;
}
}
while ($value >= 0x80 || $value < 0) {
$buffer[$current] = chr($value | 0x80);
while ($low >= 0x80 || $low < 0) {
$buffer[$current] = chr($low | 0x80);
$value = ($value >> 7) & ~(0x7F << ((PHP_INT_SIZE << 3) - 7));
$carry = ($high & 0x7F) << ((PHP_INT_SIZE << 3) - 7);
$high = ($high >> 7) & ~(0x7F << ((PHP_INT_SIZE << 3) - 7));
$low = (($low >> 7) & ~(0x7F << ((PHP_INT_SIZE << 3) - 7)) | $carry);
$current++;
}
$buffer[$current] = chr($value);
$buffer[$current] = chr($low);
return $current + 1;
}
@ -130,14 +141,24 @@ class OutputStream
private static function writeLittleEndian64ToArray($value, &$buffer)
{
$buffer[0] = chr($value & 0x000000FF);
$buffer[1] = chr(($value >> 8) & 0x000000FF);
$buffer[2] = chr(($value >> 16) & 0x000000FF);
$buffer[3] = chr(($value >> 24) & 0x000000FF);
$buffer[4] = chr(($value >> 32) & 0x000000FF);
$buffer[5] = chr(($value >> 40) & 0x000000FF);
$buffer[6] = chr(($value >> 48) & 0x000000FF);
$buffer[7] = chr(($value >> 56) & 0x000000FF);
$high = 0;
$low = 0;
if (PHP_INT_SIZE == 4) {
GPBUtil::divideInt64ToInt32($value, $high, $low);
} else {
$low = $value & 0xFFFFFFFF;
$high = ($value >> 32) & 0xFFFFFFFF;
}
$buffer[0] = chr($low & 0x000000FF);
$buffer[1] = chr(($low >> 8) & 0x000000FF);
$buffer[2] = chr(($low >> 16) & 0x000000FF);
$buffer[3] = chr(($low >> 24) & 0x000000FF);
$buffer[4] = chr($high & 0x000000FF);
$buffer[5] = chr(($high >> 8) & 0x000000FF);
$buffer[6] = chr(($high >> 16) & 0x000000FF);
$buffer[7] = chr(($high >> 24) & 0x000000FF);
return 8;
}
}

@ -1,175 +0,0 @@
<?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 GPBInteger
{
public $high = 0;
public $low = 0;
public function __construct($value = 0)
{
$this->low = $value & 0xFFFFFFFF;
if (PHP_INT_SIZE === 8) {
$this->high = ($value >> 32) & 0xFFFFFFFF;
}
}
// Return 0 for unsigned integers and 1 for signed integers.
protected function sign()
{
trigger_error("Not implemented", E_ERROR);
}
public function leftShift($count)
{
if ($count > 63) {
$this->low = 0;
$this->high = 0;
return;
}
if ($count > 32) {
$this->high = $this->low;
$this->low = 0;
$count -= 32;
}
$mask = (1 << $count) - 1;
$this->high = (($this->high << $count) & 0xFFFFFFFF) |
(($this->low >> (32 - $count)) & $mask);
$this->low = ($this->low << $count) & 0xFFFFFFFF;
$this->high &= 0xFFFFFFFF;
$this->low &= 0xFFFFFFFF;
return $this;
}
public function rightShift($count)
{
$sign = (($this->high & 0x80000000) >> 31) & $this->sign();
if ($count > 63) {
$this->low = -$sign;
$this->high = -$sign;
return;
}
if ($count > 32) {
$this->low = $this->high;
$this->high = -$sign;
$count -= 32;
}
$this->low = (($this->low >> $count) & 0xFFFFFFFF) |
(($this->high << (32 - $count)) & 0xFFFFFFFF);
$this->high = (($this->high >> $count) | (-$sign << $count));
$this->high &= 0xFFFFFFFF;
$this->low &= 0xFFFFFFFF;
return $this;
}
public function bitOr($var)
{
$this->high |= $var->high;
$this->low |= $var->low;
return $this;
}
public function bitXor($var)
{
$this->high ^= $var->high;
$this->low ^= $var->low;
return $this;
}
public function bitAnd($var)
{
$this->high &= $var->high;
$this->low &= $var->low;
return $this;
}
// Even: all zero; Odd: all one.
public function oddMask()
{
$low = (-($this->low & 1)) & 0xFFFFFFFF;
$high = $low;
return UInt64::newValue($high, $low);
}
public function toInteger()
{
if (PHP_INT_SIZE === 8) {
return ($this->high << 32) | $this->low;
} else {
return $this->low;
}
}
public function copy()
{
return static::newValue($this->high, $this->low);
}
}
class Uint64 extends GPBInteger
{
public static function newValue($high, $low)
{
$uint64 = new Uint64(0);
$uint64->high = $high;
$uint64->low = $low;
return $uint64;
}
protected function sign()
{
return 0;
}
}
class Int64 extends GPBInteger
{
public static function newValue($high, $low)
{
$int64 = new Int64(0);
$int64->high = $high;
$int64->low = $low;
return $int64;
}
protected function sign()
{
return 1;
}
}

@ -215,6 +215,18 @@ class Descriptor
return $desc;
}
}
function addPrefixIfSpecial(
$name,
$package)
{
if ($name === "Empty" && $package === "google.protobuf") {
return "GPBEmpty";
} else {
return $name;
}
}
function getFullClassName(
$proto,
$containing,
@ -224,7 +236,8 @@ function getFullClassName(
&$fullname)
{
// Full name needs to start with '.'.
$message_name_without_package = $proto->getName();
$message_name_without_package =
addPrefixIfSpecial($proto->getName(), $package);
if ($containing !== "") {
$message_name_without_package =
$containing . "." . $message_name_without_package;
@ -240,10 +253,14 @@ function getFullClassName(
$class_name_without_package =
implode('_', array_map('ucwords',
explode('.', $message_name_without_package)));
if ($package === "") {
$classname = $class_name_without_package;
} else {
$classname =
implode('\\', array_map('ucwords', explode('.', $package))).
"\\".$class_name_without_package;
}
}
class OneofDescriptor
{

@ -65,6 +65,17 @@ class RepeatedFieldTest extends PHPUnit_Framework_TestCase
$this->assertSame(3, $arr[6]);
$arr [7]= MAX_INT32_STRING;
$this->assertSame(MAX_INT32, $arr[7]);
// Test foreach.
$arr = new RepeatedField(GPBType::INT32);
for ($i = 0; $i < 3; $i++) {
$arr []= $i;
}
$i = 0;
foreach ($arr as $val) {
$this->assertSame($i++, $val);
}
$this->assertSame(3, $i);
}
/**
@ -225,47 +236,69 @@ class RepeatedFieldTest extends PHPUnit_Framework_TestCase
// Test append.
$arr []= MAX_INT64;
$this->assertSame(MAX_INT64, $arr[0]);
$arr []= MIN_INT64;
$this->assertEquals(MIN_INT64, $arr[1]);
$arr []= 1.1;
$this->assertSame(1, $arr[2]);
$arr []= '2';
$this->assertSame(2, $arr[3]);
$arr []= '3.1';
$this->assertSame(3, $arr[4]);
$arr []= MAX_INT64_STRING;
$this->assertSame(MAX_INT64, $arr[5]);
$arr []= MIN_INT64_STRING;
$this->assertEquals(MIN_INT64, $arr[6]);
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_INT64, $arr[0]);
$this->assertSame(MIN_INT64, $arr[1]);
$this->assertSame('1', $arr[2]);
$this->assertSame('2', $arr[3]);
$this->assertSame('3', $arr[4]);
$this->assertSame(MAX_INT64_STRING, $arr[5]);
$this->assertSame(MIN_INT64_STRING, $arr[6]);
} else {
$this->assertSame(MAX_INT64, $arr[0]);
$this->assertSame(MIN_INT64, $arr[1]);
$this->assertSame(1, $arr[2]);
$this->assertSame(2, $arr[3]);
$this->assertSame(3, $arr[4]);
$this->assertSame(MAX_INT64, $arr[5]);
$this->assertSame(MIN_INT64, $arr[6]);
}
$this->assertEquals(7, count($arr));
for ($i = 0; $i < count($arr); $i++) {
$arr[$i] = 0;
if (PHP_INT_SIZE == 4) {
$this->assertSame('0', $arr[$i]);
} else {
$this->assertSame(0, $arr[$i]);
}
}
// Test set.
$arr [0]= MAX_INT64;
$this->assertSame(MAX_INT64, $arr[0]);
$arr [1]= MIN_INT64;
$this->assertEquals(MIN_INT64, $arr[1]);
$arr [2]= 1.1;
$this->assertSame(1, $arr[2]);
$arr [3]= '2';
$this->assertSame(2, $arr[3]);
$arr [4]= '3.1';
$this->assertSame(3, $arr[4]);
$arr [5]= MAX_INT64_STRING;
$this->assertSame(MAX_INT64, $arr[5]);
$arr [6]= MIN_INT64_STRING;
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_INT64_STRING, $arr[0]);
$this->assertSame(MIN_INT64_STRING, $arr[1]);
$this->assertSame('1', $arr[2]);
$this->assertSame('2', $arr[3]);
$this->assertSame('3', $arr[4]);
$this->assertSame(MAX_INT64_STRING, $arr[5]);
$this->assertEquals(MIN_INT64_STRING, $arr[6]);
} else {
$this->assertSame(MAX_INT64, $arr[0]);
$this->assertSame(MIN_INT64, $arr[1]);
$this->assertSame(1, $arr[2]);
$this->assertSame(2, $arr[3]);
$this->assertSame(3, $arr[4]);
$this->assertSame(MAX_INT64, $arr[5]);
$this->assertEquals(MIN_INT64, $arr[6]);
}
}
/**
* @expectedException PHPUnit_Framework_Error
@ -315,38 +348,57 @@ class RepeatedFieldTest extends PHPUnit_Framework_TestCase
// Test append.
$arr []= MAX_UINT64;
$this->assertEquals(MAX_UINT64, $arr[0]);
$arr []= 1.1;
$this->assertSame(1, $arr[1]);
$arr []= '2';
$this->assertSame(2, $arr[2]);
$arr []= '3.1';
$this->assertSame(3, $arr[3]);
$arr []= MAX_UINT64_STRING;
$this->assertEquals(MAX_UINT64, $arr[4]);
$this->assertEquals(5, count($arr));
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_UINT64_STRING, $arr[0]);
$this->assertSame('1', $arr[1]);
$this->assertSame('2', $arr[2]);
$this->assertSame('3', $arr[3]);
$this->assertSame(MAX_UINT64_STRING, $arr[4]);
} else {
$this->assertSame(MAX_UINT64, $arr[0]);
$this->assertSame(1, $arr[1]);
$this->assertSame(2, $arr[2]);
$this->assertSame(3, $arr[3]);
$this->assertSame(MAX_UINT64, $arr[4]);
$this->assertSame(5, count($arr));
}
$this->assertSame(5, count($arr));
for ($i = 0; $i < count($arr); $i++) {
$arr[$i] = 0;
if (PHP_INT_SIZE == 4) {
$this->assertSame('0', $arr[$i]);
} else {
$this->assertSame(0, $arr[$i]);
}
}
// Test set.
$arr [0]= MAX_UINT64;
$this->assertEquals(MAX_UINT64, $arr[0]);
$arr [1]= 1.1;
$this->assertSame(1, $arr[1]);
$arr [2]= '2';
$this->assertSame(2, $arr[2]);
$arr [3]= '3.1';
$this->assertSame(3, $arr[3]);
$arr [4]= MAX_UINT64_STRING;
$this->assertEquals(MAX_UINT64, $arr[4]);
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_UINT64_STRING, $arr[0]);
$this->assertSame('1', $arr[1]);
$this->assertSame('2', $arr[2]);
$this->assertSame('3', $arr[3]);
$this->assertSame(MAX_UINT64_STRING, $arr[4]);
} else {
$this->assertSame(MAX_UINT64, $arr[0]);
$this->assertSame(1, $arr[1]);
$this->assertSame(2, $arr[2]);
$this->assertSame(3, $arr[3]);
$this->assertSame(MAX_UINT64, $arr[4]);
}
}
/**

@ -1,6 +1,7 @@
<?php
require_once('test.pb.php');
require_once('test_no_namespace.pb.php');
require_once('test_util.php');
use Google\Protobuf\Internal\RepeatedField;
@ -147,17 +148,40 @@ class GeneratedClassTest extends PHPUnit_Framework_TestCase
// Set float.
$m->setOptionalInt64(1.1);
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $m->getOptionalInt64());
} else {
$this->assertSame(1, $m->getOptionalInt64());
}
// Set string.
$m->setOptionalInt64('2');
if (PHP_INT_SIZE == 4) {
$this->assertSame('2', $m->getOptionalInt64());
} else {
$this->assertSame(2, $m->getOptionalInt64());
}
$m->setOptionalInt64('3.1');
if (PHP_INT_SIZE == 4) {
$this->assertSame('3', $m->getOptionalInt64());
} else {
$this->assertSame(3, $m->getOptionalInt64());
}
$m->setOptionalInt64(MAX_INT64_STRING);
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_INT64_STRING, $m->getOptionalInt64());
} else {
$this->assertSame(MAX_INT64, $m->getOptionalInt64());
}
$m->setOptionalInt64(MIN_INT64_STRING);
$this->assertEquals(MIN_INT64, $m->getOptionalInt64());
if (PHP_INT_SIZE == 4) {
$this->assertSame(MIN_INT64_STRING, $m->getOptionalInt64());
} else {
$this->assertSame(MIN_INT64, $m->getOptionalInt64());
}
}
/**
@ -188,19 +212,41 @@ class GeneratedClassTest extends PHPUnit_Framework_TestCase
// Set integer.
$m->setOptionalUint64(MAX_UINT64);
$this->assertEquals(MAX_UINT64, $m->getOptionalUint64());
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_UINT64_STRING, $m->getOptionalUint64());
} else {
$this->assertSame(MAX_UINT64, $m->getOptionalUint64());
}
// Set float.
$m->setOptionalUint64(1.1);
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $m->getOptionalUint64());
} else {
$this->assertSame(1, $m->getOptionalUint64());
}
// Set string.
$m->setOptionalUint64('2');
if (PHP_INT_SIZE == 4) {
$this->assertSame('2', $m->getOptionalUint64());
} else {
$this->assertSame(2, $m->getOptionalUint64());
}
$m->setOptionalUint64('3.1');
if (PHP_INT_SIZE == 4) {
$this->assertSame('3', $m->getOptionalUint64());
} else {
$this->assertSame(3, $m->getOptionalUint64());
}
$m->setOptionalUint64(MAX_UINT64_STRING);
$this->assertEquals(MAX_UINT64, $m->getOptionalUint64());
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_UINT64_STRING, $m->getOptionalUint64());
} else {
$this->assertSame(MAX_UINT64, $m->getOptionalUint64());
}
}
/**
@ -554,4 +600,12 @@ class GeneratedClassTest extends PHPUnit_Framework_TestCase
$this->assertSame('', $m->getOneofString());
$this->assertSame(1, $m->getOneofMessage()->getA());
}
#########################################################
# Test oneof field.
#########################################################
public function testMessageWithoutNamespace() {
$m = new NoNameSpace();
}
}

@ -0,0 +1,28 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: google/protobuf/empty.proto
namespace Google\Protobuf;
use Google\Protobuf\Internal\DescriptorPool;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
class GPBEmpty extends \Google\Protobuf\Internal\Message
{
}
$pool = DescriptorPool::getGeneratedPool();
$pool->internalAddGeneratedFile(hex2bin(
"0ab7010a1b676f6f676c652f70726f746f6275662f656d7074792e70726f" .
"746f120f676f6f676c652e70726f746f62756622070a05456d7074794276" .
"0a13636f6d2e676f6f676c652e70726f746f627566420a456d7074795072" .
"6f746f50015a276769746875622e636f6d2f676f6c616e672f70726f746f" .
"6275662f7074797065732f656d707479f80101a20203475042aa021e476f" .
"6f676c652e50726f746f6275662e57656c6c4b6e6f776e54797065736206" .
"70726f746f33"
));

@ -205,9 +205,14 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
// Test integer argument.
$arr[MAX_INT64] = MAX_INT64;
$this->assertSame(MAX_INT64, $arr[MAX_INT64]);
$arr[MIN_INT64] = MIN_INT64;
$this->assertEquals(MIN_INT64, $arr[MIN_INT64]);
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_INT64_STRING, $arr[MAX_INT64_STRING]);
$this->assertSame(MIN_INT64_STRING, $arr[MIN_INT64_STRING]);
} else {
$this->assertSame(MAX_INT64, $arr[MAX_INT64]);
$this->assertSame(MIN_INT64, $arr[MIN_INT64]);
}
$this->assertEquals(2, count($arr));
unset($arr[MAX_INT64]);
unset($arr[MIN_INT64]);
@ -215,20 +220,31 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
// Test float argument.
$arr[1.1] = 1.1;
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $arr['1']);
} else {
$this->assertSame(1, $arr[1]);
}
$this->assertEquals(1, count($arr));
unset($arr[1.1]);
$this->assertEquals(0, count($arr));
// Test string argument.
$arr['2'] = '2';
$this->assertSame(2, $arr[2]);
$arr['3.1'] = '3.1';
$this->assertSame(3, $arr[3]);
$arr[MAX_INT64_STRING] = MAX_INT64_STRING;
$this->assertSame(MAX_INT64, $arr[MAX_INT64]);
$arr[MIN_INT64_STRING] = MIN_INT64_STRING;
$this->assertEquals(MIN_INT64, $arr[MIN_INT64]);
if (PHP_INT_SIZE == 4) {
$this->assertSame('2', $arr['2']);
$this->assertSame('3', $arr['3']);
$this->assertSame(MAX_INT64_STRING, $arr[MAX_INT64_STRING]);
$this->assertSame(MIN_INT64_STRING, $arr[MIN_INT64_STRING]);
} else {
$this->assertSame(2, $arr[2]);
$this->assertSame(3, $arr[3]);
$this->assertSame(MAX_INT64, $arr[MAX_INT64]);
$this->assertSame(MIN_INT64, $arr[MIN_INT64]);
}
$this->assertEquals(4, count($arr));
unset($arr['2']);
unset($arr['3.1']);
@ -282,25 +298,41 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
// Test integer argument.
$arr[MAX_UINT64] = MAX_UINT64;
$this->assertEquals(MAX_UINT64, $arr[MAX_UINT64]);
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_UINT64_STRING, $arr[MAX_UINT64_STRING]);
} else {
$this->assertSame(MAX_UINT64, $arr[MAX_UINT64]);
}
$this->assertEquals(1, count($arr));
unset($arr[MAX_UINT64]);
$this->assertEquals(0, count($arr));
// Test float argument.
$arr[1.1] = 1.1;
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $arr['1']);
} else {
$this->assertSame(1, $arr[1]);
}
$this->assertEquals(1, count($arr));
unset($arr[1.1]);
$this->assertEquals(0, count($arr));
// Test string argument.
$arr['2'] = '2';
$this->assertSame(2, $arr[2]);
$arr['3.1'] = '3.1';
$this->assertSame(3, $arr[3]);
$arr[MAX_UINT64_STRING] = MAX_UINT64_STRING;
$this->assertEquals(MAX_UINT64, $arr[MAX_UINT64]);
if (PHP_INT_SIZE == 4) {
$this->assertSame('2', $arr['2']);
$this->assertSame('3', $arr['3']);
$this->assertSame(MAX_UINT64_STRING, $arr[MAX_UINT64_STRING]);
} else {
$this->assertSame(2, $arr[2]);
$this->assertSame(3, $arr[3]);
$this->assertSame(MAX_UINT64, $arr[MAX_UINT64]);
}
$this->assertEquals(3, count($arr));
unset($arr['2']);
unset($arr['3.1']);

@ -9,14 +9,10 @@ use Foo\TestMessage_Sub;
use Foo\TestPackedMessage;
use Google\Protobuf\Internal\InputStream;
use Google\Protobuf\Internal\FileDescriptorSet;
use Google\Protobuf\Internal\GPBUtil;
use Google\Protobuf\Internal\Int64;
use Google\Protobuf\Internal\Uint64;
use Google\Protobuf\Internal\GPBLabel;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\GPBWire;
use Google\Protobuf\Internal\OutputStream;
use Google\Protobuf\Internal\RepeatedField;
class ImplementationTest extends TestBase
{
@ -68,17 +64,17 @@ class ImplementationTest extends TestBase
// Positive number.
$input = new InputStream(hex2bin("01"));
GPBWire::readInt64($input, $value);
$this->assertSame(1, $value->toInteger());
$this->assertEquals(1, $value);
// Negative number.
$input = new InputStream(hex2bin("ffffffffffffffffff01"));
GPBWire::readInt64($input, $value);
$this->assertSame(-1, $value->toInteger());
$this->assertEquals(-1, $value);
// Discard overflow bits.
$input = new InputStream(hex2bin("ffffffffffffffffff0f"));
GPBWire::readInt64($input, $value);
$this->assertSame(-1, $value->toInteger());
$this->assertEquals(-1, $value);
}
public function testReadUint64()
@ -88,17 +84,17 @@ class ImplementationTest extends TestBase
// Positive number.
$input = new InputStream(hex2bin("01"));
GPBWire::readUint64($input, $value);
$this->assertSame(1, $value->toInteger());
$this->assertEquals(1, $value);
// Negative number.
$input = new InputStream(hex2bin("FFFFFFFFFFFFFFFFFF01"));
GPBWire::readUint64($input, $value);
$this->assertSame(-1, $value->toInteger());
$this->assertEquals(-1, $value);
// Discard overflow bits.
$input = new InputStream(hex2bin("FFFFFFFFFFFFFFFFFF0F"));
GPBWire::readUint64($input, $value);
$this->assertSame(-1, $value->toInteger());
$this->assertEquals(-1, $value);
}
public function testReadSint32()
@ -124,15 +120,15 @@ class ImplementationTest extends TestBase
$input = new InputStream(hex2bin("00"));
GPBWire::readSint64($input, $value);
$this->assertEquals(GPBUtil::Int64(0), $value);
$this->assertEquals(0, $value);
$input = new InputStream(hex2bin("01"));
GPBWire::readSint64($input, $value);
$this->assertEquals(GPBUtil::Int64(-1), $value);
$this->assertEquals(-1, $value);
$input = new InputStream(hex2bin("02"));
GPBWire::readSint64($input, $value);
$this->assertEquals(GPBUtil::Int64(1), $value);
$this->assertEquals(1, $value);
}
public function testReadFixed32()
@ -148,7 +144,11 @@ class ImplementationTest extends TestBase
$value = null;
$input = new InputStream(hex2bin("1234567812345678"));
GPBWire::readFixed64($input, $value);
$this->assertEquals(Uint64::newValue(0x78563412, 0x78563412), $value);
if (PHP_INT_SIZE == 4) {
$this->assertSame("8671175386481439762", $value);
} else {
$this->assertSame(0x7856341278563412, $value);
}
}
public function testReadSfixed32()
@ -193,7 +193,11 @@ class ImplementationTest extends TestBase
$value = null;
$input = new InputStream(hex2bin("1234567812345678"));
GPBWire::readSfixed64($input, $value);
$this->assertEquals(Int64::newValue(0x78563412, 0x78563412), $value);
if (PHP_INT_SIZE == 4) {
$this->assertSame("8671175386481439762", $value);
} else {
$this->assertSame(0x7856341278563412, $value);
}
}
public function testZigZagEncodeDecode()
@ -214,43 +218,65 @@ class ImplementationTest extends TestBase
$this->assertSame(0x3FFFFFFF, GPBWire::zigZagDecode32(0x7FFFFFFE));
$this->assertSame(-1073741824, GPBWire::zigZagDecode32(0x7FFFFFFF));
$this->assertSame(0x7FFFFFFF, GPBWire::zigZagDecode32(0xFFFFFFFE));
$this->assertSame(-2147483648, GPBWire::zigZagDecode32(0xFFFFFFFF));
$this->assertEquals(GPBUtil::Uint64(0),
GPBWire::zigZagEncode64(GPBUtil::Int64(0)));
$this->assertEquals(GPBUtil::Uint64(1),
GPBWire::zigZagEncode64(GPBUtil::Int64(-1)));
$this->assertEquals(GPBUtil::Uint64(2),
GPBWire::zigZagEncode64(GPBUtil::Int64(1)));
$this->assertEquals(GPBUtil::Uint64(3),
GPBWire::zigZagEncode64(GPBUtil::Int64(-2)));
$this->assertEquals(
GPBUtil::Uint64(0x000000007FFFFFFE),
GPBWire::zigZagEncode64(GPBUtil::Int64(0x000000003FFFFFFF)));
$this->assertEquals(
GPBUtil::Uint64(0x000000007FFFFFFF),
GPBWire::zigZagEncode64(GPBUtil::Int64(0xFFFFFFFFC0000000)));
$this->assertEquals(
GPBUtil::Uint64(0x00000000FFFFFFFE),
GPBWire::zigZagEncode64(GPBUtil::Int64(0x000000007FFFFFFF)));
$this->assertEquals(
GPBUtil::Uint64(0x00000000FFFFFFFF),
GPBWire::zigZagEncode64(GPBUtil::Int64(0xFFFFFFFF80000000)));
$this->assertEquals(
Uint64::newValue(4294967295, 4294967294),
GPBWire::zigZagEncode64(GPBUtil::Int64(0x7FFFFFFFFFFFFFFF)));
$this->assertEquals(
Uint64::newValue(4294967295, 4294967295),
GPBWire::zigZagEncode64(GPBUtil::Int64(0x8000000000000000)));
$this->assertEquals(GPBUtil::Int64(0),
GPBWire::zigZagDecode64(GPBUtil::Uint64(0)));
$this->assertEquals(GPBUtil::Int64(-1),
GPBWire::zigZagDecode64(GPBUtil::Uint64(1)));
$this->assertEquals(GPBUtil::Int64(1),
GPBWire::zigZagDecode64(GPBUtil::Uint64(2)));
$this->assertEquals(GPBUtil::Int64(-2),
GPBWire::zigZagDecode64(GPBUtil::Uint64(3)));
$this->assertSame((int)-2147483648,GPBWire::zigZagDecode32(0xFFFFFFFF));
if (PHP_INT_SIZE == 4) {
$this->assertSame('0', GPBWire::zigZagEncode64(0));
$this->assertSame('1', GPBWire::zigZagEncode64(-1));
$this->assertSame('2', GPBWire::zigZagEncode64(1));
$this->assertSame('3', GPBWire::zigZagEncode64(-2));
$this->assertSame(
'2147483646', // 0x7FFFFFE
GPBWire::zigZagEncode64(0x3FFFFFFF));
$this->assertSame(
'2147483647', // 0x7FFFFFF
GPBWire::zigZagEncode64(-1073741824)); // 0xFFFFFFFFC0000000
$this->assertSame(
'4294967294', // 0xFFFFFFFE
GPBWire::zigZagEncode64(2147483647)); // 0x7FFFFFFF
$this->assertSame(
'4294967295', // 0xFFFFFFFF
GPBWire::zigZagEncode64(-2147483648)); // 0xFFFFFFFF80000000
$this->assertSame(
'18446744073709551614', // 0xFFFFFFFFFFFFFFFE
// 0x7FFFFFFFFFFFFFFF
GPBWire::zigZagEncode64("9223372036854775807"));
$this->assertSame(
'18446744073709551615', // 0xFFFFFFFFFFFFFFFF
// 0x8000000000000000
GPBWire::zigZagEncode64("-9223372036854775808"));
$this->assertSame('0', GPBWire::zigZagDecode64(0));
$this->assertSame('-1', GPBWire::zigZagDecode64(1));
$this->assertSame('1', GPBWire::zigZagDecode64(2));
$this->assertSame('-2', GPBWire::zigZagDecode64(3));
} else {
$this->assertSame(0, GPBWire::zigZagEncode64(0));
$this->assertSame(1, GPBWire::zigZagEncode64(-1));
$this->assertSame(2, GPBWire::zigZagEncode64(1));
$this->assertSame(3, GPBWire::zigZagEncode64(-2));
$this->assertSame(0x7FFFFFFE, GPBWire::zigZagEncode64(0x3FFFFFFF));
$this->assertSame(
0x7FFFFFFF,
GPBWire::zigZagEncode64(0xFFFFFFFFC0000000));
$this->assertSame(
0xFFFFFFFE,
GPBWire::zigZagEncode64(0x7FFFFFFF));
$this->assertSame(
0xFFFFFFFF,
GPBWire::zigZagEncode64(0xFFFFFFFF80000000));
$this->assertSame(
-2, // 0xFFFFFFFFFFFFFFFE
GPBWire::zigZagEncode64(0x7FFFFFFFFFFFFFFF));
$this->assertSame(
-1, // 0xFFFFFFFFFFFFFFFF
GPBWire::zigZagEncode64(0x8000000000000000));
$this->assertSame(0, GPBWire::zigZagDecode64(0));
$this->assertSame(-1, GPBWire::zigZagDecode64(1));
$this->assertSame(1, GPBWire::zigZagDecode64(2));
$this->assertSame(-2, GPBWire::zigZagDecode64(3));
}
// Round trip
$this->assertSame(0, GPBWire::zigZagDecode32(GPBWire::zigZagEncode32(0)));
@ -319,15 +345,27 @@ class ImplementationTest extends TestBase
// Normal case.
$input = new InputStream(hex2bin('808001'));
$this->assertTrue($input->readVarint64($var));
$this->assertSame(16384, $var->toInteger());
if (PHP_INT_SIZE == 4) {
$this->assertSame('16384', $var);
} else {
$this->assertSame(16384, $var);
}
$this->assertFalse($input->readVarint64($var));
// Read two varint.
$input = new InputStream(hex2bin('808001808002'));
$this->assertTrue($input->readVarint64($var));
$this->assertSame(16384, $var->toInteger());
if (PHP_INT_SIZE == 4) {
$this->assertSame('16384', $var);
} else {
$this->assertSame(16384, $var);
}
$this->assertTrue($input->readVarint64($var));
$this->assertSame(32768, $var->toInteger());
if (PHP_INT_SIZE == 4) {
$this->assertSame('32768', $var);
} else {
$this->assertSame(32768, $var);
}
$this->assertFalse($input->readVarint64($var));
}

@ -7,10 +7,11 @@
pushd ../ext/google/protobuf/
make clean
set -e
phpize && ./configure --enable-debug CFLAGS='-g -O0' && make
# Add following in configure for debug: --enable-debug CFLAGS='-g -O0'
phpize && ./configure && make
popd
tests=( array_test.php encode_decode_test.php generated_class_test.php map_field_test.php )
tests=( array_test.php encode_decode_test.php generated_class_test.php map_field_test.php well_known_test.php )
for t in "${tests[@]}"
do

@ -13,22 +13,28 @@ class TestBase extends PHPUnit_Framework_TestCase
public function expectFields(TestMessage $m)
{
$this->assertSame(-42, $m->getOptionalInt32());
$this->assertSame(42, $m->getOptionalUint32());
$this->assertSame(-43, $m->getOptionalInt64());
$this->assertSame(43, $m->getOptionalUint64());
$this->assertSame(-44, $m->getOptionalSint32());
$this->assertSame(-45, $m->getOptionalSint64());
$this->assertSame(46, $m->getOptionalFixed32());
$this->assertSame(47, $m->getOptionalFixed64());
$this->assertSame(-46, $m->getOptionalSfixed32());
$this->assertSame(-47, $m->getOptionalSfixed64());
$this->assertSame(1.5, $m->getOptionalFloat());
$this->assertSame(1.6, $m->getOptionalDouble());
$this->assertSame(true, $m->getOptionalBool());
$this->assertSame('a', $m->getOptionalString());
$this->assertSame('b', $m->getOptionalBytes());
$this->assertSame(33, $m->getOptionalMessage()->getA());
if (PHP_INT_SIZE == 4) {
$this->assertSame('-43', $m->getOptionalInt64());
$this->assertSame('43', $m->getOptionalUint64());
$this->assertSame('-45', $m->getOptionalSint64());
$this->assertSame('47', $m->getOptionalFixed64());
$this->assertSame('-47', $m->getOptionalSfixed64());
} else {
$this->assertSame(-43, $m->getOptionalInt64());
$this->assertSame(43, $m->getOptionalUint64());
$this->assertSame(-45, $m->getOptionalSint64());
$this->assertSame(47, $m->getOptionalFixed64());
$this->assertSame(-47, $m->getOptionalSfixed64());
}
$this->assertEquals(-42, $m->getRepeatedInt32()[0]);
$this->assertEquals(42, $m->getRepeatedUint32()[0]);
@ -69,20 +75,28 @@ class TestBase extends PHPUnit_Framework_TestCase
{
$this->assertSame(0, $m->getOptionalInt32());
$this->assertSame(0, $m->getOptionalUint32());
$this->assertSame(0, $m->getOptionalInt64());
$this->assertSame(0, $m->getOptionalUint64());
$this->assertSame(0, $m->getOptionalSint32());
$this->assertSame(0, $m->getOptionalSint64());
$this->assertSame(0, $m->getOptionalFixed32());
$this->assertSame(0, $m->getOptionalFixed64());
$this->assertSame(0, $m->getOptionalSfixed32());
$this->assertSame(0, $m->getOptionalSfixed64());
$this->assertSame(0.0, $m->getOptionalFloat());
$this->assertSame(0.0, $m->getOptionalDouble());
$this->assertSame(false, $m->getOptionalBool());
$this->assertSame('', $m->getOptionalString());
$this->assertSame('', $m->getOptionalBytes());
$this->assertNull($m->getOptionalMessage());
if (PHP_INT_SIZE == 4) {
$this->assertSame("0", $m->getOptionalInt64());
$this->assertSame("0", $m->getOptionalUint64());
$this->assertSame("0", $m->getOptionalSint64());
$this->assertSame("0", $m->getOptionalFixed64());
$this->assertSame("0", $m->getOptionalSfixed64());
} else {
$this->assertSame(0, $m->getOptionalInt64());
$this->assertSame(0, $m->getOptionalUint64());
$this->assertSame(0, $m->getOptionalSint64());
$this->assertSame(0, $m->getOptionalFixed64());
$this->assertSame(0, $m->getOptionalSfixed64());
}
}
// This test is to avoid the warning of no test by php unit.

@ -0,0 +1,34 @@
<?php
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: test_no_namespace.proto
use Google\Protobuf\Internal\DescriptorPool;
use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;
class NoNameSpace extends \Google\Protobuf\Internal\Message
{
private $a = 0;
public function getA()
{
return $this->a;
}
public function setA($var)
{
GPBUtil::checkInt32($var);
$this->a = $var;
}
}
$pool = DescriptorPool::getGeneratedPool();
$pool->internalAddGeneratedFile(hex2bin(
"0a3b0a17746573745f6e6f5f6e616d6573706163652e70726f746f22180a" .
"0b4e6f4e616d65537061636512090a0161180120012805620670726f746f" .
"33"
));

@ -0,0 +1,5 @@
syntax = "proto3";
message NoNameSpace {
int32 a = 1;
}

@ -20,7 +20,7 @@ define('MAX_INT32', 2147483647);
define('MAX_INT32_FLOAT', 2147483647.0);
define('MAX_INT32_STRING', '2147483647');
define('MIN_INT32', -2147483648);
define('MIN_INT32', (int)-2147483648);
define('MIN_INT32_FLOAT', -2147483648.0);
define('MIN_INT32_STRING', '-2147483648');
@ -28,22 +28,23 @@ define('MAX_UINT32', 4294967295);
define('MAX_UINT32_FLOAT', 4294967295.0);
define('MAX_UINT32_STRING', '4294967295');
define('MIN_UINT32', -2147483648);
define('MIN_UINT32', (int)-2147483648);
define('MIN_UINT32_FLOAT', -2147483648.0);
define('MIN_UINT32_STRING', '-2147483648');
define('MAX_INT64', 9223372036854775807);
define('MAX_INT64_STRING', '9223372036854775807');
define('MIN_INT64_STRING', '-9223372036854775808');
define('MAX_UINT64_STRING', '-9223372036854775808');
if (PHP_INT_SIZE === 8) {
define('MIN_INT64', -9223372036854775808);
define('MAX_INT64', (int)9223372036854775807);
define('MIN_INT64', (int)-9223372036854775808);
define('MAX_UINT64', (int)-9223372036854775808);
} else {
define('MAX_INT64', MAX_INT64_STRING);
define('MIN_INT64', MIN_INT64_STRING);
}
define('MAX_UINT64_STRING', '-9223372036854775808');
define('MAX_UINT64', MAX_UINT64_STRING);
}
class TestUtil
{
@ -129,16 +130,24 @@ class TestUtil
public static function assertTestMessage(TestMessage $m)
{
assert(-42 === $m->getOptionalInt32());
assert(42 === $m->getOptionalUint32());
if (PHP_INT_SIZE == 4) {
assert('-43' === $m->getOptionalInt64());
assert('43' === $m->getOptionalUint64());
assert('-45' === $m->getOptionalSint64());
assert('47' === $m->getOptionalFixed64());
assert('-47' === $m->getOptionalSfixed64());
} else {
assert(-43 === $m->getOptionalInt64());
assert(43 === $m->getOptionalUint64());
assert(-44 === $m->getOptionalSint32());
assert(-45 === $m->getOptionalSint64());
assert(46 === $m->getOptionalFixed32());
assert(47 === $m->getOptionalFixed64());
assert(-46 === $m->getOptionalSfixed32());
assert(-47 === $m->getOptionalSfixed64());
}
assert(-42 === $m->getOptionalInt32());
assert(42 === $m->getOptionalUint32());
assert(-44 === $m->getOptionalSint32());
assert(46 === $m->getOptionalFixed32());
assert(-46 === $m->getOptionalSfixed32());
assert(1.5 === $m->getOptionalFloat());
assert(1.6 === $m->getOptionalDouble());
assert(true=== $m->getOptionalBool());
@ -147,16 +156,24 @@ class TestUtil
assert(TestEnum::ONE === $m->getOptionalEnum());
assert(33 === $m->getOptionalMessage()->getA());
assert(-42 === $m->getRepeatedInt32()[0]);
assert(42 === $m->getRepeatedUint32()[0]);
if (PHP_INT_SIZE == 4) {
assert('-43' === $m->getRepeatedInt64()[0]);
assert('43' === $m->getRepeatedUint64()[0]);
assert('-45' === $m->getRepeatedSint64()[0]);
assert('47' === $m->getRepeatedFixed64()[0]);
assert('-47' === $m->getRepeatedSfixed64()[0]);
} else {
assert(-43 === $m->getRepeatedInt64()[0]);
assert(43 === $m->getRepeatedUint64()[0]);
assert(-44 === $m->getRepeatedSint32()[0]);
assert(-45 === $m->getRepeatedSint64()[0]);
assert(46 === $m->getRepeatedFixed32()[0]);
assert(47 === $m->getRepeatedFixed64()[0]);
assert(-46 === $m->getRepeatedSfixed32()[0]);
assert(-47 === $m->getRepeatedSfixed64()[0]);
}
assert(-42 === $m->getRepeatedInt32()[0]);
assert(42 === $m->getRepeatedUint32()[0]);
assert(-44 === $m->getRepeatedSint32()[0]);
assert(46 === $m->getRepeatedFixed32()[0]);
assert(-46 === $m->getRepeatedSfixed32()[0]);
assert(1.5 === $m->getRepeatedFloat()[0]);
assert(1.6 === $m->getRepeatedDouble()[0]);
assert(true=== $m->getRepeatedBool()[0]);
@ -165,16 +182,24 @@ class TestUtil
assert(TestEnum::ZERO === $m->getRepeatedEnum()[0]);
assert(34 === $m->getRepeatedMessage()[0]->getA());
assert(-52 === $m->getRepeatedInt32()[1]);
assert(52 === $m->getRepeatedUint32()[1]);
if (PHP_INT_SIZE == 4) {
assert('-53' === $m->getRepeatedInt64()[1]);
assert('53' === $m->getRepeatedUint64()[1]);
assert('-55' === $m->getRepeatedSint64()[1]);
assert('57' === $m->getRepeatedFixed64()[1]);
assert('-57' === $m->getRepeatedSfixed64()[1]);
} else {
assert(-53 === $m->getRepeatedInt64()[1]);
assert(53 === $m->getRepeatedUint64()[1]);
assert(-54 === $m->getRepeatedSint32()[1]);
assert(-55 === $m->getRepeatedSint64()[1]);
assert(56 === $m->getRepeatedFixed32()[1]);
assert(57 === $m->getRepeatedFixed64()[1]);
assert(-56 === $m->getRepeatedSfixed32()[1]);
assert(-57 === $m->getRepeatedSfixed64()[1]);
}
assert(-52 === $m->getRepeatedInt32()[1]);
assert(52 === $m->getRepeatedUint32()[1]);
assert(-54 === $m->getRepeatedSint32()[1]);
assert(56 === $m->getRepeatedFixed32()[1]);
assert(-56 === $m->getRepeatedSfixed32()[1]);
assert(2.5 === $m->getRepeatedFloat()[1]);
assert(2.6 === $m->getRepeatedDouble()[1]);
assert(false === $m->getRepeatedBool()[1]);
@ -183,14 +208,21 @@ class TestUtil
assert(TestEnum::ONE === $m->getRepeatedEnum()[1]);
assert(35 === $m->getRepeatedMessage()[1]->getA());
assert(-62 === $m->getMapInt32Int32()[-62]);
if (PHP_INT_SIZE == 4) {
assert('-63' === $m->getMapInt64Int64()['-63']);
assert('63' === $m->getMapUint64Uint64()['63']);
assert('-65' === $m->getMapSint64Sint64()['-65']);
assert('67' === $m->getMapFixed64Fixed64()['67']);
} else {
assert(-63 === $m->getMapInt64Int64()[-63]);
assert(62 === $m->getMapUint32Uint32()[62]);
assert(63 === $m->getMapUint64Uint64()[63]);
assert(-64 === $m->getMapSint32Sint32()[-64]);
assert(-65 === $m->getMapSint64Sint64()[-65]);
assert(66 === $m->getMapFixed32Fixed32()[66]);
assert(67 === $m->getMapFixed64Fixed64()[67]);
}
assert(-62 === $m->getMapInt32Int32()[-62]);
assert(62 === $m->getMapUint32Uint32()[62]);
assert(-64 === $m->getMapSint32Sint32()[-64]);
assert(66 === $m->getMapFixed32Fixed32()[66]);
assert(3.5 === $m->getMapInt32Float()[1]);
assert(3.6 === $m->getMapInt32Double()[1]);
assert(true === $m->getMapBoolBool()[true]);
@ -325,24 +357,14 @@ class TestUtil
assert(-42 === $m->getRepeatedInt32()[0]);
assert(-52 === $m->getRepeatedInt32()[1]);
assert(-43 === $m->getRepeatedInt64()[0]);
assert(-53 === $m->getRepeatedInt64()[1]);
assert(42 === $m->getRepeatedUint32()[0]);
assert(52 === $m->getRepeatedUint32()[1]);
assert(43 === $m->getRepeatedUint64()[0]);
assert(53 === $m->getRepeatedUint64()[1]);
assert(-44 === $m->getRepeatedSint32()[0]);
assert(-54 === $m->getRepeatedSint32()[1]);
assert(-45 === $m->getRepeatedSint64()[0]);
assert(-55 === $m->getRepeatedSint64()[1]);
assert(46 === $m->getRepeatedFixed32()[0]);
assert(56 === $m->getRepeatedFixed32()[1]);
assert(47 === $m->getRepeatedFixed64()[0]);
assert(57 === $m->getRepeatedFixed64()[1]);
assert(-46 === $m->getRepeatedSfixed32()[0]);
assert(-56 === $m->getRepeatedSfixed32()[1]);
assert(-47 === $m->getRepeatedSfixed64()[0]);
assert(-57 === $m->getRepeatedSfixed64()[1]);
assert(1.5 === $m->getRepeatedFloat()[0]);
assert(2.5 === $m->getRepeatedFloat()[1]);
assert(1.6 === $m->getRepeatedDouble()[0]);
@ -351,6 +373,29 @@ class TestUtil
assert(false === $m->getRepeatedBool()[1]);
assert(TestEnum::ONE === $m->getRepeatedEnum()[0]);
assert(TestEnum::ZERO === $m->getRepeatedEnum()[1]);
if (PHP_INT_SIZE == 4) {
assert('-43' === $m->getRepeatedInt64()[0]);
assert('-53' === $m->getRepeatedInt64()[1]);
assert('43' === $m->getRepeatedUint64()[0]);
assert('53' === $m->getRepeatedUint64()[1]);
assert('-45' === $m->getRepeatedSint64()[0]);
assert('-55' === $m->getRepeatedSint64()[1]);
assert('47' === $m->getRepeatedFixed64()[0]);
assert('57' === $m->getRepeatedFixed64()[1]);
assert('-47' === $m->getRepeatedSfixed64()[0]);
assert('-57' === $m->getRepeatedSfixed64()[1]);
} else {
assert(-43 === $m->getRepeatedInt64()[0]);
assert(-53 === $m->getRepeatedInt64()[1]);
assert(43 === $m->getRepeatedUint64()[0]);
assert(53 === $m->getRepeatedUint64()[1]);
assert(-45 === $m->getRepeatedSint64()[0]);
assert(-55 === $m->getRepeatedSint64()[1]);
assert(47 === $m->getRepeatedFixed64()[0]);
assert(57 === $m->getRepeatedFixed64()[1]);
assert(-47 === $m->getRepeatedSfixed64()[0]);
assert(-57 === $m->getRepeatedSfixed64()[1]);
}
}
public static function getGoldenTestPackedMessage()

@ -0,0 +1,13 @@
<?php
require_once("google/protobuf/empty.pb.php");
use Google\Protobuf\GPBEmpty;
class WellKnownTest extends PHPUnit_Framework_TestCase {
public function testNone() {
$msg = new GPBEmpty();
}
}

@ -8,6 +8,7 @@
<file>php/tests/encode_decode_test.php</file>
<file>php/tests/generated_class_test.php</file>
<file>php/tests/map_field_test.php</file>
<file>php/tests/well_known_test.php</file>
</testsuite>
</testsuites>
</phpunit>

@ -13,14 +13,21 @@ def _GenDir(ctx):
return _GetPath(ctx, ctx.attr.includes[0])
return _GetPath(ctx, ctx.label.package + '/' + ctx.attr.includes[0])
def _CcOuts(srcs, use_grpc_plugin=False):
ret = [s[:-len(".proto")] + ".pb.h" for s in srcs] + \
[s[:-len(".proto")] + ".pb.cc" for s in srcs]
def _CcHdrs(srcs, use_grpc_plugin=False):
ret = [s[:-len(".proto")] + ".pb.h" for s in srcs]
if use_grpc_plugin:
ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs]
return ret
def _CcSrcs(srcs, use_grpc_plugin=False):
ret = [s[:-len(".proto")] + ".pb.cc" for s in srcs]
if use_grpc_plugin:
ret += [s[:-len(".proto")] + ".grpc.pb.h" for s in srcs] + \
[s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
ret += [s[:-len(".proto")] + ".grpc.pb.cc" for s in srcs]
return ret
def _CcOuts(srcs, use_grpc_plugin=False):
return _CcHdrs(srcs, use_grpc_plugin) + _CcSrcs(srcs, use_grpc_plugin)
def _PyOuts(srcs):
return [s[:-len(".proto")] + "_pb2.py" for s in srcs]
@ -201,7 +208,9 @@ def cc_proto_library(
if use_grpc_plugin:
grpc_cpp_plugin = "//external:grpc_cpp_plugin"
outs = _CcOuts(srcs, use_grpc_plugin)
gen_srcs = _CcSrcs(srcs, use_grpc_plugin)
gen_hdrs = _CcHdrs(srcs, use_grpc_plugin)
outs = gen_srcs + gen_hdrs
proto_gen(
name=name + "_genproto",
@ -223,7 +232,8 @@ def cc_proto_library(
native.cc_library(
name=name,
srcs=outs,
srcs=gen_srcs,
hdrs=gen_hdrs,
deps=cc_libs + deps,
includes=includes,
**kargs)

@ -92,7 +92,7 @@ Installation
error: "sem_init: Resource temporarily unavailable". This appears
to be a bug either in Cygwin or in Python:
http://www.cygwin.com/ml/cygwin/2005-07/msg01378.html
We do not know if or when it might me fixed. We also do not know
We do not know if or when it might be fixed. We also do not know
how likely it is that this bug will affect users in practice.
5) Install:

@ -1994,7 +1994,11 @@ static PyObject* CopyFrom(CMessage* self, PyObject* arg) {
// get OOM errors. The protobuf APIs do not provide any tools for processing
// protobufs in chunks. If you have protos this big you should break them up if
// it is at all convenient to do so.
#ifdef PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS
static bool allow_oversize_protos = true;
#else
static bool allow_oversize_protos = false;
#endif
// Provide a method in the module to set allow_oversize_protos to a boolean
// value. This method returns the newly value of allow_oversize_protos.

@ -178,6 +178,45 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) {
}
}
VALUE Message_respond_to_missing(int argc, VALUE* argv, VALUE _self) {
MessageHeader* self;
VALUE method_name, method_str;
char* name;
size_t name_len;
bool setter;
const upb_oneofdef* o;
const upb_fielddef* f;
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
if (argc < 1) {
rb_raise(rb_eArgError, "Expected method name as first argument.");
}
method_name = argv[0];
if (!SYMBOL_P(method_name)) {
rb_raise(rb_eArgError, "Expected symbol as method name.");
}
method_str = rb_id2str(SYM2ID(method_name));
name = RSTRING_PTR(method_str);
name_len = RSTRING_LEN(method_str);
setter = false;
// Setters have names that end in '='.
if (name[name_len - 1] == '=') {
setter = true;
name_len--;
}
// See if this name corresponds to either a oneof or field in this message.
if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f,
&o)) {
return rb_call_super(argc, argv);
}
if (o != NULL) {
return setter ? Qfalse : Qtrue;
}
return Qtrue;
}
int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
MessageHeader* self;
VALUE method_str;
@ -305,6 +344,9 @@ VALUE Message_deep_copy(VALUE _self) {
VALUE Message_eq(VALUE _self, VALUE _other) {
MessageHeader* self;
MessageHeader* other;
if (TYPE(_self) != TYPE(_other)) {
return Qfalse;
}
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
TypedData_Get_Struct(_other, MessageHeader, &Message_type, other);
@ -459,6 +501,8 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
rb_define_method(klass, "method_missing",
Message_method_missing, -1);
rb_define_method(klass, "respond_to_missing?",
Message_respond_to_missing, -1);
rb_define_method(klass, "initialize", Message_initialize, -1);
rb_define_method(klass, "dup", Message_dup, 0);
// Also define #clone so that we don't inherit Object#clone.

@ -1181,5 +1181,15 @@ module BasicTest
m2 = MapMessage.decode_json(MapMessage.encode_json(m))
assert m == m2
end
def test_comparison_with_arbitrary_object
assert_false MapMessage.new == nil
end
def test_respond_to
msg = MapMessage.new
assert msg.respond_to?(:map_string_int32)
assert_false msg.respond_to?(:bacon)
end
end
end

@ -10,12 +10,14 @@ test_version() {
bash --login -c \
"rvm install $version && rvm use $version && rvm get head && \
which ruby && \
git clean -f && \
gem install bundler && bundle && \
rake test"
else
bash --login -c \
"rvm install $version && rvm use $version && \
which ruby && \
git clean -f && \
gem install bundler && bundle && \
rake test &&
cd ../conformance && make test_ruby"

@ -70,10 +70,10 @@ nobase_include_HEADERS = \
google/protobuf/stubs/atomicops_internals_arm_gcc.h \
google/protobuf/stubs/atomicops_internals_arm_qnx.h \
google/protobuf/stubs/atomicops_internals_atomicword_compat.h \
google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h \
google/protobuf/stubs/atomicops_internals_generic_gcc.h \
google/protobuf/stubs/atomicops_internals_macosx.h \
google/protobuf/stubs/atomicops_internals_mips_gcc.h \
google/protobuf/stubs/atomicops_internals_pnacl.h \
google/protobuf/stubs/atomicops_internals_solaris.h \
google/protobuf/stubs/atomicops_internals_tsan.h \
google/protobuf/stubs/atomicops_internals_x86_gcc.h \

@ -83,6 +83,7 @@ inline void arena_free(void* object, size_t size) {
#if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
::operator delete(object, size);
#else
(void)size;
::operator delete(object);
#endif
}

@ -263,6 +263,12 @@ void AddDefaultProtoPaths(vector<pair<string, string> >* paths) {
return;
}
}
string PluginName(const string& plugin_prefix, const string& directive) {
// Assuming the directive starts with "--" and ends with "_out" or "_opt",
// strip the "--" and "_out/_opt" and add the plugin prefix.
return plugin_prefix + "gen-" + directive.substr(2, directive.size() - 6);
}
} // namespace
// A MultiFileErrorCollector that prints errors to stderr.
@ -1008,6 +1014,18 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
return status;
}
// Make sure each plugin option has a matching plugin output.
for (map<string, string>::const_iterator i = plugin_parameters_.begin();
i != plugin_parameters_.end(); ++i) {
if (plugins_.find(i->first) == plugins_.end()) {
std::cerr << "Unknown flag: "
// strip prefix + "gen-" and add back "_opt"
<< "--" + i->first.substr(plugin_prefix_.size() + 4) + "_opt"
<< std::endl;
return PARSE_ARGUMENT_FAIL;
}
}
// If no --proto_path was given, use the current working directory.
if (proto_path_.empty()) {
// Don't use make_pair as the old/default standard library on Solaris
@ -1338,15 +1356,22 @@ CommandLineInterface::InterpretArgument(const string& name,
(plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
// Check if it's a generator option flag.
generator_info = FindOrNull(generators_by_option_name_, name);
if (generator_info == NULL) {
std::cerr << "Unknown flag: " << name << std::endl;
return PARSE_ARGUMENT_FAIL;
} else {
if (generator_info != NULL) {
string* parameters = &generator_parameters_[generator_info->flag_name];
if (!parameters->empty()) {
parameters->append(",");
}
parameters->append(value);
} else if (HasPrefixString(name, "--") && HasSuffixString(name, "_opt")) {
string* parameters =
&plugin_parameters_[PluginName(plugin_prefix_, name)];
if (!parameters->empty()) {
parameters->append(",");
}
parameters->append(value);
} else {
std::cerr << "Unknown flag: " << name << std::endl;
return PARSE_ARGUMENT_FAIL;
}
} else {
// It's an output flag. Add it to the output directives.
@ -1465,12 +1490,16 @@ bool CommandLineInterface::GenerateOutput(
HasSuffixString(output_directive.name, "_out"))
<< "Bad name for plugin generator: " << output_directive.name;
// Strip the "--" and "_out" and add the plugin prefix.
string plugin_name = plugin_prefix_ + "gen-" +
output_directive.name.substr(2, output_directive.name.size() - 6);
string plugin_name = PluginName(plugin_prefix_ , output_directive.name);
string parameters = output_directive.parameter;
if (!plugin_parameters_[plugin_name].empty()) {
if (!parameters.empty()) {
parameters.append(",");
}
parameters.append(plugin_parameters_[plugin_name]);
}
if (!GeneratePluginOutput(parsed_files, plugin_name,
output_directive.parameter,
parameters,
generator_context, &error)) {
std::cerr << output_directive.name << ": " << error << std::endl;
return false;

@ -144,14 +144,14 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS
// --out indicates the output directory (as passed to the --foo_out
// parameter); if omitted, the current directory should be used. --parameter
// gives the generator parameter, if any was provided. The PROTO_FILES list
// the .proto files which were given on the compiler command-line; these are
// the files for which the plugin is expected to generate output code.
// Finally, DESCRIPTORS is an encoded FileDescriptorSet (as defined in
// descriptor.proto). This is piped to the plugin's stdin. The set will
// include descriptors for all the files listed in PROTO_FILES as well as
// all files that they import. The plugin MUST NOT attempt to read the
// PROTO_FILES directly -- it must use the FileDescriptorSet.
// gives the generator parameter, if any was provided (see below). The
// PROTO_FILES list the .proto files which were given on the compiler
// command-line; these are the files for which the plugin is expected to
// generate output code. Finally, DESCRIPTORS is an encoded FileDescriptorSet
// (as defined in descriptor.proto). This is piped to the plugin's stdin.
// The set will include descriptors for all the files listed in PROTO_FILES as
// well as all files that they import. The plugin MUST NOT attempt to read
// the PROTO_FILES directly -- it must use the FileDescriptorSet.
//
// The plugin should generate whatever files are necessary, as code generators
// normally do. It should write the names of all files it generates to
@ -159,6 +159,13 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// names or relative to the current directory. If any errors occur, error
// messages should be written to stderr. If an error is fatal, the plugin
// should exit with a non-zero exit code.
//
// Plugins can have generator parameters similar to normal built-in
// generators. Extra generator parameters can be passed in via a matching
// "_opt" parameter. For example:
// protoc --plug_out=enable_bar:outdir --plug_opt=enable_baz
// This will pass "enable_bar,enable_baz" as the parameter to the plugin.
//
void AllowPlugins(const string& exe_name_prefix);
// Run the Protocol Compiler with the given command-line parameters.
@ -314,6 +321,8 @@ class LIBPROTOC_EXPORT CommandLineInterface {
// protoc --foo_out=outputdir --foo_opt=enable_bar ...
// Then there will be an entry ("--foo_out", "enable_bar") in this map.
std::map<string, string> generator_parameters_;
// Similar to generator_parameters_, but stores the parameters for plugins.
std::map<string, string> plugin_parameters_;
// See AllowPlugins(). If this is empty, plugins aren't allowed.
string plugin_prefix_;

@ -653,6 +653,44 @@ TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) {
"test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b");
}
TEST_F(CommandLineInterfaceTest, ExtraPluginParameters) {
// Test that generator parameters specified with the option flag are
// correctly passed to the code generator.
CreateTempFile("foo.proto",
"syntax = \"proto2\";\n"
"message Foo {}\n");
// Create the "a" and "b" sub-directories.
CreateTempDir("a");
CreateTempDir("b");
Run("protocol_compiler "
"--plug_opt=foo1 "
"--plug_out=bar:$tmpdir/a "
"--plug_opt=foo2 "
"--plug_out=baz:$tmpdir/b "
"--plug_opt=foo3 "
"--proto_path=$tmpdir foo.proto");
ExpectNoErrors();
ExpectGenerated(
"test_plugin", "bar,foo1,foo2,foo3", "foo.proto", "Foo", "a");
ExpectGenerated(
"test_plugin", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b");
}
TEST_F(CommandLineInterfaceTest, UnrecognizedExtraParameters) {
CreateTempFile("foo.proto",
"syntax = \"proto2\";\n"
"message Foo {}\n");
Run("protocol_compiler --plug_out=TestParameter:$tmpdir "
"--unknown_plug_opt=Foo "
"--proto_path=$tmpdir foo.proto");
ExpectErrorSubstring("Unknown flag: --unknown_plug_opt");
}
TEST_F(CommandLineInterfaceTest, Insert) {
// Test running a generator that inserts code into another's output.

@ -61,7 +61,7 @@ namespace compiler {
// comma-separated string.
string CommaSeparatedList(const std::vector<const FileDescriptor*> all_files) {
std::vector<string> names;
for (int i = 0; i < all_files.size(); i++) {
for (size_t i = 0; i < all_files.size(); i++) {
names.push_back(all_files[i]->name());
}
return Join(names, ",");
@ -98,7 +98,7 @@ void MockCodeGenerator::ExpectGenerated(
while (!lines.empty() && lines.back().empty()) {
lines.pop_back();
}
for (int i = 0; i < lines.size(); i++) {
for (size_t i = 0; i < lines.size(); i++) {
lines[i] += "\n";
}
@ -115,7 +115,7 @@ void MockCodeGenerator::ExpectGenerated(
EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]);
for (int i = 0; i < insertion_list.size(); i++) {
for (size_t i = 0; i < insertion_list.size(); i++) {
EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
file, file, first_message_name),
lines[1 + i]);
@ -171,7 +171,7 @@ bool MockCodeGenerator::Generate(
SplitStringUsing(StripPrefixString(parameter, "insert="),
",", &insert_into);
for (int i = 0; i < insert_into.size(); i++) {
for (size_t i = 0; i < insert_into.size(); i++) {
{
google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->OpenForInsert(
GetOutputFileName(insert_into[i], file), kFirstInsertionPointName));

@ -70,6 +70,16 @@ void GenerateEnum(const google::protobuf::EnumDescriptor* en,
void Indent(google::protobuf::io::Printer* printer);
void Outdent(google::protobuf::io::Printer* printer);
std::string MessagePrefix(const google::protobuf::Descriptor* message) {
// Empty cannot be php class name.
if (message->name() == "Empty" &&
message->file()->package() == "google.protobuf") {
return "GPB";
} else {
return "";
}
}
std::string MessageName(const google::protobuf::Descriptor* message,
bool is_descriptor) {
string message_name = message->name();
@ -78,6 +88,8 @@ std::string MessageName(const google::protobuf::Descriptor* message,
message_name = descriptor->name() + '_' + message_name;
descriptor = descriptor->containing_type();
}
message_name = MessagePrefix(message) + message_name;
return PhpName(message->file()->package(), is_descriptor) + '\\' +
message_name;
}
@ -483,8 +495,10 @@ void GenerateMessage(const string& name_prefix,
return;
}
string message_name = name_prefix.empty()?
message->name() : name_prefix + "_" + message->name();
string message_name =
name_prefix.empty()
? message->name()
: name_prefix + "_" + MessagePrefix(message) + message->name();
printer->Print(
"class @name@ extends \\Google\\Protobuf\\Internal\\Message\n"

@ -686,8 +686,7 @@ inline const Message& GenericTypeHandler<Message>::default_instance() {
return *null;
}
class StringTypeHandler {
class LIBPROTOBUF_EXPORT StringTypeHandler {
public:
typedef string Type;

@ -196,14 +196,22 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
// Apple.
#elif defined(GOOGLE_PROTOBUF_OS_APPLE)
#if __has_feature(cxx_atomic) || _GNUC_VER >= 407
#include <google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h>
#else // __has_feature(cxx_atomic) || _GNUC_VER >= 407
#include <google/protobuf/stubs/atomicops_internals_macosx.h>
#endif // __has_feature(cxx_atomic) || _GNUC_VER >= 407
// GCC.
#elif defined(__GNUC__)
#if defined(GOOGLE_PROTOBUF_ARCH_IA32) || defined(GOOGLE_PROTOBUF_ARCH_X64)
#include <google/protobuf/stubs/atomicops_internals_x86_gcc.h>
#elif defined(GOOGLE_PROTOBUF_ARCH_ARM) && defined(__linux__)
#if (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))
#include <google/protobuf/stubs/atomicops_internals_generic_gcc.h>
#else
#include <google/protobuf/stubs/atomicops_internals_arm_gcc.h>
#endif
#elif defined(GOOGLE_PROTOBUF_ARCH_AARCH64)
#include <google/protobuf/stubs/atomicops_internals_arm64_gcc.h>
#elif defined(GOOGLE_PROTOBUF_ARCH_ARM_QNX)
@ -213,7 +221,7 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
#elif defined(GOOGLE_PROTOBUF_ARCH_POWER)
#include <google/protobuf/stubs/atomicops_internals_power.h>
#elif defined(__native_client__)
#include <google/protobuf/stubs/atomicops_internals_pnacl.h>
#include <google/protobuf/stubs/atomicops_internals_generic_c11_atomic.h>
#elif defined(GOOGLE_PROTOBUF_ARCH_PPC)
#include <google/protobuf/stubs/atomicops_internals_ppc_gcc.h>
#elif (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4))

@ -30,8 +30,8 @@
// This file is an internal atomic implementation, use atomicops.h instead.
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_
#include <atomic>
@ -228,4 +228,4 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_
#endif // GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_

@ -38,7 +38,7 @@ namespace internal {
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
return old_value;
}
@ -61,7 +61,7 @@ inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
return old_value;
}
@ -69,7 +69,7 @@ inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value,
Atomic32 new_value) {
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
return old_value;
}
@ -115,7 +115,7 @@ inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
Atomic64 new_value) {
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
return old_value;
}
@ -123,7 +123,7 @@ inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
Atomic64 new_value) {
__atomic_compare_exchange_n(ptr, &old_value, new_value, true,
__atomic_compare_exchange_n(ptr, &old_value, new_value, false,
__ATOMIC_RELAXED, __ATOMIC_RELAXED);
return old_value;
}

@ -114,11 +114,11 @@ GOOGLE_PROTOBUF_PLATFORM_ERROR
#undef GOOGLE_PROTOBUF_PLATFORM_ERROR
#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE)
#if defined(GOOGLE_PROTOBUF_OS_ANDROID) || defined(GOOGLE_PROTOBUF_OS_IPHONE) || defined(__OpenBSD__)
// Android ndk does not support the __thread keyword very well yet. Here
// we use pthread_key_create()/pthread_getspecific()/... methods for
// TLS support on android.
// iOS also does not support the __thread keyword.
// iOS and OpenBSD also do not support the __thread keyword.
#define GOOGLE_PROTOBUF_NO_THREADLOCAL
#endif

@ -139,18 +139,10 @@ template<> struct is_integral<int> : true_type { };
template<> struct is_integral<unsigned int> : true_type { };
template<> struct is_integral<long> : true_type { };
template<> struct is_integral<unsigned long> : true_type { };
#ifdef HAVE_LONG_LONG
#if defined(HAVE_LONG_LONG) || defined(_MSC_VER)
template<> struct is_integral<long long> : true_type { };
template<> struct is_integral<unsigned long long> : true_type { };
#endif
#if defined(_MSC_VER)
// With VC, __int8, __int16, and __int32 are synonymous with standard types
// with the same size, but __int64 has not equivalent (i.e., it's neither
// long, nor long long and should be treated differnetly).
// https://msdn.microsoft.com/en-us/library/29dh1w7z.aspx
template<> struct is_integral<__int64> : true_type { };
template<> struct is_integral<unsigned __int64> : true_type {};
#endif
template <class T> struct is_integral<const T> : is_integral<T> { };
template <class T> struct is_integral<volatile T> : is_integral<T> { };
template <class T> struct is_integral<const volatile T> : is_integral<T> { };

@ -50,16 +50,16 @@ const char kRfc3339TimeFormat[] = "%E4Y-%m-%dT%H:%M:%S";
const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S";
// Minimun seconds allowed in a google.protobuf.Timestamp value.
const int64 kTimestampMinSeconds = -62135596800;
const int64 kTimestampMinSeconds = -62135596800LL;
// Maximum seconds allowed in a google.protobuf.Timestamp value.
const int64 kTimestampMaxSeconds = 253402300799;
const int64 kTimestampMaxSeconds = 253402300799LL;
// Minimum seconds allowed in a google.protobuf.Duration value.
const int64 kDurationMinSeconds = -315576000000;
const int64 kDurationMinSeconds = -315576000000LL;
// Maximum seconds allowed in a google.protobuf.Duration value.
const int64 kDurationMaxSeconds = 315576000000;
const int64 kDurationMaxSeconds = 315576000000LL;
// Nano seconds in a second.
const int32 kNanosPerSecond = 1000000000;

@ -1028,8 +1028,11 @@ bool ProtoStreamObjectSource::IsMap(
// TODO(xiaofeng): Unify option names.
return field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE &&
(GetBoolOptionOrDefault(field_type->options(),
"google.protobuf.MessageOptions.map_entry", false) ||
GetBoolOptionOrDefault(field_type->options(), "map_entry", false));
"google.protobuf.MessageOptions.map_entry",
false) ||
GetBoolOptionOrDefault(field_type->options(), "map_entry", false) ||
GetBoolOptionOrDefault(field_type->options(),
"proto2.MessageOptions.map_entry", false));
}
std::pair<int64, int32> ProtoStreamObjectSource::ReadSecondsAndNanos(
@ -1125,3 +1128,4 @@ const string FormatNanos(uint32 nanos, bool with_trailing_zeros) {
} // namespace util
} // namespace protobuf
} // namespace google

@ -1240,8 +1240,11 @@ bool ProtoStreamObjectWriter::IsMap(const google::protobuf::Field& field) {
// TODO(xiaofeng): Unify option names.
return GetBoolOptionOrDefault(field_type->options(),
"google.protobuf.MessageOptions.map_entry", false) ||
GetBoolOptionOrDefault(field_type->options(), "map_entry", false);
"google.protobuf.MessageOptions.map_entry",
false) ||
GetBoolOptionOrDefault(field_type->options(), "map_entry", false) ||
GetBoolOptionOrDefault(field_type->options(),
"proto2.MessageOptions.map_entry", false);
}
bool ProtoStreamObjectWriter::IsAny(const google::protobuf::Field& field) {
@ -1266,3 +1269,4 @@ bool ProtoStreamObjectWriter::IsStructListValue(
} // namespace util
} // namespace protobuf
} // namespace google

@ -356,15 +356,23 @@ bool IsValidBoolString(const string& bool_string) {
bool IsMap(const google::protobuf::Field& field,
const google::protobuf::Type& type) {
return (field.cardinality() ==
return (
field.cardinality() ==
google::protobuf::Field_Cardinality_CARDINALITY_REPEATED &&
GetBoolOptionOrDefault(type.options(),
"google.protobuf.MessageOptions.map_entry", false));
(GetBoolOptionOrDefault(
type.options(), "google.protobuf.MessageOptions.map_entry", false) ||
GetBoolOptionOrDefault(type.options(), "proto2.MessageOptions.map_entry",
false)));
}
bool IsMessageSetWireFormat(const google::protobuf::Type& type) {
return GetBoolOptionOrDefault(
type.options(), "google.protobuf.MessageOptions.message_set_wire_format", false);
return (
GetBoolOptionOrDefault(
type.options(),
"google.protobuf.MessageOptions.message_set_wire_format", false) ||
GetBoolOptionOrDefault(type.options(),
"proto2.MessageOptions.message_set_wire_format",
false));
}
string DoubleAsString(double value) {
@ -404,3 +412,4 @@ bool SafeStrToFloat(StringPiece str, float* value) {
} // namespace util
} // namespace protobuf
} // namespace google

@ -358,6 +358,16 @@ use_php_zts() {
ln -sfn "/usr/local/php-${VERSION}-zts/bin/phpize" $PHPIZE
}
use_php_bc() {
VERSION=$1
PHP=`which php`
PHP_CONFIG=`which php-config`
PHPIZE=`which phpize`
ln -sfn "/usr/local/php-${VERSION}-bc/bin/php" $PHP
ln -sfn "/usr/local/php-${VERSION}-bc/bin/php-config" $PHP_CONFIG
ln -sfn "/usr/local/php-${VERSION}-bc/bin/phpize" $PHPIZE
}
build_php5.5() {
use_php 5.5
rm -rf vendor
@ -376,6 +386,19 @@ build_php5.5_zts_c() {
cd php/tests && /bin/bash ./test.sh && cd ../..
}
build_php5.5_32() {
use_php_bc 5.5
rm -rf vendor
cp -r /usr/local/vendor-5.5 vendor
./vendor/bin/phpunit
}
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 ../..
}
build_php5.6() {
use_php 5.6
rm -rf vendor
@ -391,7 +414,8 @@ build_php5.6_c() {
build_php5.6_mac() {
# Install PHP
curl -s https://php-osx.liip.ch/install.sh | bash -s 5.6
export PATH="/usr/local/php5-5.6.25-20160831-101628/bin:$PATH"
PHP_FOLDER=`find /usr/local -type d -name "php5-5.6*"` # The folder name may change upon time
export PATH="$PHP_FOLDER/bin:$PATH"
# Install phpunit
curl https://phar.phpunit.de/phpunit.phar -L -o phpunit.phar
@ -429,6 +453,11 @@ build_php_all() {
build_php5.5_zts_c
}
build_php_all_32() {
build_php5.5_32
build_php5.5_c_32
}
# Note: travis currently does not support testing more than one language so the
# .travis.yml cheats and claims to only be cpp. If they add multiple language
# support, this should probably get updated to install steps and/or

Loading…
Cancel
Save