此功能应如何从 PHP 正确移植到 Javascript

How this function should be properly ported from PHP to Javascript

我正在做一个项目,我需要一个只能从 PHP 项目获得的编码:

public static function writeVarLong(int $v) : string{
    return self::writeUnsignedVarLong(($v << 1) ^ ($v >> 63));
}

public static function writeUnsignedVarLong(int $value) : string{
    $buf = "";
    for($i = 0; $i < 10; ++$i){
        if(($value >> 7) !== 0){
            $buf .= chr($value | 0x80); //Let chr() take the last byte of this, it's faster than adding another & 0x7f.
        }else{
            $buf .= chr($value & 0x7f);
            return $buf;
        }

        $value = (($value >> 7) & (PHP_INT_MAX >> 6)); //PHP really needs a logical right-shift operator
    }

    throw new InvalidArgumentException("Value too large to be encoded as a VarLong");
}

这是我的 Javascript 实现:

writeVarLong(v) {
   return this.writeUnsignedVarLong((v << 1) ^ (v >> 63))
}

writeUnsignedVarLong(v) {
   for (let i = 0; i < 10; i++) {
     if ((v >> 7) !== 0) {
        this.writeByte(v | 0x80)
     } else {
        this.writeByte(v & 0x7f)
        break
     }
     v >>= 7
  }
}

当我运行一个简单的测试时,问题就来了,我实例化了两个二进制流,并在它们上面写了一个值,问题是输出不同。

这是 PHP 测试和输出:

$stream = new NetworkBinaryStream();
$stream->putVarLong(422212465606656);
var_dump(bin2hex($stream->buffer));
// Output: 8080c2808080c001

这是 Javascript 测试和输出:

let stream = new PacketBinaryStream()
stream.writeVarLong(422212465606656)
console.log(stream.buffer)
// Output: 80 80 42

我们可以看到输出是不同的

完整文件:

这些方法遇到了按位运算符仅在 32 位中工作的问题,因此 64 位数字在序列化之前被截断了。

您可以使用 BigInt 解决此问题。

const BinaryStream = require('jsbinaryutils')

class PacketBinaryStream extends BinaryStream {
    writeVarLong(v) {
        let bi = BigInt(v);
        return this.writeUnsignedVarLong((bi << 1n) ^ (bi >> 63n))
    }

    writeUnsignedVarLong(v) {
        let bi = BigInt(v);
        for (let i = 0; i < 10; i++) {
            if ((bi >> 7n) !== 0n) {
                this.writeByte(Number((bi | 0x80n)));
            } else {
                this.writeByte(Number((bi & 0x7fn)));
                break
            }
            bi >>= 7n
        }
    }
}

let toWrite = 422212465606656;
let stream = new PacketBinaryStream();
stream.writeVarLong(toWrite);
console.log(stream.buffer);

// Output: <Buffer 80 80 c2 80 80 80 c0 01>