From 2bddffc993db05df57b6ebaea18f42c7b31753e9 Mon Sep 17 00:00:00 2001 From: Sufir Date: Sun, 8 Jan 2017 22:50:50 +0300 Subject: PHP fix int64 decoding (#2516) * fix int64 decoding * fix int64 decoding + tests --- php/src/Google/Protobuf/Internal/InputStream.php | 75 +++++++++++++++--------- php/tests/php_implementation_test.php | 30 ++++++++++ 2 files changed, 77 insertions(+), 28 deletions(-) diff --git a/php/src/Google/Protobuf/Internal/InputStream.php b/php/src/Google/Protobuf/Internal/InputStream.php index 6d6c74e9..c5a76d5d 100644 --- a/php/src/Google/Protobuf/Internal/InputStream.php +++ b/php/src/Google/Protobuf/Internal/InputStream.php @@ -160,40 +160,59 @@ class InputStream */ public function readVarint64(&$var) { - $high = 0; - $low = 0; $count = 0; - $b = 0; - - do { - if ($this->current === $this->buffer_end) { - return false; - } - if ($count === self::MAX_VARINT_BYTES) { - return false; - } - $b = ord($this->buffer[$this->current]); - $bits = 7 * $count; - if ($bits >= 32) { - $high |= (($b & 0x7F) << ($bits - 32)); - } else if ($bits > 25){ - $high_bits = $bits - 25; - $low = ($low | (($b & 0x7F) << $bits)) & (int) 0xFFFFFFFF; - $high = $b & ((0x1 << $high_bits) -1); - } else { - $low |= (($b & 0x7F) << $bits); - } - - $this->advance(1); - $count += 1; - } while ($b & 0x80); if (PHP_INT_SIZE == 4) { + $high = 0; + $low = 0; + $b = 0; + + do { + if ($this->current === $this->buffer_end) { + return false; + } + if ($count === self::MAX_VARINT_BYTES) { + return false; + } + $b = ord($this->buffer[$this->current]); + $bits = 7 * $count; + if ($bits >= 32) { + $high |= (($b & 0x7F) << ($bits - 32)); + } else if ($bits > 25){ + $high_bits = $bits - 25; + $low = ($low | (($b & 0x7F) << $bits)) & (int) 0xFFFFFFFF; + $high = $b & ((0x1 << $high_bits) -1); + } else { + $low |= (($b & 0x7F) << $bits); + } + + $this->advance(1); + $count += 1; + } while ($b & 0x80); + $var = combineInt32ToInt64($high, $low); } else { - $var = ($high & 0xFFFFFFFF) << 32 | - ($low & 0xFFFFFFFF); + $result = 0; + $shift = 0; + + do { + if ($this->current === $this->buffer_end) { + return false; + } + if ($count === self::MAX_VARINT_BYTES) { + return false; + } + + $byte = ord($this->buffer[$this->current]); + $result |= ($byte & 0x7f) << $shift; + $shift += 7; + $this->advance(1); + $count += 1; + } while ($byte > 0x7f); + + $var = $result; } + return true; } diff --git a/php/tests/php_implementation_test.php b/php/tests/php_implementation_test.php index 4f626f1c..6b922a9b 100644 --- a/php/tests/php_implementation_test.php +++ b/php/tests/php_implementation_test.php @@ -366,6 +366,36 @@ class ImplementationTest extends TestBase $this->assertSame(32768, $var); } $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); + } + } } public function testReadVarint32() -- cgit v1.2.3