你可以扩展pack()来处理自定义的可变长度字段吗?

时间:2014-07-17 08:36:28

标签: perl

为了节省空间,Bitcoin protocol使用他们称为可变长度整数或变量的整数来编码它们的整数。 varint的第一个字节对其长度及其解释进行编码:

FirstByte  Value
< 0xfd     treat the byte itself as an 8 bit integer
0xfd       next 2 bytes form a 16 bit integer
0xfe       next 4 bytes form a 32 bit integer
0xff       next 8 bytes form a 64 bit integer

(所有整数都是小端和无符号)。我编写了以下函数来解压缩varints:

my $varint = "\xfd\x00\xff"; # \x00\xff in little endian == 65280 
say unpack_varint($varint);  # print 65280

sub unpack_varint{
    my $v = shift;
    my $first_byte = unpack "C", $v;
    say $first_byte;
    if ($first_byte < 253) { # \xfd == 253
        return $first_byte;
    }
    elsif ($first_byte == 253){
        return unpack "S<", substr $v, 1, 2;
    }
    elsif ($first_byte == 254){
        return unpack "L<", substr $v, 1, 4;
    }
    elsif ($first_byte == 255){
        return unpack "Q<", substr $v, 1, 8;
    }
    else{
        die "error";
    }
}

这很有效...但是如果我有一个带有嵌入式varint的长字节串,它的非常优雅的b / c,我必须读取varint的开头,将余数传递给上面的函数,找出多长时间编码的varint是等等。有没有更好的方法来写这个?特别是,我可以以某种方式扩展pack()来支持这种结构吗?

1 个答案:

答案 0 :(得分:1)

您可以创建一组shift_$type函数来读取和删除给定字符串开头的某些值,因此您的代码将变为如下所示:

my $buffer = ...;

my $val1 = shift_varint($buffer);
my $val2 = shift_string($buffer);
my $val3 = shift_uint32($buffer);
...

您还可以添加多记录“移位器”:

my ($val1, $val2, $val3) = shift_multi($buffer, qw(varint string uint32));

如果你需要更高的速度,你也可以编写一个编译器,它可以将一组类型转换为解包器子。