使用Perl解压缩LZ4 blob

时间:2015-12-25 08:45:21

标签: perl sqlite lz4

我在SQLite数据库中有一个表,用于存储使用LZ4算法压缩的blob。我试图使用Compress :: LZ4中的解压缩/解压缩功能,但没有取得任何成功。

示例SQLite数据库可以是downloaded from here

以下是我如何连接到SQLite数据库并获取blob:

use DBI; 
use Data::Dump; 
use MIME::Base64; 
use Compress::LZ4;    

my $dbh = DBI->connect("dbi:SQLite:dbname=$ARGV[0]","","");   
$sth = $dbh->prepare("select blob_data from blob_parts where data_fk = 6");
$sth->execute();   
$result = $sth->fetch;   
$blob = $result->[0];

dd $blob;
dd (decompress($blob));

$sth->finish();  
$dbh->disconnect;

对于我在此示例代码中选择的特定blob(data_fk = 6),dd输出以下内容:

  

“LZ4 \ 1> \ 1 \ 0 \ 0 \ XF7 \ xD6df \ xF1mBXML \ 1 \ XA1 \厌恶\ XA1 \ 4Type \ XA1 \ 2ID \ XA1 \ 3Ref \ XA1 \ 4Size \ XA1 \ 3使用\ XA1 \ 4expr \ XA1 \ 5value \ XA1 \ 4数据\ XA1 /串行化\ XA1 \ aPoints3 \ XA1 \ tuser_   È\ 0 \ XF0 \ 16个\ bvertices \ XA1 \ 6double \ XA1 \ bhas_attr \ XA1 \ 16 \ n \ 0 \ xC7object_ids \ XA1 \ n \˚F\ 0 \ xF1M \ 4item \ XA1 \ tis_active \ XA0〜乙\ 20 \ ñ\ 22 \ 6 \ 4 \ x8C \ 1 \ 0 \ 0 \ 0 \ 6 \ 2 \ XAA \ 24 \ 6 \ 0 \ XA4 \ X82 \ X88 \ 2 \ X80 \ X82 \ X82 \ xA6B \ 26 \ 6 \ b \ X80 \ 1B \ 30   \ 6 \ B \ X88 \ 2 \ 3B \ 32 \ 1 \ X93 \ 6 \ 0 \ 0 \ 0` \ xACu \ XCF \ XBF \ 0 \ 0 \ 0 \ 0 \ XCC \ XF8 \ XC2?\ 0 \ 0 \ 0 \ 0 \ 0 \ X004 \ @ \ 0 \ 0 \ 0   \ XAA \ XEF版权所有\ xA9 \ 20 \ x001h \ XC5 \ XB1 \ B \ 0 \ XD0 \ 0 \ 0 \ $ \ @ \ 1B \ 34 \ x85B \ 36 \ x87B   C \ 0 \ xF0 \ aB \“\ 6 \ 0 \ x88 \ 3B \ $ \ x85 \ 1B \”\ 6 \ 0 \ x88 \ 3B \ $ \ x85 \ 1 \ 1 \ 1“

但是解压缩/解压缩功能只返回undef。未压缩的数据应该类似(以下输出由XML转换器生成):

<?xml version="1.0" encoding="utf-8"?>
<MultiStreamDocument>
<!-- Stream 1 -->
<?xml version="1.0" encoding="utf-8"?>
<data xmlns="" Id="1" Type="Points3" Version="1 2 0 1 1">
    <user_data Size="0"></user_data>
    <vertices Size="2">
        <double>-0.24577860534191132</double>
        <double>0.14821767807006836</double>
        <double>20</double>
        <double>0.050656620413064957</double>
        <double>0.069418430328369141</double>
        <double>10</double>
    </vertices>
    <has_attr>false</has_attr>
    <has_object_ids>true</has_object_ids>
    <object_ids Size="2">
        <item Version="3">
            <is_active>false</is_active>
        </item>
        <item Version="3">
            <is_active>false</is_active>
        </item>
    </object_ids>
</data><!-- Stream size: 126 bytes -->
</MultiStreamDocument>

从此SQLite数据库获取未压缩的blob数据的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

您的数据看起来像是LZ4压缩的,并且前缀为四个字节"LZ4\1",可能是格式指示符

接下来的四个字节">\1\0\0"是一个little-endian原始大小字段,其值为318字节,这是合理的。 decompress库函数需要此字段

所以理论上,你应该能够写

$blob = substr($blob(4);
dd decompress($blob);

并获得正确的结果。但是,对我来说这也会导致undef的值,这表明数据已经被破坏了

可以肯定的是,大多数数据最终都是未压缩的。长度字段后面的两个字节是"\xF7\xD6",表示后面的数据是229字节的文字数据(第一个字节的上部nybl - 0xF - 加上第二个字​​节 - 0xD6 - 是0xE5或229) 。所以这部分数据

"df\xF1mBXML\1\xA1\aVersion\xA1\4Type\xA1\2Id\xA1\3Ref\xA1\4Size\xA1\3use\xA1\4expr\xA1\5value\xA1\4data\xA1/http://www.slb.com/Petrel/2011/03/Serialization\xA1\aPoints3\xA1\tuser_E\0\xF0\16\bvertices\xA1\6double\xA1\bhas_attr\xA1\16\n\0\xC7object_ids\xA1\n\f\0\xF1M\4item\xA1\tis_active\xA0~B\20\n\22\6\4\x8C\1\0\0\0\6\2\xAA\24\6\0\xA4\x82\x88\2\x80\x82\x82\xA6B\26\6\b\x80\1"

是字面意思,可以通过它包含的可读文本量来猜测

以下两个字节"B\30"应指示应从中复制数据的已转换缓冲区中的偏移量。不幸的是,这个评估为6210,而我们已经看到,到目前为止缓冲区只有229个字节。这可能是数据导致decompress函数无效并返回undef

的地方

这是我能用得最好的数据。我希望它有所帮助