~earboxer/bare-mess-php

5299c3ecb318e76a19a001d67b384a711c41a1ff — Zach DeCook 1 year, 11 months ago 07fd06e
Int: Fix implementation

Previously, these were encoded (and decoded) incorrectly.
2 files changed, 48 insertions(+), 11 deletions(-)

M src/Integer.php
M tests/PrimitivesTest.php
M src/Integer.php => src/Integer.php +11 -5
@@ 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;

M tests/PrimitivesTest.php => tests/PrimitivesTest.php +37 -6
@@ 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()