Browse Source

PHP fix int64 decoding (#2516)

* fix int64 decoding

* fix int64 decoding + tests
Sufir 8 years ago
parent
commit
2bddffc993

+ 47 - 28
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;
     }
 

+ 30 - 0
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()