Commit d1fde361 authored by Bo Yang's avatar Bo Yang

Fix int64 decoding on 32-bit machines.

parent c871ce6e
......@@ -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;
......
......@@ -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(
......
......@@ -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);
}
......
......@@ -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:
......
......@@ -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());
}
}
}
......@@ -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);
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment