aboutsummaryrefslogtreecommitdiffhomepage
path: root/php/src/Google/Protobuf
diff options
context:
space:
mode:
authorGravatar Paul Yang <TeBoring@users.noreply.github.com>2016-10-25 17:27:05 -0700
committerGravatar GitHub <noreply@github.com>2016-10-25 17:27:05 -0700
commit51c5ff889ccd3836c25f40baafb350f92c9ee103 (patch)
tree39ba93f36167e2ab73c25ac337da0a97a4df4970 /php/src/Google/Protobuf
parent58580da37357941d502805be3ae520441be77728 (diff)
Fix pure php implementation for 32-bit machine. (#2282)
Diffstat (limited to 'php/src/Google/Protobuf')
-rw-r--r--php/src/Google/Protobuf/Internal/GPBUtil.php41
-rw-r--r--php/src/Google/Protobuf/Internal/GPBWire.php47
-rw-r--r--php/src/Google/Protobuf/Internal/InputStream.php66
-rw-r--r--php/src/Google/Protobuf/Internal/Message.php5
-rw-r--r--php/src/Google/Protobuf/Internal/OutputStream.php51
-rw-r--r--php/src/Google/Protobuf/Internal/Type.php175
6 files changed, 155 insertions, 230 deletions
diff --git a/php/src/Google/Protobuf/Internal/GPBUtil.php b/php/src/Google/Protobuf/Internal/GPBUtil.php
index 417a9729..30d7350f 100644
--- a/php/src/Google/Protobuf/Internal/GPBUtil.php
+++ b/php/src/Google/Protobuf/Internal/GPBUtil.php
@@ -37,6 +37,28 @@ use Google\Protobuf\Internal\RepeatedField;
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)
{
@@ -70,9 +92,14 @@ class GPBUtil
public static function checkUint32(&$var)
{
if (is_numeric($var)) {
- $var = intval($var);
if (PHP_INT_SIZE === 8) {
+ $var = intval($var);
$var |= ((-(($var >> 31) & 0x1)) & ~0xFFFFFFFF);
+ } else {
+ if (bccomp($var, 0x7FFFFFFF) > 0) {
+ $var = bcsub($var, "4294967296");
+ }
+ $var = (int) $var;
}
} else {
trigger_error("Expect integer.", E_USER_ERROR);
@@ -82,7 +109,11 @@ class GPBUtil
public static function checkInt64(&$var)
{
if (is_numeric($var)) {
- $var = intval($var);
+ if (PHP_INT_SIZE == 8) {
+ $var = intval($var);
+ } else {
+ $var = bcdiv($var, 1, 0);
+ }
} else {
trigger_error("Expect integer.", E_USER_ERROR);
}
@@ -91,7 +122,11 @@ class GPBUtil
public static function checkUint64(&$var)
{
if (is_numeric($var)) {
- $var = intval($var);
+ if (PHP_INT_SIZE == 8) {
+ $var = intval($var);
+ } else {
+ $var = bcdiv($var, 1, 0);
+ }
} else {
trigger_error("Expect integer.", E_USER_ERROR);
}
diff --git a/php/src/Google/Protobuf/Internal/GPBWire.php b/php/src/Google/Protobuf/Internal/GPBWire.php
index 0e741e15..7e2c124f 100644
--- a/php/src/Google/Protobuf/Internal/GPBWire.php
+++ b/php/src/Google/Protobuf/Internal/GPBWire.php
@@ -32,10 +32,6 @@
namespace Google\Protobuf\Internal;
-use Google\Protobuf\Internal\GPBUtil;
-use Google\Protobuf\Internal\Int64;
-use Google\Protobuf\Internal\Uint64;
-
class GPBWire
{
@@ -150,20 +146,28 @@ class GPBWire
public static function zigZagEncode64($int64)
{
- $a = $int64->copy()->leftShift(1);
- $b = $int64->copy()->rightShift(63);
- $result = $a->bitXor($b);
- $uint64 = Uint64::newValue($result->high, $result->low);
- return $uint64;
+ if (PHP_INT_SIZE == 4) {
+ if (bccomp($int64, 0) >= 0) {
+ return bcmul($int64, 2);
+ } else {
+ return bcsub(bcmul(bcsub(0, $int64), 2), 1);
+ }
+ } else {
+ return ($int64 << 1) ^ ($int64 >> 63);
+ }
}
public static function zigZagDecode64($uint64)
{
- $a = $uint64->copy()->rightShift(1);
- $b = $uint64->oddMask();
- $result = $a->bitXor($b);
- $int64 = Int64::newValue($result->high, $result->low);
- return $int64;
+ if (PHP_INT_SIZE == 4) {
+ if (bcmod($uint64, 2) == 0) {
+ return bcdiv($uint64, 2, 0);
+ } else {
+ return bcsub(0, bcdiv(bcadd($uint64, 1), 2, 0));
+ }
+ } else {
+ return (($uint64 >> 1) & 0x7FFFFFFFFFFFFFFF) ^ (-($uint64 & 1));
+ }
}
public static function readInt32(&$input, &$value)
@@ -227,11 +231,7 @@ class GPBWire
public static function readSfixed64(&$input, &$value)
{
- if (!self::readFixed64($input, $value)) {
- return false;
- }
- $value = Int64::newValue($value->high, $value->low);
- return true;
+ return $input->readLittleEndian64($value);
}
public static function readFloat(&$input, &$value)
@@ -259,7 +259,7 @@ class GPBWire
if (!$input->readVarint64($value)) {
return false;
}
- if ($value->high === 0 && $value->low === 0) {
+ if ($value == 0) {
$value = false;
} else {
$value = true;
@@ -324,8 +324,8 @@ class GPBWire
public static function writeSint64(&$output, $value)
{
- $value = GPBWire::zigZagEncode64(GPBUtil::Int64($value));
- return $output->writeVarint64($value->toInteger());
+ $value = GPBWire::zigZagEncode64($value);
+ return $output->writeVarint64($value);
}
public static function writeFixed32(&$output, $value)
@@ -431,9 +431,8 @@ class GPBWire
public static function sint64Size($value)
{
- $value = GPBUtil::Int64($value);
$value = self::zigZagEncode64($value);
- return self::varint64Size($value->toInteger());
+ return self::varint64Size($value);
}
public static function varint64Size($value)
diff --git a/php/src/Google/Protobuf/Internal/InputStream.php b/php/src/Google/Protobuf/Internal/InputStream.php
index 18d07075..6d6c74e9 100644
--- a/php/src/Google/Protobuf/Internal/InputStream.php
+++ b/php/src/Google/Protobuf/Internal/InputStream.php
@@ -34,6 +34,24 @@ namespace Google\Protobuf\Internal;
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
{
@@ -116,11 +134,23 @@ class InputStream
if (!$this->readVarint64($var)) {
return false;
}
- $var = $var->toInteger() & 0xFFFFFFFF;
+
+ if (PHP_INT_SIZE == 4) {
+ $var = bcmod($var, 4294967296);
+ } else {
+ $var &= 0xFFFFFFFF;
+ }
+
// Convert large uint32 to int32.
- if (PHP_INT_SIZE === 8 && ($var > 0x7FFFFFFF)) {
- $var = $var | (0xFFFFFFFF << 32);
+ if ($var > 0x7FFFFFFF) {
+ if (PHP_INT_SIZE === 8) {
+ $var = $var | (0xFFFFFFFF << 32);
+ } else {
+ $var = bcsub($var, 4294967296);
+ }
}
+
+ $var = intval($var);
return true;
}
@@ -130,7 +160,8 @@ class InputStream
*/
public function readVarint64(&$var)
{
- $result = new Uint64(0);
+ $high = 0;
+ $low = 0;
$count = 0;
$b = 0;
@@ -142,12 +173,27 @@ class InputStream
return false;
}
$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);
$count += 1;
} while ($b & 0x80);
- $var = $result;
+ if (PHP_INT_SIZE == 4) {
+ $var = combineInt32ToInt64($high, $low);
+ } else {
+ $var = ($high & 0xFFFFFFFF) << 32 |
+ ($low & 0xFFFFFFFF);
+ }
return true;
}
@@ -161,7 +207,7 @@ class InputStream
if (!$this->readVarint64($var)) {
return false;
}
- $var = $var->toInteger();
+ $var = (int)$var;
return true;
}
@@ -197,7 +243,11 @@ class InputStream
return false;
}
$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;
}
diff --git a/php/src/Google/Protobuf/Internal/Message.php b/php/src/Google/Protobuf/Internal/Message.php
index 7bdc6a8c..38513e91 100644
--- a/php/src/Google/Protobuf/Internal/Message.php
+++ b/php/src/Google/Protobuf/Internal/Message.php
@@ -210,13 +210,11 @@ class Message
if (!GPBWire::readInt64($input, $value)) {
return false;
}
- $value = $value->toInteger();
break;
case GPBType::UINT64:
if (!GPBWire::readUint64($input, $value)) {
return false;
}
- $value = $value->toInteger();
break;
case GPBType::INT32:
if (!GPBWire::readInt32($input, $value)) {
@@ -227,7 +225,6 @@ class Message
if (!GPBWire::readFixed64($input, $value)) {
return false;
}
- $value = $value->toInteger();
break;
case GPBType::FIXED32:
if (!GPBWire::readFixed32($input, $value)) {
@@ -285,7 +282,6 @@ class Message
if (!GPBWire::readSfixed64($input, $value)) {
return false;
}
- $value = $value->toInteger();
break;
case GPBType::SINT32:
if (!GPBWire::readSint32($input, $value)) {
@@ -296,7 +292,6 @@ class Message
if (!GPBWire::readSint64($input, $value)) {
return false;
}
- $value = $value->toInteger();
break;
default:
user_error("Unsupported type.");
diff --git a/php/src/Google/Protobuf/Internal/OutputStream.php b/php/src/Google/Protobuf/Internal/OutputStream.php
index fcc5ce6d..587ac352 100644
--- a/php/src/Google/Protobuf/Internal/OutputStream.php
+++ b/php/src/Google/Protobuf/Internal/OutputStream.php
@@ -90,8 +90,6 @@ class OutputStream
public function writeRaw($data, $size)
{
if ($this->buffer_size < $size) {
- var_dump($this->buffer_size);
- var_dump($size);
trigger_error("Output stream doesn't have enough buffer.");
return false;
}
@@ -107,15 +105,28 @@ class OutputStream
private static function writeVarintToArray($value, &$buffer, $trim = false)
{
$current = 0;
- if ($trim) {
- $value &= 0xFFFFFFFF;
+
+ $high = 0;
+ $low = 0;
+ if (PHP_INT_SIZE == 4) {
+ GPBUtil::divideInt64ToInt32($value, $high, $low, $trim);
+ } else {
+ if ($trim) {
+ $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));
+ $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++;
}
- $buffer[$current] = chr($value);
+ $buffer[$current] = chr($low);
return $current + 1;
}
@@ -130,14 +141,24 @@ class OutputStream
private static function writeLittleEndian64ToArray($value, &$buffer)
{
- $buffer[0] = chr($value & 0x000000FF);
- $buffer[1] = chr(($value >> 8) & 0x000000FF);
- $buffer[2] = chr(($value >> 16) & 0x000000FF);
- $buffer[3] = chr(($value >> 24) & 0x000000FF);
- $buffer[4] = chr(($value >> 32) & 0x000000FF);
- $buffer[5] = chr(($value >> 40) & 0x000000FF);
- $buffer[6] = chr(($value >> 48) & 0x000000FF);
- $buffer[7] = chr(($value >> 56) & 0x000000FF);
+ $high = 0;
+ $low = 0;
+ if (PHP_INT_SIZE == 4) {
+ GPBUtil::divideInt64ToInt32($value, $high, $low);
+ } else {
+ $low = $value & 0xFFFFFFFF;
+ $high = ($value >> 32) & 0xFFFFFFFF;
+ }
+
+ $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;
}
+
}
diff --git a/php/src/Google/Protobuf/Internal/Type.php b/php/src/Google/Protobuf/Internal/Type.php
deleted file mode 100644
index 088f0e0c..00000000
--- a/php/src/Google/Protobuf/Internal/Type.php
+++ /dev/null
@@ -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;
- }
-}