2014-07-17 40 views
3

为了节省空间,Bitcoin protocol使用他们称之为可变长度整数或varint的整数进行编码。 varint的第一个字节对其长度及其解释进行编码:你可以扩展pack()来处理自定义,可变长度的字段吗?

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"; 
    } 
} 

这工作...但它很不雅观B/C,如果我有很长的字节串嵌入varints,我会阅读到varint的开始,将余数传递给上面的函数,找出编码的varint等等等等。有没有更好的方法来写这个?特别是,我能以某种方式扩展pack()来支持这种结构吗?

回答

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)); 

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

相关问题