drslump / Protobuf-PHP

PHP implementation of Google's Protocol Buffers with a protoc plugin compiler
http://drslump.github.com/Protobuf-PHP/
MIT License
462 stars 163 forks source link

Wrong value UINT64 #35

Closed kpachbiu88 closed 10 years ago

kpachbiu88 commented 10 years ago

TYPE_UINT64 Binary compiler, function decode()

Value 76561198028888080 -> 85399568

How convert 85399568 in 76561198028888080 again?

drslump commented 10 years ago

Unfortunately PHP doesn't offer great support for numbers so it's not possible to properly support 64bit integers without using a specialised extension like GMP or BC Math. I'm afraid the library is not able to decode these numbers, it can encode them using those extensions though).

Protobuf encodes UINT64 as a varint so in order to support large numbers you would need to extend the varint method in the Binary codec Reader class to use and algorithm compatible with big numbers. This is not done by default because it would impact heavily on the performance. If using GMP for example, it could be something like the following:

public function varint()
{
    $result = gmp_init(0, 10);
    $shift = gmp_init(0, 10);
    do {
        $byte = $this->byte();
        $result = gmp_or($result, gmp_mul($byte & 0x7f, gmp_pow(2, $shift)));
        $result |= ($byte & 0x7f) << $shift;
        $shift = gmp_add($shift, 7);
    } while ($byte > 0x7f);

    //  return an int if it's within limits or a gmp_resource if it's not
    if (gmp_cmp($result, PHP_INT_MAX) < 0) {
        return gmp_intval($result);
    } else {
        return $result;
    }
}