【问题标题】:How this function should be properly ported from PHP to Javascript这个函数应该如何正确地从 PHP 移植到 Javascript
【发布时间】:2020-07-27 13:34:06
【问题描述】:

我正在做一个项目,我需要一个只能从 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

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

完整的文件:

【问题讨论】:

    标签: javascript php binary-data


    【解决方案1】:

    这些方法遇到的问题是按位运算符只能在 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>
    

    【讨论】:

      猜你喜欢
      • 2011-03-21
      • 1970-01-01
      • 2013-10-15
      • 1970-01-01
      • 2021-09-25
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多