aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBo Yang <teboring@google.com>2017-01-08 12:53:46 -0800
committerBo Yang <teboring@google.com>2017-01-09 18:37:54 +0000
commitd1fde361a738aa86625bfd7fa7442ef28a6b3011 (patch)
tree645ea5ee650226778c02b710e6b4a3777a103ae7
parentc871ce6e7b3987636ec4927e221a179729bddd11 (diff)
downloadprotobuf-d1fde361a738aa86625bfd7fa7442ef28a6b3011.tar.gz
protobuf-d1fde361a738aa86625bfd7fa7442ef28a6b3011.tar.bz2
protobuf-d1fde361a738aa86625bfd7fa7442ef28a6b3011.zip
Fix int64 decoding on 32-bit machines.
-rw-r--r--php/src/Google/Protobuf/Internal/GPBUtil.php9
-rw-r--r--php/src/Google/Protobuf/Internal/GPBWire.php85
-rw-r--r--php/src/Google/Protobuf/Internal/InputStream.php9
-rw-r--r--php/src/Google/Protobuf/Internal/Message.php15
-rw-r--r--php/tests/encode_decode_test.php35
-rw-r--r--php/tests/php_implementation_test.php52
6 files changed, 142 insertions, 63 deletions
diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php
index 30d7350f..ba1d2eb3 100644
--- a/php/src/Google/Protobuf/Internal/GPBUtil.php
+++ b/php/src/Google/Protobuf/Internal/GPBUtil.php
@@ -43,8 +43,15 @@ class GPBUtil
if ($isNeg) {
$value = bcsub(0, $value);
}
+
$high = (int) bcdiv(bcadd($value, 1), 4294967296);
- $low = (int) bcmod($value, 4294967296);
+ $low = bcmod($value, 4294967296);
+ if (bccomp($low, 2147483647) > 0) {
+ $low = (int) bcsub($low, 4294967296);
+ } else {
+ $low = (int) $low;
+ }
+
if ($isNeg) {
$high = ~$high;
$low = ~$low;
diff --git a/php/src/Google/Protobuf/Internal/GPBWire.php b/php/src/Google/Protobuf/Internal/GPBWire.php
index 7e2c124f..f75e0861 100644
--- a/php/src/Google/Protobuf/Internal/GPBWire.php
+++ b/php/src/Google/Protobuf/Internal/GPBWire.php
@@ -437,34 +437,65 @@ class GPBWire
public static function varint64Size($value)
{
- if ($value < 0) {
- return 10;
- }
- if ($value < (1 << 7)) {
- return 1;
- }
- if ($value < (1 << 14)) {
- return 2;
- }
- if ($value < (1 << 21)) {
- return 3;
- }
- if ($value < (1 << 28)) {
- return 4;
- }
- if ($value < (1 << 35)) {
- return 5;
- }
- if ($value < (1 << 42)) {
- return 6;
- }
- if ($value < (1 << 49)) {
- return 7;
- }
- if ($value < (1 << 56)) {
- return 8;
+ if (PHP_INT_SIZE == 4) {
+ if (bccomp($value, 0) < 0) {
+ return 10;
+ }
+ if (bccomp($value, 1 << 7) < 0) {
+ return 1;
+ }
+ if (bccomp($value, 1 << 14) < 0) {
+ return 2;
+ }
+ if (bccomp($value, 1 << 21) < 0) {
+ return 3;
+ }
+ if (bccomp($value, 1 << 28) < 0) {
+ return 4;
+ }
+ if (bccomp($value, '34359738368') < 0) {
+ return 5;
+ }
+ if (bccomp($value, '4398046511104') < 0) {
+ return 6;
+ }
+ if (bccomp($value, '562949953421312') < 0) {
+ return 7;
+ }
+ if (bccomp($value, '72057594037927936') < 0) {
+ return 8;
+ }
+ return 9;
+ } else {
+ if ($value < 0) {
+ return 10;
+ }
+ if ($value < (1 << 7)) {
+ return 1;
+ }
+ if ($value < (1 << 14)) {
+ return 2;
+ }
+ if ($value < (1 << 21)) {
+ return 3;
+ }
+ if ($value < (1 << 28)) {
+ return 4;
+ }
+ if ($value < (1 << 35)) {
+ return 5;
+ }
+ if ($value < (1 << 42)) {
+ return 6;
+ }
+ if ($value < (1 << 49)) {
+ return 7;
+ }
+ if ($value < (1 << 56)) {
+ return 8;
+ }
+ return 9;
}
- return 9;
}
public static function serializeFieldToStream(
diff --git a/php/src/Google/Protobuf/Internal/InputStream.php b/php/src/Google/Protobuf/Internal/InputStream.php
index c5a76d5d..bf052c2f 100644
--- a/php/src/Google/Protobuf/Internal/InputStream.php
+++ b/php/src/Google/Protobuf/Internal/InputStream.php
@@ -46,6 +46,9 @@ function combineInt32ToInt64($high, $low)
}
}
$result = bcadd(bcmul($high, 4294967296), $low);
+ if ($low < 0) {
+ $result = bcadd($result, 4294967296);
+ }
if ($isNeg) {
$result = bcsub(0, $result);
}
@@ -179,9 +182,9 @@ class InputStream
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);
+ // $bits is 28 in this case.
+ $low |= (($b & 0x7F) << 28);
+ $high = ($b & 0x7F) >> 4;
} else {
$low |= (($b & 0x7F) << $bits);
}
diff --git a/php/src/Google/Protobuf/Internal/Message.php b/php/src/Google/Protobuf/Internal/Message.php
index 3d1f1598..7d1e51e8 100644
--- a/php/src/Google/Protobuf/Internal/Message.php
+++ b/php/src/Google/Protobuf/Internal/Message.php
@@ -175,17 +175,22 @@ class Message
case GPBType::FLOAT:
return 0.0;
case GPBType::UINT32:
- case GPBType::UINT64:
case GPBType::INT32:
- case GPBType::INT64:
case GPBType::FIXED32:
- case GPBType::FIXED64:
case GPBType::SFIXED32:
- case GPBType::SFIXED64:
case GPBType::SINT32:
- case GPBType::SINT64:
case GPBType::ENUM:
return 0;
+ case GPBType::INT64:
+ case GPBType::UINT64:
+ case GPBType::FIXED64:
+ case GPBType::SFIXED64:
+ case GPBType::SINT64:
+ if (PHP_INT_SIZE === 4) {
+ return '0';
+ } else {
+ return 0;
+ }
case GPBType::BOOL:
return false;
case GPBType::STRING:
diff --git a/php/tests/encode_decode_test.php b/php/tests/encode_decode_test.php
index af9c0415..7bb75336 100644
--- a/php/tests/encode_decode_test.php
+++ b/php/tests/encode_decode_test.php
@@ -132,4 +132,39 @@ class EncodeDecodeTest extends TestBase
$to->decode(TestUtil::getGoldenTestUnpackedMessage());
TestUtil::assertTestPackedMessage($to);
}
+
+ public function testDecodeInt64()
+ {
+ // Read 64 testing
+ $testVals = array(
+ '10' => '100a',
+ '100' => '1064',
+ '800' => '10a006',
+ '6400' => '108032',
+ '70400' => '1080a604',
+ '774400' => '1080a22f',
+ '9292800' => '108098b704',
+ '74342400' => '1080c0b923',
+ '743424000' => '108080bfe202',
+ '8177664000' => '108080b5bb1e',
+ '65421312000' => '108080a8dbf301',
+ '785055744000' => '108080e0c7ec16',
+ '9420668928000' => '10808080dd969202',
+ '103627358208000' => '10808080fff9c717',
+ '1139900940288000' => '10808080f5bd978302',
+ '13678811283456000' => '10808080fce699a618',
+ '109430490267648000' => '10808080e0b7ceb1c201',
+ '984874412408832000' => '10808080e0f5c1bed50d',
+ );
+
+ $msg = new TestMessage();
+ foreach ($testVals as $original => $encoded) {
+ $msg->setOptionalInt64($original);
+ $data = $msg->encode();
+ $this->assertSame($encoded, bin2hex($data));
+ $msg->setOptionalInt64(0);
+ $msg->decode($data);
+ $this->assertEquals($original, $msg->getOptionalInt64());
+ }
+ }
}
diff --git a/php/tests/php_implementation_test.php b/php/tests/php_implementation_test.php
index 6b922a9b..ac7c13dc 100644
--- a/php/tests/php_implementation_test.php
+++ b/php/tests/php_implementation_test.php
@@ -368,33 +368,31 @@ class ImplementationTest extends TestBase
$this->assertFalse($input->readVarint64($var));
// Read 64 testing
- if (PHP_INT_SIZE > 4) {
- $testVals = array(
- '10' => '0a000000000000000000',
- '100' => '64000000000000000000',
- '800' => 'a0060000000000000000',
- '6400' => '80320000000000000000',
- '70400' => '80a60400000000000000',
- '774400' => '80a22f00000000000000',
- '9292800' => '8098b704000000000000',
- '74342400' => '80c0b923000000000000',
- '743424000' => '8080bfe2020000000000',
- '8177664000' => '8080b5bb1e0000000000',
- '65421312000' => '8080a8dbf30100000000',
- '785055744000' => '8080e0c7ec1600000000',
- '9420668928000' => '808080dd969202000000',
- '103627358208000' => '808080fff9c717000000',
- '1139900940288000' => '808080f5bd9783020000',
- '13678811283456000' => '808080fce699a6180000',
- '109430490267648000' => '808080e0b7ceb1c20100',
- '984874412408832000' => '808080e0f5c1bed50d00',
- );
-
- foreach ($testVals as $original => $encoded) {
- $input = new InputStream(hex2bin($encoded));
- $this->assertTrue($input->readVarint64($var));
- $this->assertSame($original, $var);
- }
+ $testVals = array(
+ '10' => '0a000000000000000000',
+ '100' => '64000000000000000000',
+ '800' => 'a0060000000000000000',
+ '6400' => '80320000000000000000',
+ '70400' => '80a60400000000000000',
+ '774400' => '80a22f00000000000000',
+ '9292800' => '8098b704000000000000',
+ '74342400' => '80c0b923000000000000',
+ '743424000' => '8080bfe2020000000000',
+ '8177664000' => '8080b5bb1e0000000000',
+ '65421312000' => '8080a8dbf30100000000',
+ '785055744000' => '8080e0c7ec1600000000',
+ '9420668928000' => '808080dd969202000000',
+ '103627358208000' => '808080fff9c717000000',
+ '1139900940288000' => '808080f5bd9783020000',
+ '13678811283456000' => '808080fce699a6180000',
+ '109430490267648000' => '808080e0b7ceb1c20100',
+ '984874412408832000' => '808080e0f5c1bed50d00',
+ );
+
+ foreach ($testVals as $original => $encoded) {
+ $input = new InputStream(hex2bin($encoded));
+ $this->assertTrue($input->readVarint64($var));
+ $this->assertEquals($original, $var);
}
}