Skip to content
This repository has been archived by the owner on May 29, 2018. It is now read-only.

Commit

Permalink
A few more changes to improve the support of negative numbers.
Browse files Browse the repository at this point in the history
  • Loading branch information
bramp committed Feb 12, 2016
1 parent 83bc491 commit 9a3f3ff
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 15 deletions.
36 changes: 24 additions & 12 deletions protocolbuffers.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ public static function size_varint($value) {
*/
public static function decode_varint($encoded) {
checkArgument(is_string($encoded), 'encoded value must be a string of bytes');
checkArgument($encoded !== '', 'encoded value contains no bytes');

$len = strlen($encoded);
if ($len <= self::MAX_PHP_INT_VARINT_LEN) { // TODO lower this on PHP32.
Expand All @@ -238,17 +237,15 @@ public static function decode_signed_varint($encoded) {
// signed extension. To help maintain a accuracy we do it manually
// over the bytes of the varint, by flipping the bits and adding one.

// All but the last bit should be disacard (as it would be above 64bits)
$encoded[$len - 1] = chr(ord($encoded[$len - 1]) & 0x01);
$lastZero = $len - 1;
for ($i = $len - 2; $i >= 0; $i--) {
$len--;
for ($i = 0; $i < $len; $i++) {
$encoded[$i] = chr(~(ord($encoded[$i]) & 0x7F));
if ($encoded[$i] === "\x80" && $lastZero === $i + 1) {
$lastZero = $i + 1;
}
}

$encoded = substr($encoded, 0, $lastZero);
// Drop the last digit as it's above 64bit and not used
$encoded = substr($encoded, 0, $len);
$encoded = rtrim($encoded, "\x80"); // TODO change this to rtrim(\xff) and move above the loop

return -self::decode_varint($encoded) - 1;
} else {
return self::decode_varint($encoded);
Expand Down Expand Up @@ -553,16 +550,31 @@ public static function encode_varint_float($value) {
public static function encode_varint($value) {

if ($value < 0) {
$value = -$value + 1;
$value = -($value + 1);
$negative = true;
} else {
$negative = false;
}

if (is_int($value)) {
return self::encode_varint_float($value);
$encoded = self::encode_varint_int($value);
} elseif (is_float($value)) {
return self::encode_varint_float($value);
$encoded = self::encode_varint_float($value);
} else {
throw new InvalidArgumentException('value must be a integer or float');
}

if ($negative) {
$len = strlen($encoded);
for ($i = $len - 1; $i >= 0; $i--) {
$encoded[$i] = chr(~(ord($encoded[$i])) | 0x80);
}

// Now sign extend
$encoded = str_pad($encoded, 9, "\xff", STR_PAD_RIGHT) . "\x01";
}

return $encoded;
}

/**
Expand Down
9 changes: 6 additions & 3 deletions tests/protocolbuffers_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,24 @@ class VarintProtobufTest extends ProtobufTestCase {

var $tests = array(
-9223372036854775808 => "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01", // -2^63
-9223372036854775800 => "\x88\x80\x80\x80\x80\x80\x80\x80\x80\x01",
-9223372036854775807 => "\x81\x80\x80\x80\x80\x80\x80\x80\x80\x01", // -2^63 + 1
-9223372036854775800 => "\x88\x80\x80\x80\x80\x80\x80\x80\x80\x01", // -2^63 + 8

-72057594037927935 => "\x81\x80\x80\x80\x80\x80\x80\x80\xff\x01", // -2^56 - 1
-72057594037927937 => "\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x01", // -2^56 - 1
-72057594037927936 => "\x80\x80\x80\x80\x80\x80\x80\x80\xff\x01", // -2^56
-72057594037927937 => "\xff\xff\xff\xff\xff\xff\xff\xff\xfe\x01", // -2^56 + 1
-72057594037927935 => "\x81\x80\x80\x80\x80\x80\x80\x80\xff\x01", // -2^56 + 1

-2147483648 => "\x80\x80\x80\x80\xf8\xff\xff\xff\xff\x01", // -2^31
-255 => "\x81\xfe\xff\xff\xff\xff\xff\xff\xff\x01",
-16 => "\xf0\xff\xff\xff\xff\xff\xff\xff\xff\x01",
-8 => "\xf8\xff\xff\xff\xff\xff\xff\xff\xff\x01",
-3 => "\xfd\xff\xff\xff\xff\xff\xff\xff\xff\x01",
-2 => "\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01",
-1 => "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01",
0 => "\x00",
1 => "\x01",
2 => "\x02",
3 => "\x03",
127 => "\x7F",
128 => "\x80\x01",
255 => "\xff\x01",
Expand Down

0 comments on commit 9a3f3ff

Please sign in to comment.