使用 Perl 解压缩 LZ4 blob

Uncompressing a LZ4 blob with Perl

我在 SQLite 数据库中有一个 table,用于存储使用 LZ4 算法压缩的 blob。我正在尝试使用 Compress::LZ4 中的 decompress/uncompress 函数,但没有取得任何成功。

示例 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>[=12=][=12=]\xF7\xD6df\xF1mBXML\xA1\aVersion\xA1Type\xA1Id\xA1Ref\xA1Size\xA1use\xA1expr\xA1value\xA1data\xA1/Serialization\xA1\aPoints3\xA1\tuser_ E[=12=]\xF0\bvertices\xA1double\xA1\bhas_attr\xA1\n[=12=]\xC7object_ids\xA1\n\f[=12=]\xF1Mitem\xA1\tis_active\xA0~B\n\x8C[=12=][=12=][=12=]\xAA[=12=]\xA4\x82\x88\x80\x82\x82\xA6B\b\x80B \b\x88B\x93[=12=][=12=][=12=]`\xACu\xCF\xBF[=12=][=12=][=12=][=12=]\xCC\xF8\xC2?[=12=][=12=][=12=][=12=][=12=]\x004\@[=12=][=12=][=12=] \xAA\xEF\xA9\x001h\xC5\xB1\b[=12=]\xD0[=12=][=12=]$\@B\x85B\x87B C[=12=]\xF0\aB\"[=12=]\x88B$\x85B\"[=12=]\x88B\ $\x85"

但是 decompress/uncompress 功能只是 return 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 数据的正确方法是什么?

您的数据看起来像是经过 LZ4 压缩并以四个字节为前缀 "LZ4" 大概是作为格式指示符

接下来的四个字节 ">[=13=][=13=]" 是小端原始大小字段,计算结果为 318 字节,这是合理的。 decompress 库函数需要这个字段

所以理论上你应该可以写

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

并得到正确的结果。然而,这对我来说也是 undef 的值,这表明数据以某种方式损坏

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

"df\xF1mBXML\xA1\aVersion\xA1Type\xA1Id\xA1Ref\xA1Size\xA1use\xA1expr\xA1value\xA1data\xA1/http://www.slb.com/Petrel/2011/03/Serialization\xA1\aPoints3\xA1\tuser_E[=11=]\xF0\bvertices\xA1double\xA1\bhas_attr\xA1\n[=11=]\xC7object_ids\xA1\n\f[=11=]\xF1Mitem\xA1\tis_active\xA0~B\n\x8C[=11=][=11=][=11=]\xAA[=11=]\xA4\x82\x88\x80\x82\x82\xA6B\b\x80"

是字面意思,从它包含的可读文本的数量可以猜到

接下来的两个字节,"B" 应指示已翻译缓冲区内的偏移量,应从中复制数据。不幸的是,它的计算结果为 6210,而正如我们所见,缓冲区到目前为止只有 229 字节长。这大概是数据导致 decompress 函数停滞和 return undef

的地方

这是我对您的数据的最大了解。希望对你有帮助