@@ 23,6 23,7 @@ class Integer
if (! (ord($mess[$i - 1]) & 0b10000000) ) {
$mess = substr($mess, $i);
$this->value *= $sign;
+ $this->value -= (int)($sign == -1);
return;
}
// TODO: Throw an error if $mess is empty here.
@@ 34,17 35,22 @@ class Integer
public function mess()
{
$mess = '';
- // The number of bytes should be greater than or equal to the number required,
- // abs(value * 2) < pow(2, 7 * bytes)
- $bytes = floor(log(abs($this->value) + 1, 2) / 7) + 1;
- $bits = (abs($this->value) << 1 & 0b01111110) + ($this->value < 0);
+ $isNeg = $this->value < 0 ? true : false;
+ // Unsigned value that follows the sign bit.
+ $uval = abs($this->value)-$isNeg;
+ // The number of bytes MUST be equal to the number required.
+ // $uval < pow(2, 6 + (7 * (bytes - 1)))
+ $bitcount = (int)floor(log($uval,2)) + 1;
+ $bytes = 1 + ceil( ($bitcount - 6)/7 );
+
+ $bits = ($uval << 1 & 0b01111110) + $isNeg;
if ($bytes != 1) {
$bits = $bits | 0b10000000;
}
$mess .= chr($bits);
for ($i = 1; $i < $bytes; $i++) {
// BARE encodes integers as little-endian (least significant first),
- $bits = (abs($this->value) >> (($i * 7)-1)) & 0b01111111;
+ $bits = ($uval >> (($i * 7)-1)) & 0b01111111;
// with the most significant bit being set for all except the last byte.
if ($i != $bytes - 1) {
$bits = $bits | 0b10000000;
@@ 71,24 71,24 @@ class PrimitivesTest extends TestCase
// Various equivalent ints.
$mess = "\xC1\x80\x00\xC1\x00\x41";
$int = Bare::construct($mess, 0);
- $this->assertEquals(-32, $int);
+ $this->assertEquals(-33, $int);
$int2 = Bare::construct($mess, 0);
- $this->assertEquals(-32, $int2);
+ $this->assertEquals(-33, $int2);
$int3 = Bare::construct($mess, 0);
- $this->assertEquals(-32, $int3);
+ $this->assertEquals(-33, $int3);
$this->assertEquals('', $mess);
$int = 300;
$this->assertEquals(UInt::fromValue(600)->mess(), Bare::mess($int));
- // This is usually PHP_INT_MIN - 1 (BARE's ints are zig-zag encoded).
+ // This is usually PHP_INT_MIN + 1 (BARE's ints are zig-zag encoded).
$int = Integer::fromValue(-9223372036854775807);
// Test round-tripping
$mess = $int->mess();
$int2 = new Integer($mess);
$this->assertEquals('', $mess);
- $this->assertEquals(-9223372036854775807, $int->get());
- $this->assertEquals(-9223372036854775807, $int2->get());
+ $this->assertEquals(-9223372036854775807, $int->get(), "Integer didn't store its value.");
+ $this->assertEquals(-9223372036854775807, $int2->get(), "Integer failed to round-trip.");
// Test largest value
$int = Integer::fromValue(9223372036854775807);
@@ 97,6 97,37 @@ class PrimitivesTest extends TestCase
$this->assertEquals('', $mess);
$this->assertEquals(9223372036854775807, $int->get());
$this->assertEquals(9223372036854775807, $int2->get());
+
+ // Zig-zag encoding?
+ $int->set(0);
+ $this->assertEquals("\x00", $int->mess());
+ $int->set(-1);
+ $this->assertEquals("\x01", $int->mess(), "Int -1 encoded incorrectly.");
+ $int->set(1);
+ $this->assertEquals("\x02", $int->mess());
+
+ $mess = "\x00";
+ $int = new Integer($mess);
+ $this->assertEquals('', $mess);
+ $this->assertEquals(0, $int->get());
+
+ // The encoder MUST encode int using the minimum necessary number of octets
+ $int->set(63);
+ $this->assertEquals("\x7e", $int->mess());
+ $int->set(-63);
+ $this->assertEquals("\x7d", $int->mess(), "Int -63 encoded incorrectly.");
+ $int->set(64);
+ $this->assertEquals("\x80\x01", $int->mess(), "Int 64 encoded incorrectly.");
+ $int->set(-64);
+ $this->assertEquals("\x7f", $int->mess());
+ $int->set(65);
+ $this->assertEquals("\x82\x01", $int->mess());
+ $int->set(-65);
+ $this->assertEquals("\x81\x01", $int->mess());
+ $int->set(255);
+ $this->assertEquals("\xfe\x03", $int->mess());
+ $int->set(-255);
+ $this->assertEquals("\xfd\x03", $int->mess());
}
public function testIs()