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

@ -577,7 +577,6 @@ php_EXTRA_DIST= \
php/src/Google/Protobuf/Internal/DescriptorPool.php \ php/src/Google/Protobuf/Internal/DescriptorPool.php \
php/src/Google/Protobuf/Internal/OneofField.php \ php/src/Google/Protobuf/Internal/OneofField.php \
php/src/Google/Protobuf/Internal/MapEntry.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/InputStream.php \
php/src/Google/Protobuf/Internal/OutputStream.php \ php/src/Google/Protobuf/Internal/OutputStream.php \
php/src/Google/Protobuf/Internal/MessageBuilderContext.php \ php/src/Google/Protobuf/Internal/MessageBuilderContext.php \
@ -600,6 +599,8 @@ php_EXTRA_DIST= \
php/tests/test_include.pb.php \ php/tests/test_include.pb.php \
php/tests/map_field_test.php \ php/tests/map_field_test.php \
php/tests/test_base.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_util.php \
php/tests/test.proto \ php/tests/test.proto \
php/tests/test.pb.php \ 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_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_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_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_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_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_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_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_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 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": [ "files": [
"php/src/Google/Protobuf/descriptor.php", "php/src/Google/Protobuf/descriptor.php",
"php/src/Google/Protobuf/descriptor_internal.pb.php", "php/src/Google/Protobuf/descriptor_internal.pb.php"
"php/src/Google/Protobuf/Internal/Type.php"
] ]
} }
} }

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

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

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

@ -61,7 +61,7 @@ namespace Google.Protobuf
{ {
return new InvalidProtocolBufferException( return new InvalidProtocolBufferException(
"While parsing a protocol message, the input ended unexpectedly " + "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 " + "input has been truncated or that an embedded message " +
"misreported its own length."); "misreported its own length.");
} }

@ -248,87 +248,25 @@ namespace Google.Protobuf
return !first; return !first;
} }
/// <summary> // Converted from java/core/src/main/java/com/google/protobuf/Descriptors.java
/// Camel-case converter with added strictness for field mask formatting. internal static string ToJsonName(string name)
/// </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] == '_')
{ {
capitalizeNext = true; StringBuilder result = new StringBuilder(name.Length);
if (result.Length != 0) bool isNextUpperCase = false;
foreach (char ch in name)
{ {
firstWord = false; if (ch == '_')
}
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]))
{ {
result.Append(char.ToUpperInvariant(input[i])); isNextUpperCase = true;
continue;
} }
else else if (isNextUpperCase)
{ {
result.Append(input[i]); result.Append(char.ToUpperInvariant(ch));
continue; isNextUpperCase = false;
}
} }
else else
{ {
result.Append(char.ToLowerInvariant(input[i])); result.Append(ch);
} }
} }
return result.ToString(); 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 // We could trust the generated code and check whether the type of the property is
// a MapField, but that feels a tad nasty. // a MapField, but that feels a tad nasty.
this.propertyName = propertyName; 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> /// </remarks>
/// <param name="paths">Paths in the field mask</param> /// <param name="paths">Paths in the field mask</param>
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</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) internal static string ToJson(IList<string> paths, bool diagnosticOnly)
{ {
var firstInvalid = paths.FirstOrDefault(p => !ValidatePath(p)); var firstInvalid = paths.FirstOrDefault(p => !ValidatePath(p));
@ -60,10 +60,10 @@ namespace Google.Protobuf.WellKnownTypes
{ {
var writer = new StringWriter(); var writer = new StringWriter();
#if DOTNET35 #if DOTNET35
var query = paths.Select(JsonFormatter.ToCamelCase); var query = paths.Select(JsonFormatter.ToJsonName);
JsonFormatter.WriteString(writer, string.Join(",", query.ToArray())); JsonFormatter.WriteString(writer, string.Join(",", query.ToArray()));
#else #else
JsonFormatter.WriteString(writer, string.Join(",", paths.Select(JsonFormatter.ToCamelCase))); JsonFormatter.WriteString(writer, string.Join(",", paths.Select(JsonFormatter.ToJsonName)));
#endif #endif
return writer.ToString(); return writer.ToString();
} }
@ -85,9 +85,9 @@ namespace Google.Protobuf.WellKnownTypes
} }
/// <summary> /// <summary>
/// Camel-case converter with added strictness for field mask formatting. /// Checks whether the given path is valid for a field mask.
/// </summary> /// </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) private static bool ValidatePath(string input)
{ {
for (int i = 0; i < input.Length; i++) 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: https://github.com/SandroGrzicic/ScalaBuff
* Scala: http://trueaccord.github.io/ScalaPB/ * Scala: http://trueaccord.github.io/ScalaPB/
* Swift: https://github.com/alexeyxo/protobuf-swift * Swift: https://github.com/alexeyxo/protobuf-swift
* Swift: https://github.com/apple/swift-protobuf/
* Vala: https://launchpad.net/protobuf-vala * Vala: https://launchpad.net/protobuf-vala
* Visual Basic: http://code.google.com/p/protobuf-net/ * Visual Basic: http://code.google.com/p/protobuf-net/

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

@ -92,11 +92,34 @@
<!-- Add the generated sources to the build --> <!-- Add the generated sources to the build -->
<plugin> <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> <configuration>
<generatedSourcesDirectory>${generated.sources.dir}</generatedSourcesDirectory> <sources>
<generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory> <source>${generated.testsources.dir}</source>
</sources>
</configuration> </configuration>
</execution>
</executions>
</plugin> </plugin>
<!-- OSGI bundle configuration --> <!-- OSGI bundle configuration -->

@ -33,11 +33,12 @@ package com.google.protobuf;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
/** /**
* Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s. * 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 = private static final ThreadLocal<SoftReference<byte[]>> BUFFER =
new ThreadLocal<SoftReference<byte[]>>(); 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 * For testing purposes only. Clears the cached buffer to force a new allocation on the next
* invocation. * invocation.
@ -93,10 +100,7 @@ final class ByteBufferWriter {
// Optimized write for array-backed buffers. // Optimized write for array-backed buffers.
// Note that we're taking the risk that a malicious OutputStream could modify the array. // 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()); output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining());
} else if (output instanceof FileOutputStream) { } else if (!writeToChannel(buffer, output)){
// Use a channel to write out the ByteBuffer. This will automatically empty the buffer.
((FileOutputStream) output).getChannel().write(buffer);
} else {
// Read all of the data from the buffer to an array. // Read all of the data from the buffer to an array.
// TODO(nathanmittler): Consider performance improvements for other "known" stream types. // TODO(nathanmittler): Consider performance improvements for other "known" stream types.
final byte[] array = getOrCreateBuffer(buffer.remaining()); final byte[] array = getOrCreateBuffer(buffer.remaining());
@ -142,4 +146,40 @@ final class ByteBufferWriter {
private static void setBuffer(byte[] value) { private static void setBuffer(byte[] value) {
BUFFER.set(new SoftReference<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"}) @SuppressWarnings({"rawtypes", "unchecked"})
private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite(Collections.emptyMap()); private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite();
static { static {
EMPTY_MAP_FIELD.makeImmutable(); EMPTY_MAP_FIELD.makeImmutable();
} }

@ -75,11 +75,39 @@
</plugin> </plugin>
<!-- Only compile a subset of the files --> <!-- 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> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<configuration> <configuration>
<generatedSourcesDirectory>${generated.sources.lite.dir}</generatedSourcesDirectory>
<generatedTestSourcesDirectory>${generated.testsources.lite.dir}</generatedTestSourcesDirectory>
<includes> <includes>
<include>**/AbstractMessageLite.java</include> <include>**/AbstractMessageLite.java</include>
<include>**/AbstractParser.java</include> <include>**/AbstractParser.java</include>

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

@ -79,12 +79,24 @@
</executions> </executions>
</plugin> </plugin>
<!-- Add the generated test sources to the build -->
<plugin> <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> <configuration>
<!-- Add the generated test sources to the build --> <sources>
<generatedTestSourcesDirectory>${generated.testsources.dir}</generatedTestSourcesDirectory> <source>${generated.testsources.dir}</source>
</sources>
</configuration> </configuration>
</execution>
</executions>
</plugin> </plugin>
<!-- Configure the OSGI bundle --> <!-- Configure the OSGI bundle -->

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

@ -48,7 +48,7 @@ public class InvalidProtocolBufferNanoException extends IOException {
static InvalidProtocolBufferNanoException truncatedMessage() { static InvalidProtocolBufferNanoException truncatedMessage() {
return new InvalidProtocolBufferNanoException( return new InvalidProtocolBufferNanoException(
"While parsing a protocol message, the input ended unexpectedly " + "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 " + "input has been truncated or that an embedded message " +
"misreported its own length."); "misreported its own length.");
} }

@ -12,5 +12,5 @@
export DOCKERFILE_DIR=jenkins/docker32 export DOCKERFILE_DIR=jenkins/docker32
export DOCKER_RUN_SCRIPT=jenkins/pull_request_in_docker.sh export DOCKER_RUN_SCRIPT=jenkins/pull_request_in_docker.sh
export OUTPUT_DIR=testoutput export OUTPUT_DIR=testoutput
export TEST_SET="php_all" export TEST_SET="php_all_32"
./jenkins/build_and_run_docker.sh ./jenkins/build_and_run_docker.sh

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

@ -64,6 +64,7 @@ RUN php -r "unlink('composer-setup.php');"
RUN cd /tmp && \ RUN cd /tmp && \
git clone https://github.com/google/protobuf.git && \ git clone https://github.com/google/protobuf.git && \
cd protobuf && \ cd protobuf && \
git reset 734930f9197b7bc97c3c794c7a949fee2a08c280 && \
ln -sfn /usr/bin/php5.5 /usr/bin/php && \ ln -sfn /usr/bin/php5.5 /usr/bin/php && \
ln -sfn /usr/bin/php-config5.5 /usr/bin/php-config && \ ln -sfn /usr/bin/php-config5.5 /usr/bin/php-config && \
ln -sfn /usr/bin/phpize5.5 /usr/bin/phpize && \ 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 mv mirror php-5.5.38.tar.bz2
RUN tar -xvf 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 && \ 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 # Python dependencies

@ -941,11 +941,9 @@ jspb.BinaryDecoder.prototype.readEnum = function() {
/** /**
* Reads and parses a UTF-8 encoded unicode string from the stream. * Reads and parses a UTF-8 encoded unicode string from the stream.
* The code is inspired by maps.vectortown.parse.StreamedDataViewReader, with * The code is inspired by maps.vectortown.parse.StreamedDataViewReader.
* the exception that the implementation here does not get confused if it * Supports codepoints from U+0000 up to U+10FFFF.
* encounters characters longer than three bytes. These characters are ignored * (http://en.wikipedia.org/wiki/UTF-8).
* though, as they are extremely rare: three UTF-8 bytes cover virtually all
* characters in common use (http://en.wikipedia.org/wiki/UTF-8).
* @param {number} length The length of the string to read. * @param {number} length The length of the string to read.
* @return {string} The decoded string. * @return {string} The decoded string.
*/ */
@ -953,30 +951,45 @@ jspb.BinaryDecoder.prototype.readString = function(length) {
var bytes = this.bytes_; var bytes = this.bytes_;
var cursor = this.cursor_; var cursor = this.cursor_;
var end = cursor + length; var end = cursor + length;
var chars = []; var codeUnits = [];
while (cursor < end) { while (cursor < end) {
var c = bytes[cursor++]; var c = bytes[cursor++];
if (c < 128) { // Regular 7-bit ASCII. if (c < 128) { // Regular 7-bit ASCII.
chars.push(c); codeUnits.push(c);
} else if (c < 192) { } else if (c < 192) {
// UTF-8 continuation mark. We are out of sync. This // UTF-8 continuation mark. We are out of sync. This
// might happen if we attempted to read a character // might happen if we attempted to read a character
// with more than three bytes. // with more than four bytes.
continue; continue;
} else if (c < 224) { // UTF-8 with two bytes. } else if (c < 224) { // UTF-8 with two bytes.
var c2 = bytes[cursor++]; 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. } else if (c < 240) { // UTF-8 with three bytes.
var c2 = bytes[cursor++]; var c2 = bytes[cursor++];
var c3 = 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 // String.fromCharCode.apply is faster than manually appending characters on
// Chrome 25+, and generates no additional cons string garbage. // 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; this.cursor_ = cursor;
return result; return result;
}; };

@ -210,6 +210,29 @@ describe('binaryDecoderTest', function() {
assertEquals(hashD, decoder.readFixedHash64()); 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. * 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) { jspb.BinaryEncoder.prototype.writeString = function(value) {
var oldLength = this.buffer_.length; var oldLength = this.buffer_.length;
// UTF16 to UTF8 conversion loop swiped from goog.crypt.stringToUtf8ByteArray.
for (var i = 0; i < value.length; i++) { for (var i = 0; i < value.length; i++) {
var c = value.charCodeAt(i); var c = value.charCodeAt(i);
if (c < 128) { if (c < 128) {
this.buffer_.push(c); this.buffer_.push(c);
} else if (c < 2048) { } else if (c < 2048) {
this.buffer_.push((c >> 6) | 192); this.buffer_.push((c >> 6) | 192);
this.buffer_.push((c & 63) | 128); 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 >> 12) | 224);
this.buffer_.push(((c >> 6) & 63) | 128); this.buffer_.push(((c >> 6) & 63) | 128);
this.buffer_.push((c & 63) | 128); this.buffer_.push((c & 63) | 128);
} }
} }
}
var length = this.buffer_.length - oldLength; var length = this.buffer_.length - oldLength;
return length; return length;

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

@ -217,6 +217,27 @@ CF_EXTERN_C_END
**/ **/
- (size_t)position; - (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 * 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. * 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; return state_.bufferPos;
} }
- (size_t)pushLimit:(size_t)byteLimit {
return GPBCodedInputStreamPushLimit(&state_, byteLimit);
}
- (void)popLimit:(size_t)oldLimit {
GPBCodedInputStreamPopLimit(&state_, oldLimit);
}
- (double)readDouble { - (double)readDouble {
return GPBCodedInputStreamReadDouble(&state_); return GPBCodedInputStreamReadDouble(&state_);
} }

@ -65,6 +65,15 @@ CF_EXTERN_C_END
/** /**
* Base class that each generated message subclasses from. * 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> @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 If the target is using ARC, remember to turn off ARC (`-fno-objc-arc`) for the
`.m` files. `.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. `\*.pbobjc.m`) are then also added to the target.
Usage Usage

@ -54,6 +54,16 @@ static zend_function_entry repeated_field_methods[] = {
PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC) PHP_ME(RepeatedField, offsetSet, arginfo_offsetSet, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC) PHP_ME(RepeatedField, offsetUnset, arginfo_offsetGet, ZEND_ACC_PUBLIC)
PHP_ME(RepeatedField, count, arginfo_void, 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 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, static HashTable *repeated_field_get_gc(zval *object, zval ***table,
int *n TSRMLS_DC); 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 // RepeatedField creation/desctruction
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
zend_class_entry* repeated_field_type; zend_class_entry* repeated_field_type;
zend_class_entry* repeated_field_iter_type;
zend_object_handlers* repeated_field_handlers; zend_object_handlers* repeated_field_handlers;
void repeated_field_init(TSRMLS_D) { 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 = zend_register_internal_class(&class_type TSRMLS_CC);
repeated_field_type->create_object = repeated_field_create; repeated_field_type->create_object = repeated_field_create;
zend_class_implements(repeated_field_type TSRMLS_CC, 2, spl_ce_ArrayAccess, zend_class_implements(repeated_field_type TSRMLS_CC, 3, spl_ce_ArrayAccess,
spl_ce_Countable); zend_ce_aggregate, spl_ce_Countable);
repeated_field_handlers = PEMALLOC(zend_object_handlers); repeated_field_handlers = PEMALLOC(zend_object_handlers);
memcpy(repeated_field_handlers, zend_get_std_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_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); RETURN_ZVAL(generated_pool_php, 1, 0);
} }
static void convert_to_class_name_inplace(char *proto_name, static void convert_to_class_name_inplace(char *class_name,
size_t pkg_name_len) { const char* fullname,
const char* package_name) {
size_t i; size_t i;
bool first_char = false; 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++) { for (i = 0; i <= pkg_name_len + 1; i++) {
// PHP package uses camel case. // PHP package uses camel case.
if (!first_char && proto_name[i] != '.') { if (!first_char && class_name[i] != '.') {
first_char = true; first_char = true;
proto_name[i] += 'A' - 'a'; class_name[i] += 'A' - 'a';
} }
// php packages are divided by '\'. // php packages are divided by '\'.
if (proto_name[i] == '.') { if (class_name[i] == '.') {
first_char = false; first_char = false;
proto_name[i] = '\\'; class_name[i] = '\\';
}
} }
} }
// Submessage is concatenated with its containing messages by '_'. // Submessage is concatenated with its containing messages by '_'.
for (i = pkg_name_len; i < strlen(proto_name); i++) { for (i = pkg_name_len; i < strlen(class_name); i++) {
if (proto_name[i] == '.') { if (class_name[i] == '.') {
proto_name[i] = '_'; class_name[i] = '_';
} }
} }
} }
@ -322,13 +335,13 @@ PHP_METHOD(DescriptorPool, internalAddGeneratedFile) {
upb_msgdef_mapentry(upb_downcast_msgdef(def))) { \ upb_msgdef_mapentry(upb_downcast_msgdef(def))) { \
break; \ 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); \ const char *fullname = upb_##def_type_lower##_fullname(def_type_lower); \
char *klass_name = ecalloc(sizeof(char), 2 + strlen(fullname)); \ char *klass_name = ecalloc(sizeof(char), 5 + strlen(fullname)); \
klass_name[0] = '.'; \ convert_to_class_name_inplace(klass_name, fullname, \
strcpy(&klass_name[1], fullname); \ upb_filedef_package(files[0])); \
size_t pkg_name_len = strlen(upb_filedef_package(files[0])); \
convert_to_class_name_inplace(klass_name, pkg_name_len); \
zend_class_entry **pce; \ zend_class_entry **pce; \
if (zend_lookup_class(klass_name, strlen(klass_name), &pce TSRMLS_CC) == \ if (zend_lookup_class(klass_name, strlen(klass_name), &pce TSRMLS_CC) == \
FAILURE) { \ 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); zend_object_std_init(&msg->std, ce TSRMLS_CC);
object_properties_init(&msg->std, ce); object_properties_init(&msg->std, ce);
layout_init(desc->layout, message_data(msg), msg->std.properties_table layout_init(desc->layout, message_data(msg),
TSRMLS_CC); msg->std.properties_table TSRMLS_CC);
return_value.handle = zend_objects_store_put( return_value.handle = zend_objects_store_put(
msg, (zend_objects_store_dtor_t)zend_objects_destroy_object, message_free, 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) { static PHP_MINIT_FUNCTION(protobuf) {
map_field_init(TSRMLS_C); map_field_init(TSRMLS_C);
repeated_field_init(TSRMLS_C); repeated_field_init(TSRMLS_C);
repeated_field_iter_init(TSRMLS_C);
gpb_type_init(TSRMLS_C); gpb_type_init(TSRMLS_C);
message_init(TSRMLS_C); message_init(TSRMLS_C);
descriptor_pool_init(TSRMLS_C); descriptor_pool_init(TSRMLS_C);

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

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

@ -34,6 +34,7 @@
#include "utf8.h" #include "utf8.h"
static zend_class_entry* util_type; 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_BEGIN_ARG_INFO_EX(arg_check_optional, 0, 0, 1)
ZEND_ARG_INFO(1, val) ZEND_ARG_INFO(1, val)
@ -78,8 +79,128 @@ void util_init(TSRMLS_D) {
// Type checking/conversion. // 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) \ #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; \ *type##_value = (type##_t)val; \
return true; \ return true; \
} \ } \
@ -91,15 +212,15 @@ void util_init(TSRMLS_D) {
\ \
static bool convert_string_to_##type(const char* val, int len, \ static bool convert_string_to_##type(const char* val, int len, \
type##_t* type##_value) { \ type##_t* type##_value) { \
long lval; \ int64_t lval; \
double dval; \ double dval; \
\ \
switch (is_numeric_string(val, len, &lval, &dval, 0)) { \ switch (convert_numeric_string(val, len, &lval, &dval)) { \
case IS_DOUBLE: { \ case IS_DOUBLE: { \
return convert_double_to_##type(dval, type##_value); \ return convert_double_to_##type(dval, type##_value); \
} \ } \
case IS_LONG: { \ case IS_LONG: { \
return convert_long_to_##type(lval, type##_value); \ return convert_int64_to_##type(lval, type##_value); \
} \ } \
default: \ default: \
zend_error(E_USER_ERROR, \ zend_error(E_USER_ERROR, \
@ -111,7 +232,7 @@ void util_init(TSRMLS_D) {
bool protobuf_convert_to_##type(zval* from, type##_t* to) { \ bool protobuf_convert_to_##type(zval* from, type##_t* to) { \
switch (Z_TYPE_P(from)) { \ switch (Z_TYPE_P(from)) { \
case IS_LONG: { \ 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: { \ case IS_DOUBLE: { \
return convert_double_to_##type(Z_DVAL_P(from), to); \ return convert_double_to_##type(Z_DVAL_P(from), to); \
@ -137,7 +258,7 @@ CONVERT_TO_INTEGER(uint64);
#undef CONVERT_TO_INTEGER #undef CONVERT_TO_INTEGER
#define CONVERT_TO_FLOAT(type) \ #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; \ *type##_value = (type)val; \
return true; \ return true; \
} \ } \
@ -149,10 +270,10 @@ CONVERT_TO_INTEGER(uint64);
\ \
static bool convert_string_to_##type(const char* val, int len, \ static bool convert_string_to_##type(const char* val, int len, \
type* type##_value) { \ type* type##_value) { \
long lval; \ int64_t lval; \
double dval; \ double dval; \
\ \
switch (is_numeric_string(val, len, &lval, &dval, 0)) { \ switch (convert_numeric_string(val, len, &lval, &dval)) { \
case IS_DOUBLE: { \ case IS_DOUBLE: { \
*type##_value = (type)dval; \ *type##_value = (type)dval; \
return true; \ return true; \
@ -171,7 +292,7 @@ CONVERT_TO_INTEGER(uint64);
bool protobuf_convert_to_##type(zval* from, type* to) { \ bool protobuf_convert_to_##type(zval* from, type* to) { \
switch (Z_TYPE_P(from)) { \ switch (Z_TYPE_P(from)) { \
case IS_LONG: { \ 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: { \ case IS_DOUBLE: { \
return convert_double_to_##type(Z_DVAL_P(from), to); \ return convert_double_to_##type(Z_DVAL_P(from), to); \

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

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

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

@ -125,6 +125,16 @@ class Message
$oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()]; $oneof = $this->desc->getOneofDecl()[$field->getOneofIndex()];
$oneof_name = $oneof->getName(); $oneof_name = $oneof->getName();
$this->$oneof_name = new OneofField($oneof); $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)) { if (!GPBWire::readInt64($input, $value)) {
return false; return false;
} }
$value = $value->toInteger();
break; break;
case GPBType::UINT64: case GPBType::UINT64:
if (!GPBWire::readUint64($input, $value)) { if (!GPBWire::readUint64($input, $value)) {
return false; return false;
} }
$value = $value->toInteger();
break; break;
case GPBType::INT32: case GPBType::INT32:
if (!GPBWire::readInt32($input, $value)) { if (!GPBWire::readInt32($input, $value)) {
@ -227,7 +235,6 @@ class Message
if (!GPBWire::readFixed64($input, $value)) { if (!GPBWire::readFixed64($input, $value)) {
return false; return false;
} }
$value = $value->toInteger();
break; break;
case GPBType::FIXED32: case GPBType::FIXED32:
if (!GPBWire::readFixed32($input, $value)) { if (!GPBWire::readFixed32($input, $value)) {
@ -285,7 +292,6 @@ class Message
if (!GPBWire::readSfixed64($input, $value)) { if (!GPBWire::readSfixed64($input, $value)) {
return false; return false;
} }
$value = $value->toInteger();
break; break;
case GPBType::SINT32: case GPBType::SINT32:
if (!GPBWire::readSint32($input, $value)) { if (!GPBWire::readSint32($input, $value)) {
@ -296,7 +302,6 @@ class Message
if (!GPBWire::readSint64($input, $value)) { if (!GPBWire::readSint64($input, $value)) {
return false; return false;
} }
$value = $value->toInteger();
break; break;
default: default:
user_error("Unsupported type."); user_error("Unsupported type.");

@ -90,8 +90,6 @@ class OutputStream
public function writeRaw($data, $size) public function writeRaw($data, $size)
{ {
if ($this->buffer_size < $size) { if ($this->buffer_size < $size) {
var_dump($this->buffer_size);
var_dump($size);
trigger_error("Output stream doesn't have enough buffer."); trigger_error("Output stream doesn't have enough buffer.");
return false; return false;
} }
@ -107,15 +105,28 @@ class OutputStream
private static function writeVarintToArray($value, &$buffer, $trim = false) private static function writeVarintToArray($value, &$buffer, $trim = false)
{ {
$current = 0; $current = 0;
$high = 0;
$low = 0;
if (PHP_INT_SIZE == 4) {
GPBUtil::divideInt64ToInt32($value, $high, $low, $trim);
} else {
if ($trim) { 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)); $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++; $current++;
} }
$buffer[$current] = chr($value); $buffer[$current] = chr($low);
return $current + 1; return $current + 1;
} }
@ -130,14 +141,24 @@ class OutputStream
private static function writeLittleEndian64ToArray($value, &$buffer) private static function writeLittleEndian64ToArray($value, &$buffer)
{ {
$buffer[0] = chr($value & 0x000000FF); $high = 0;
$buffer[1] = chr(($value >> 8) & 0x000000FF); $low = 0;
$buffer[2] = chr(($value >> 16) & 0x000000FF); if (PHP_INT_SIZE == 4) {
$buffer[3] = chr(($value >> 24) & 0x000000FF); GPBUtil::divideInt64ToInt32($value, $high, $low);
$buffer[4] = chr(($value >> 32) & 0x000000FF); } else {
$buffer[5] = chr(($value >> 40) & 0x000000FF); $low = $value & 0xFFFFFFFF;
$buffer[6] = chr(($value >> 48) & 0x000000FF); $high = ($value >> 32) & 0xFFFFFFFF;
$buffer[7] = chr(($value >> 56) & 0x000000FF); }
$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; 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; return $desc;
} }
} }
function addPrefixIfSpecial(
$name,
$package)
{
if ($name === "Empty" && $package === "google.protobuf") {
return "GPBEmpty";
} else {
return $name;
}
}
function getFullClassName( function getFullClassName(
$proto, $proto,
$containing, $containing,
@ -224,7 +236,8 @@ function getFullClassName(
&$fullname) &$fullname)
{ {
// Full name needs to start with '.'. // Full name needs to start with '.'.
$message_name_without_package = $proto->getName(); $message_name_without_package =
addPrefixIfSpecial($proto->getName(), $package);
if ($containing !== "") { if ($containing !== "") {
$message_name_without_package = $message_name_without_package =
$containing . "." . $message_name_without_package; $containing . "." . $message_name_without_package;
@ -240,10 +253,14 @@ function getFullClassName(
$class_name_without_package = $class_name_without_package =
implode('_', array_map('ucwords', implode('_', array_map('ucwords',
explode('.', $message_name_without_package))); explode('.', $message_name_without_package)));
if ($package === "") {
$classname = $class_name_without_package;
} else {
$classname = $classname =
implode('\\', array_map('ucwords', explode('.', $package))). implode('\\', array_map('ucwords', explode('.', $package))).
"\\".$class_name_without_package; "\\".$class_name_without_package;
} }
}
class OneofDescriptor class OneofDescriptor
{ {

@ -65,6 +65,17 @@ class RepeatedFieldTest extends PHPUnit_Framework_TestCase
$this->assertSame(3, $arr[6]); $this->assertSame(3, $arr[6]);
$arr [7]= MAX_INT32_STRING; $arr [7]= MAX_INT32_STRING;
$this->assertSame(MAX_INT32, $arr[7]); $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. // Test append.
$arr []= MAX_INT64; $arr []= MAX_INT64;
$this->assertSame(MAX_INT64, $arr[0]);
$arr []= MIN_INT64; $arr []= MIN_INT64;
$this->assertEquals(MIN_INT64, $arr[1]);
$arr []= 1.1; $arr []= 1.1;
$this->assertSame(1, $arr[2]);
$arr []= '2'; $arr []= '2';
$this->assertSame(2, $arr[3]);
$arr []= '3.1'; $arr []= '3.1';
$this->assertSame(3, $arr[4]);
$arr []= MAX_INT64_STRING; $arr []= MAX_INT64_STRING;
$this->assertSame(MAX_INT64, $arr[5]);
$arr []= MIN_INT64_STRING; $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)); $this->assertEquals(7, count($arr));
for ($i = 0; $i < count($arr); $i++) { for ($i = 0; $i < count($arr); $i++) {
$arr[$i] = 0; $arr[$i] = 0;
if (PHP_INT_SIZE == 4) {
$this->assertSame('0', $arr[$i]);
} else {
$this->assertSame(0, $arr[$i]); $this->assertSame(0, $arr[$i]);
} }
}
// Test set. // Test set.
$arr [0]= MAX_INT64; $arr [0]= MAX_INT64;
$this->assertSame(MAX_INT64, $arr[0]);
$arr [1]= MIN_INT64; $arr [1]= MIN_INT64;
$this->assertEquals(MIN_INT64, $arr[1]);
$arr [2]= 1.1; $arr [2]= 1.1;
$this->assertSame(1, $arr[2]);
$arr [3]= '2'; $arr [3]= '2';
$this->assertSame(2, $arr[3]);
$arr [4]= '3.1'; $arr [4]= '3.1';
$this->assertSame(3, $arr[4]);
$arr [5]= MAX_INT64_STRING; $arr [5]= MAX_INT64_STRING;
$this->assertSame(MAX_INT64, $arr[5]);
$arr [6]= MIN_INT64_STRING; $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]); $this->assertEquals(MIN_INT64, $arr[6]);
} }
}
/** /**
* @expectedException PHPUnit_Framework_Error * @expectedException PHPUnit_Framework_Error
@ -315,38 +348,57 @@ class RepeatedFieldTest extends PHPUnit_Framework_TestCase
// Test append. // Test append.
$arr []= MAX_UINT64; $arr []= MAX_UINT64;
$this->assertEquals(MAX_UINT64, $arr[0]);
$arr []= 1.1; $arr []= 1.1;
$this->assertSame(1, $arr[1]);
$arr []= '2'; $arr []= '2';
$this->assertSame(2, $arr[2]);
$arr []= '3.1'; $arr []= '3.1';
$this->assertSame(3, $arr[3]);
$arr []= MAX_UINT64_STRING; $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++) { for ($i = 0; $i < count($arr); $i++) {
$arr[$i] = 0; $arr[$i] = 0;
if (PHP_INT_SIZE == 4) {
$this->assertSame('0', $arr[$i]);
} else {
$this->assertSame(0, $arr[$i]); $this->assertSame(0, $arr[$i]);
} }
}
// Test set. // Test set.
$arr [0]= MAX_UINT64; $arr [0]= MAX_UINT64;
$this->assertEquals(MAX_UINT64, $arr[0]);
$arr [1]= 1.1; $arr [1]= 1.1;
$this->assertSame(1, $arr[1]);
$arr [2]= '2'; $arr [2]= '2';
$this->assertSame(2, $arr[2]);
$arr [3]= '3.1'; $arr [3]= '3.1';
$this->assertSame(3, $arr[3]);
$arr [4]= MAX_UINT64_STRING; $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 <?php
require_once('test.pb.php'); require_once('test.pb.php');
require_once('test_no_namespace.pb.php');
require_once('test_util.php'); require_once('test_util.php');
use Google\Protobuf\Internal\RepeatedField; use Google\Protobuf\Internal\RepeatedField;
@ -147,17 +148,40 @@ class GeneratedClassTest extends PHPUnit_Framework_TestCase
// Set float. // Set float.
$m->setOptionalInt64(1.1); $m->setOptionalInt64(1.1);
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $m->getOptionalInt64());
} else {
$this->assertSame(1, $m->getOptionalInt64()); $this->assertSame(1, $m->getOptionalInt64());
}
// Set string. // Set string.
$m->setOptionalInt64('2'); $m->setOptionalInt64('2');
if (PHP_INT_SIZE == 4) {
$this->assertSame('2', $m->getOptionalInt64());
} else {
$this->assertSame(2, $m->getOptionalInt64()); $this->assertSame(2, $m->getOptionalInt64());
}
$m->setOptionalInt64('3.1'); $m->setOptionalInt64('3.1');
if (PHP_INT_SIZE == 4) {
$this->assertSame('3', $m->getOptionalInt64());
} else {
$this->assertSame(3, $m->getOptionalInt64()); $this->assertSame(3, $m->getOptionalInt64());
}
$m->setOptionalInt64(MAX_INT64_STRING); $m->setOptionalInt64(MAX_INT64_STRING);
if (PHP_INT_SIZE == 4) {
$this->assertSame(MAX_INT64_STRING, $m->getOptionalInt64());
} else {
$this->assertSame(MAX_INT64, $m->getOptionalInt64()); $this->assertSame(MAX_INT64, $m->getOptionalInt64());
}
$m->setOptionalInt64(MIN_INT64_STRING); $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. // Set integer.
$m->setOptionalUint64(MAX_UINT64); $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. // Set float.
$m->setOptionalUint64(1.1); $m->setOptionalUint64(1.1);
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $m->getOptionalUint64());
} else {
$this->assertSame(1, $m->getOptionalUint64()); $this->assertSame(1, $m->getOptionalUint64());
}
// Set string. // Set string.
$m->setOptionalUint64('2'); $m->setOptionalUint64('2');
if (PHP_INT_SIZE == 4) {
$this->assertSame('2', $m->getOptionalUint64());
} else {
$this->assertSame(2, $m->getOptionalUint64()); $this->assertSame(2, $m->getOptionalUint64());
}
$m->setOptionalUint64('3.1'); $m->setOptionalUint64('3.1');
if (PHP_INT_SIZE == 4) {
$this->assertSame('3', $m->getOptionalUint64());
} else {
$this->assertSame(3, $m->getOptionalUint64()); $this->assertSame(3, $m->getOptionalUint64());
}
$m->setOptionalUint64(MAX_UINT64_STRING); $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('', $m->getOneofString());
$this->assertSame(1, $m->getOneofMessage()->getA()); $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. // Test integer argument.
$arr[MAX_INT64] = MAX_INT64; $arr[MAX_INT64] = MAX_INT64;
$this->assertSame(MAX_INT64, $arr[MAX_INT64]);
$arr[MIN_INT64] = MIN_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)); $this->assertEquals(2, count($arr));
unset($arr[MAX_INT64]); unset($arr[MAX_INT64]);
unset($arr[MIN_INT64]); unset($arr[MIN_INT64]);
@ -215,20 +220,31 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
// Test float argument. // Test float argument.
$arr[1.1] = 1.1; $arr[1.1] = 1.1;
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $arr['1']);
} else {
$this->assertSame(1, $arr[1]); $this->assertSame(1, $arr[1]);
}
$this->assertEquals(1, count($arr)); $this->assertEquals(1, count($arr));
unset($arr[1.1]); unset($arr[1.1]);
$this->assertEquals(0, count($arr)); $this->assertEquals(0, count($arr));
// Test string argument. // Test string argument.
$arr['2'] = '2'; $arr['2'] = '2';
$this->assertSame(2, $arr[2]);
$arr['3.1'] = '3.1'; $arr['3.1'] = '3.1';
$this->assertSame(3, $arr[3]);
$arr[MAX_INT64_STRING] = MAX_INT64_STRING; $arr[MAX_INT64_STRING] = MAX_INT64_STRING;
$this->assertSame(MAX_INT64, $arr[MAX_INT64]);
$arr[MIN_INT64_STRING] = MIN_INT64_STRING; $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)); $this->assertEquals(4, count($arr));
unset($arr['2']); unset($arr['2']);
unset($arr['3.1']); unset($arr['3.1']);
@ -282,25 +298,41 @@ class MapFieldTest extends PHPUnit_Framework_TestCase {
// Test integer argument. // Test integer argument.
$arr[MAX_UINT64] = MAX_UINT64; $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)); $this->assertEquals(1, count($arr));
unset($arr[MAX_UINT64]); unset($arr[MAX_UINT64]);
$this->assertEquals(0, count($arr)); $this->assertEquals(0, count($arr));
// Test float argument. // Test float argument.
$arr[1.1] = 1.1; $arr[1.1] = 1.1;
if (PHP_INT_SIZE == 4) {
$this->assertSame('1', $arr['1']);
} else {
$this->assertSame(1, $arr[1]); $this->assertSame(1, $arr[1]);
}
$this->assertEquals(1, count($arr)); $this->assertEquals(1, count($arr));
unset($arr[1.1]); unset($arr[1.1]);
$this->assertEquals(0, count($arr)); $this->assertEquals(0, count($arr));
// Test string argument. // Test string argument.
$arr['2'] = '2'; $arr['2'] = '2';
$this->assertSame(2, $arr[2]);
$arr['3.1'] = '3.1'; $arr['3.1'] = '3.1';
$this->assertSame(3, $arr[3]);
$arr[MAX_UINT64_STRING] = MAX_UINT64_STRING; $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)); $this->assertEquals(3, count($arr));
unset($arr['2']); unset($arr['2']);
unset($arr['3.1']); unset($arr['3.1']);

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

@ -7,10 +7,11 @@
pushd ../ext/google/protobuf/ pushd ../ext/google/protobuf/
make clean make clean
set -e 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 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[@]}" for t in "${tests[@]}"
do do

@ -13,22 +13,28 @@ class TestBase extends PHPUnit_Framework_TestCase
public function expectFields(TestMessage $m) 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(-44, $m->getOptionalSint32());
$this->assertSame(-45, $m->getOptionalSint64());
$this->assertSame(46, $m->getOptionalFixed32()); $this->assertSame(46, $m->getOptionalFixed32());
$this->assertSame(47, $m->getOptionalFixed64());
$this->assertSame(-46, $m->getOptionalSfixed32()); $this->assertSame(-46, $m->getOptionalSfixed32());
$this->assertSame(-47, $m->getOptionalSfixed64());
$this->assertSame(1.5, $m->getOptionalFloat()); $this->assertSame(1.5, $m->getOptionalFloat());
$this->assertSame(1.6, $m->getOptionalDouble()); $this->assertSame(1.6, $m->getOptionalDouble());
$this->assertSame(true, $m->getOptionalBool()); $this->assertSame(true, $m->getOptionalBool());
$this->assertSame('a', $m->getOptionalString()); $this->assertSame('a', $m->getOptionalString());
$this->assertSame('b', $m->getOptionalBytes()); $this->assertSame('b', $m->getOptionalBytes());
$this->assertSame(33, $m->getOptionalMessage()->getA()); $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->getRepeatedInt32()[0]);
$this->assertEquals(42, $m->getRepeatedUint32()[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->getOptionalInt32());
$this->assertSame(0, $m->getOptionalUint32()); $this->assertSame(0, $m->getOptionalUint32());
$this->assertSame(0, $m->getOptionalInt64());
$this->assertSame(0, $m->getOptionalUint64());
$this->assertSame(0, $m->getOptionalSint32()); $this->assertSame(0, $m->getOptionalSint32());
$this->assertSame(0, $m->getOptionalSint64());
$this->assertSame(0, $m->getOptionalFixed32()); $this->assertSame(0, $m->getOptionalFixed32());
$this->assertSame(0, $m->getOptionalFixed64());
$this->assertSame(0, $m->getOptionalSfixed32()); $this->assertSame(0, $m->getOptionalSfixed32());
$this->assertSame(0, $m->getOptionalSfixed64());
$this->assertSame(0.0, $m->getOptionalFloat()); $this->assertSame(0.0, $m->getOptionalFloat());
$this->assertSame(0.0, $m->getOptionalDouble()); $this->assertSame(0.0, $m->getOptionalDouble());
$this->assertSame(false, $m->getOptionalBool()); $this->assertSame(false, $m->getOptionalBool());
$this->assertSame('', $m->getOptionalString()); $this->assertSame('', $m->getOptionalString());
$this->assertSame('', $m->getOptionalBytes()); $this->assertSame('', $m->getOptionalBytes());
$this->assertNull($m->getOptionalMessage()); $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. // 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_FLOAT', 2147483647.0);
define('MAX_INT32_STRING', '2147483647'); define('MAX_INT32_STRING', '2147483647');
define('MIN_INT32', -2147483648); define('MIN_INT32', (int)-2147483648);
define('MIN_INT32_FLOAT', -2147483648.0); define('MIN_INT32_FLOAT', -2147483648.0);
define('MIN_INT32_STRING', '-2147483648'); define('MIN_INT32_STRING', '-2147483648');
@ -28,22 +28,23 @@ define('MAX_UINT32', 4294967295);
define('MAX_UINT32_FLOAT', 4294967295.0); define('MAX_UINT32_FLOAT', 4294967295.0);
define('MAX_UINT32_STRING', '4294967295'); define('MAX_UINT32_STRING', '4294967295');
define('MIN_UINT32', -2147483648); define('MIN_UINT32', (int)-2147483648);
define('MIN_UINT32_FLOAT', -2147483648.0); define('MIN_UINT32_FLOAT', -2147483648.0);
define('MIN_UINT32_STRING', '-2147483648'); define('MIN_UINT32_STRING', '-2147483648');
define('MAX_INT64', 9223372036854775807);
define('MAX_INT64_STRING', '9223372036854775807'); define('MAX_INT64_STRING', '9223372036854775807');
define('MIN_INT64_STRING', '-9223372036854775808'); define('MIN_INT64_STRING', '-9223372036854775808');
define('MAX_UINT64_STRING', '-9223372036854775808');
if (PHP_INT_SIZE === 8) { 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 { } else {
define('MAX_INT64', MAX_INT64_STRING);
define('MIN_INT64', MIN_INT64_STRING); define('MIN_INT64', MIN_INT64_STRING);
}
define('MAX_UINT64_STRING', '-9223372036854775808');
define('MAX_UINT64', MAX_UINT64_STRING); define('MAX_UINT64', MAX_UINT64_STRING);
}
class TestUtil class TestUtil
{ {
@ -129,16 +130,24 @@ class TestUtil
public static function assertTestMessage(TestMessage $m) public static function assertTestMessage(TestMessage $m)
{ {
assert(-42 === $m->getOptionalInt32()); if (PHP_INT_SIZE == 4) {
assert(42 === $m->getOptionalUint32()); 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->getOptionalInt64());
assert(43 === $m->getOptionalUint64()); assert(43 === $m->getOptionalUint64());
assert(-44 === $m->getOptionalSint32());
assert(-45 === $m->getOptionalSint64()); assert(-45 === $m->getOptionalSint64());
assert(46 === $m->getOptionalFixed32());
assert(47 === $m->getOptionalFixed64()); assert(47 === $m->getOptionalFixed64());
assert(-46 === $m->getOptionalSfixed32());
assert(-47 === $m->getOptionalSfixed64()); 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.5 === $m->getOptionalFloat());
assert(1.6 === $m->getOptionalDouble()); assert(1.6 === $m->getOptionalDouble());
assert(true=== $m->getOptionalBool()); assert(true=== $m->getOptionalBool());
@ -147,16 +156,24 @@ class TestUtil
assert(TestEnum::ONE === $m->getOptionalEnum()); assert(TestEnum::ONE === $m->getOptionalEnum());
assert(33 === $m->getOptionalMessage()->getA()); assert(33 === $m->getOptionalMessage()->getA());
assert(-42 === $m->getRepeatedInt32()[0]); if (PHP_INT_SIZE == 4) {
assert(42 === $m->getRepeatedUint32()[0]); 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->getRepeatedInt64()[0]);
assert(43 === $m->getRepeatedUint64()[0]); assert(43 === $m->getRepeatedUint64()[0]);
assert(-44 === $m->getRepeatedSint32()[0]);
assert(-45 === $m->getRepeatedSint64()[0]); assert(-45 === $m->getRepeatedSint64()[0]);
assert(46 === $m->getRepeatedFixed32()[0]);
assert(47 === $m->getRepeatedFixed64()[0]); assert(47 === $m->getRepeatedFixed64()[0]);
assert(-46 === $m->getRepeatedSfixed32()[0]);
assert(-47 === $m->getRepeatedSfixed64()[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.5 === $m->getRepeatedFloat()[0]);
assert(1.6 === $m->getRepeatedDouble()[0]); assert(1.6 === $m->getRepeatedDouble()[0]);
assert(true=== $m->getRepeatedBool()[0]); assert(true=== $m->getRepeatedBool()[0]);
@ -165,16 +182,24 @@ class TestUtil
assert(TestEnum::ZERO === $m->getRepeatedEnum()[0]); assert(TestEnum::ZERO === $m->getRepeatedEnum()[0]);
assert(34 === $m->getRepeatedMessage()[0]->getA()); assert(34 === $m->getRepeatedMessage()[0]->getA());
assert(-52 === $m->getRepeatedInt32()[1]); if (PHP_INT_SIZE == 4) {
assert(52 === $m->getRepeatedUint32()[1]); 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->getRepeatedInt64()[1]);
assert(53 === $m->getRepeatedUint64()[1]); assert(53 === $m->getRepeatedUint64()[1]);
assert(-54 === $m->getRepeatedSint32()[1]);
assert(-55 === $m->getRepeatedSint64()[1]); assert(-55 === $m->getRepeatedSint64()[1]);
assert(56 === $m->getRepeatedFixed32()[1]);
assert(57 === $m->getRepeatedFixed64()[1]); assert(57 === $m->getRepeatedFixed64()[1]);
assert(-56 === $m->getRepeatedSfixed32()[1]);
assert(-57 === $m->getRepeatedSfixed64()[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.5 === $m->getRepeatedFloat()[1]);
assert(2.6 === $m->getRepeatedDouble()[1]); assert(2.6 === $m->getRepeatedDouble()[1]);
assert(false === $m->getRepeatedBool()[1]); assert(false === $m->getRepeatedBool()[1]);
@ -183,14 +208,21 @@ class TestUtil
assert(TestEnum::ONE === $m->getRepeatedEnum()[1]); assert(TestEnum::ONE === $m->getRepeatedEnum()[1]);
assert(35 === $m->getRepeatedMessage()[1]->getA()); 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(-63 === $m->getMapInt64Int64()[-63]);
assert(62 === $m->getMapUint32Uint32()[62]);
assert(63 === $m->getMapUint64Uint64()[63]); assert(63 === $m->getMapUint64Uint64()[63]);
assert(-64 === $m->getMapSint32Sint32()[-64]);
assert(-65 === $m->getMapSint64Sint64()[-65]); assert(-65 === $m->getMapSint64Sint64()[-65]);
assert(66 === $m->getMapFixed32Fixed32()[66]);
assert(67 === $m->getMapFixed64Fixed64()[67]); 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.5 === $m->getMapInt32Float()[1]);
assert(3.6 === $m->getMapInt32Double()[1]); assert(3.6 === $m->getMapInt32Double()[1]);
assert(true === $m->getMapBoolBool()[true]); assert(true === $m->getMapBoolBool()[true]);
@ -325,24 +357,14 @@ class TestUtil
assert(-42 === $m->getRepeatedInt32()[0]); assert(-42 === $m->getRepeatedInt32()[0]);
assert(-52 === $m->getRepeatedInt32()[1]); assert(-52 === $m->getRepeatedInt32()[1]);
assert(-43 === $m->getRepeatedInt64()[0]);
assert(-53 === $m->getRepeatedInt64()[1]);
assert(42 === $m->getRepeatedUint32()[0]); assert(42 === $m->getRepeatedUint32()[0]);
assert(52 === $m->getRepeatedUint32()[1]); assert(52 === $m->getRepeatedUint32()[1]);
assert(43 === $m->getRepeatedUint64()[0]);
assert(53 === $m->getRepeatedUint64()[1]);
assert(-44 === $m->getRepeatedSint32()[0]); assert(-44 === $m->getRepeatedSint32()[0]);
assert(-54 === $m->getRepeatedSint32()[1]); assert(-54 === $m->getRepeatedSint32()[1]);
assert(-45 === $m->getRepeatedSint64()[0]);
assert(-55 === $m->getRepeatedSint64()[1]);
assert(46 === $m->getRepeatedFixed32()[0]); assert(46 === $m->getRepeatedFixed32()[0]);
assert(56 === $m->getRepeatedFixed32()[1]); assert(56 === $m->getRepeatedFixed32()[1]);
assert(47 === $m->getRepeatedFixed64()[0]);
assert(57 === $m->getRepeatedFixed64()[1]);
assert(-46 === $m->getRepeatedSfixed32()[0]); assert(-46 === $m->getRepeatedSfixed32()[0]);
assert(-56 === $m->getRepeatedSfixed32()[1]); assert(-56 === $m->getRepeatedSfixed32()[1]);
assert(-47 === $m->getRepeatedSfixed64()[0]);
assert(-57 === $m->getRepeatedSfixed64()[1]);
assert(1.5 === $m->getRepeatedFloat()[0]); assert(1.5 === $m->getRepeatedFloat()[0]);
assert(2.5 === $m->getRepeatedFloat()[1]); assert(2.5 === $m->getRepeatedFloat()[1]);
assert(1.6 === $m->getRepeatedDouble()[0]); assert(1.6 === $m->getRepeatedDouble()[0]);
@ -351,6 +373,29 @@ class TestUtil
assert(false === $m->getRepeatedBool()[1]); assert(false === $m->getRepeatedBool()[1]);
assert(TestEnum::ONE === $m->getRepeatedEnum()[0]); assert(TestEnum::ONE === $m->getRepeatedEnum()[0]);
assert(TestEnum::ZERO === $m->getRepeatedEnum()[1]); 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() 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/encode_decode_test.php</file>
<file>php/tests/generated_class_test.php</file> <file>php/tests/generated_class_test.php</file>
<file>php/tests/map_field_test.php</file> <file>php/tests/map_field_test.php</file>
<file>php/tests/well_known_test.php</file>
</testsuite> </testsuite>
</testsuites> </testsuites>
</phpunit> </phpunit>

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

@ -92,7 +92,7 @@ Installation
error: "sem_init: Resource temporarily unavailable". This appears error: "sem_init: Resource temporarily unavailable". This appears
to be a bug either in Cygwin or in Python: to be a bug either in Cygwin or in Python:
http://www.cygwin.com/ml/cygwin/2005-07/msg01378.html 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. how likely it is that this bug will affect users in practice.
5) Install: 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 // 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 // protobufs in chunks. If you have protos this big you should break them up if
// it is at all convenient to do so. // 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; static bool allow_oversize_protos = false;
#endif
// Provide a method in the module to set allow_oversize_protos to a boolean // 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. // 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) { int Message_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
MessageHeader* self; MessageHeader* self;
VALUE method_str; VALUE method_str;
@ -305,6 +344,9 @@ VALUE Message_deep_copy(VALUE _self) {
VALUE Message_eq(VALUE _self, VALUE _other) { VALUE Message_eq(VALUE _self, VALUE _other) {
MessageHeader* self; MessageHeader* self;
MessageHeader* other; MessageHeader* other;
if (TYPE(_self) != TYPE(_other)) {
return Qfalse;
}
TypedData_Get_Struct(_self, MessageHeader, &Message_type, self); TypedData_Get_Struct(_self, MessageHeader, &Message_type, self);
TypedData_Get_Struct(_other, MessageHeader, &Message_type, other); 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", rb_define_method(klass, "method_missing",
Message_method_missing, -1); 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, "initialize", Message_initialize, -1);
rb_define_method(klass, "dup", Message_dup, 0); rb_define_method(klass, "dup", Message_dup, 0);
// Also define #clone so that we don't inherit Object#clone. // 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)) m2 = MapMessage.decode_json(MapMessage.encode_json(m))
assert m == m2 assert m == m2
end 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
end end

@ -10,12 +10,14 @@ test_version() {
bash --login -c \ bash --login -c \
"rvm install $version && rvm use $version && rvm get head && \ "rvm install $version && rvm use $version && rvm get head && \
which ruby && \ which ruby && \
git clean -f && \
gem install bundler && bundle && \ gem install bundler && bundle && \
rake test" rake test"
else else
bash --login -c \ bash --login -c \
"rvm install $version && rvm use $version && \ "rvm install $version && rvm use $version && \
which ruby && \ which ruby && \
git clean -f && \
gem install bundler && bundle && \ gem install bundler && bundle && \
rake test && rake test &&
cd ../conformance && make test_ruby" 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_gcc.h \
google/protobuf/stubs/atomicops_internals_arm_qnx.h \ google/protobuf/stubs/atomicops_internals_arm_qnx.h \
google/protobuf/stubs/atomicops_internals_atomicword_compat.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_generic_gcc.h \
google/protobuf/stubs/atomicops_internals_macosx.h \ google/protobuf/stubs/atomicops_internals_macosx.h \
google/protobuf/stubs/atomicops_internals_mips_gcc.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_solaris.h \
google/protobuf/stubs/atomicops_internals_tsan.h \ google/protobuf/stubs/atomicops_internals_tsan.h \
google/protobuf/stubs/atomicops_internals_x86_gcc.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) #if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
::operator delete(object, size); ::operator delete(object, size);
#else #else
(void)size;
::operator delete(object); ::operator delete(object);
#endif #endif
} }

@ -263,6 +263,12 @@ void AddDefaultProtoPaths(vector<pair<string, string> >* paths) {
return; 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 } // namespace
// A MultiFileErrorCollector that prints errors to stderr. // A MultiFileErrorCollector that prints errors to stderr.
@ -1008,6 +1014,18 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) {
return status; 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 no --proto_path was given, use the current working directory.
if (proto_path_.empty()) { if (proto_path_.empty()) {
// Don't use make_pair as the old/default standard library on Solaris // 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"))) { (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) {
// Check if it's a generator option flag. // Check if it's a generator option flag.
generator_info = FindOrNull(generators_by_option_name_, name); generator_info = FindOrNull(generators_by_option_name_, name);
if (generator_info == NULL) { if (generator_info != NULL) {
std::cerr << "Unknown flag: " << name << std::endl;
return PARSE_ARGUMENT_FAIL;
} else {
string* parameters = &generator_parameters_[generator_info->flag_name]; string* parameters = &generator_parameters_[generator_info->flag_name];
if (!parameters->empty()) { if (!parameters->empty()) {
parameters->append(","); parameters->append(",");
} }
parameters->append(value); 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 { } else {
// It's an output flag. Add it to the output directives. // It's an output flag. Add it to the output directives.
@ -1465,12 +1490,16 @@ bool CommandLineInterface::GenerateOutput(
HasSuffixString(output_directive.name, "_out")) HasSuffixString(output_directive.name, "_out"))
<< "Bad name for plugin generator: " << output_directive.name; << "Bad name for plugin generator: " << output_directive.name;
// Strip the "--" and "_out" and add the plugin prefix. string plugin_name = PluginName(plugin_prefix_ , output_directive.name);
string plugin_name = plugin_prefix_ + "gen-" + string parameters = output_directive.parameter;
output_directive.name.substr(2, output_directive.name.size() - 6); if (!plugin_parameters_[plugin_name].empty()) {
if (!parameters.empty()) {
parameters.append(",");
}
parameters.append(plugin_parameters_[plugin_name]);
}
if (!GeneratePluginOutput(parsed_files, plugin_name, if (!GeneratePluginOutput(parsed_files, plugin_name,
output_directive.parameter, parameters,
generator_context, &error)) { generator_context, &error)) {
std::cerr << output_directive.name << ": " << error << std::endl; std::cerr << output_directive.name << ": " << error << std::endl;
return false; return false;

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

@ -653,6 +653,44 @@ TEST_F(CommandLineInterfaceTest, ExtraGeneratorParameters) {
"test_generator", "baz,foo1,foo2,foo3", "foo.proto", "Foo", "b"); "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_F(CommandLineInterfaceTest, Insert) {
// Test running a generator that inserts code into another's output. // Test running a generator that inserts code into another's output.

@ -61,7 +61,7 @@ namespace compiler {
// comma-separated string. // comma-separated string.
string CommaSeparatedList(const std::vector<const FileDescriptor*> all_files) { string CommaSeparatedList(const std::vector<const FileDescriptor*> all_files) {
std::vector<string> names; 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()); names.push_back(all_files[i]->name());
} }
return Join(names, ","); return Join(names, ",");
@ -98,7 +98,7 @@ void MockCodeGenerator::ExpectGenerated(
while (!lines.empty() && lines.back().empty()) { while (!lines.empty() && lines.back().empty()) {
lines.pop_back(); lines.pop_back();
} }
for (int i = 0; i < lines.size(); i++) { for (size_t i = 0; i < lines.size(); i++) {
lines[i] += "\n"; lines[i] += "\n";
} }
@ -115,7 +115,7 @@ void MockCodeGenerator::ExpectGenerated(
EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]); EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]);
EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]); 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", EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert",
file, file, first_message_name), file, file, first_message_name),
lines[1 + i]); lines[1 + i]);
@ -171,7 +171,7 @@ bool MockCodeGenerator::Generate(
SplitStringUsing(StripPrefixString(parameter, "insert="), SplitStringUsing(StripPrefixString(parameter, "insert="),
",", &insert_into); ",", &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( google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->OpenForInsert(
GetOutputFileName(insert_into[i], file), kFirstInsertionPointName)); 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 Indent(google::protobuf::io::Printer* printer);
void Outdent(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, std::string MessageName(const google::protobuf::Descriptor* message,
bool is_descriptor) { bool is_descriptor) {
string message_name = message->name(); string message_name = message->name();
@ -78,6 +88,8 @@ std::string MessageName(const google::protobuf::Descriptor* message,
message_name = descriptor->name() + '_' + message_name; message_name = descriptor->name() + '_' + message_name;
descriptor = descriptor->containing_type(); descriptor = descriptor->containing_type();
} }
message_name = MessagePrefix(message) + message_name;
return PhpName(message->file()->package(), is_descriptor) + '\\' + return PhpName(message->file()->package(), is_descriptor) + '\\' +
message_name; message_name;
} }
@ -483,8 +495,10 @@ void GenerateMessage(const string& name_prefix,
return; return;
} }
string message_name = name_prefix.empty()? string message_name =
message->name() : name_prefix + "_" + message->name(); name_prefix.empty()
? message->name()
: name_prefix + "_" + MessagePrefix(message) + message->name();
printer->Print( printer->Print(
"class @name@ extends \\Google\\Protobuf\\Internal\\Message\n" "class @name@ extends \\Google\\Protobuf\\Internal\\Message\n"

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

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

@ -30,8 +30,8 @@
// This file is an internal atomic implementation, use atomicops.h instead. // This file is an internal atomic implementation, use atomicops.h instead.
#ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ #ifndef GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_
#define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_PNACL_H_ #define GOOGLE_PROTOBUF_ATOMICOPS_INTERNALS_GENERIC_C11_ATOMIC_H_
#include <atomic> #include <atomic>
@ -228,4 +228,4 @@ inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
} // namespace protobuf } // namespace protobuf
} // namespace google } // 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, inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 old_value,
Atomic32 new_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); __ATOMIC_RELAXED, __ATOMIC_RELAXED);
return old_value; return old_value;
} }
@ -61,7 +61,7 @@ inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr, inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 old_value,
Atomic32 new_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); __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
return old_value; return old_value;
} }
@ -69,7 +69,7 @@ inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr, inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
Atomic32 old_value, Atomic32 old_value,
Atomic32 new_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); __ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
return old_value; return old_value;
} }
@ -115,7 +115,7 @@ inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr, inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 old_value,
Atomic64 new_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); __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE);
return old_value; return old_value;
} }
@ -123,7 +123,7 @@ inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr, inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value, Atomic64 old_value,
Atomic64 new_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); __ATOMIC_RELAXED, __ATOMIC_RELAXED);
return old_value; return old_value;
} }

@ -114,11 +114,11 @@ GOOGLE_PROTOBUF_PLATFORM_ERROR
#undef 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 // Android ndk does not support the __thread keyword very well yet. Here
// we use pthread_key_create()/pthread_getspecific()/... methods for // we use pthread_key_create()/pthread_getspecific()/... methods for
// TLS support on android. // 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 #define GOOGLE_PROTOBUF_NO_THREADLOCAL
#endif #endif

@ -139,18 +139,10 @@ template<> struct is_integral<int> : true_type { };
template<> struct is_integral<unsigned int> : true_type { }; template<> struct is_integral<unsigned int> : true_type { };
template<> struct is_integral<long> : true_type { }; template<> struct is_integral<long> : true_type { };
template<> struct is_integral<unsigned 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<long long> : true_type { };
template<> struct is_integral<unsigned long long> : true_type { }; template<> struct is_integral<unsigned long long> : true_type { };
#endif #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<const T> : is_integral<T> { };
template <class T> struct is_integral<volatile 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> { }; 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"; const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S";
// Minimun seconds allowed in a google.protobuf.Timestamp value. // 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. // 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. // 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. // Maximum seconds allowed in a google.protobuf.Duration value.
const int64 kDurationMaxSeconds = 315576000000; const int64 kDurationMaxSeconds = 315576000000LL;
// Nano seconds in a second. // Nano seconds in a second.
const int32 kNanosPerSecond = 1000000000; const int32 kNanosPerSecond = 1000000000;

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

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

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

@ -358,6 +358,16 @@ use_php_zts() {
ln -sfn "/usr/local/php-${VERSION}-zts/bin/phpize" $PHPIZE 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() { build_php5.5() {
use_php 5.5 use_php 5.5
rm -rf vendor rm -rf vendor
@ -376,6 +386,19 @@ build_php5.5_zts_c() {
cd php/tests && /bin/bash ./test.sh && cd ../.. 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() { build_php5.6() {
use_php 5.6 use_php 5.6
rm -rf vendor rm -rf vendor
@ -391,7 +414,8 @@ build_php5.6_c() {
build_php5.6_mac() { build_php5.6_mac() {
# Install PHP # Install PHP
curl -s https://php-osx.liip.ch/install.sh | bash -s 5.6 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 # Install phpunit
curl https://phar.phpunit.de/phpunit.phar -L -o phpunit.phar curl https://phar.phpunit.de/phpunit.phar -L -o phpunit.phar
@ -429,6 +453,11 @@ build_php_all() {
build_php5.5_zts_c 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 # 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 # .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 # support, this should probably get updated to install steps and/or

Loading…
Cancel
Save