使用Perl解压LZ4 blob

5
我在SQLite数据库中有一张表,存储着使用LZ4算法压缩的二进制大对象。我尝试使用Compress::LZ4中的解压/解压缩函数,但没有成功。
可以从这里下载示例SQLite数据库。
以下是我连接到SQLite数据库并获取二进制大对象的方法:
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\a版本\xA1\4类型\xA1\2标识符\xA1\3引用\xA1\4大小\xA1\3使用\xA1\4表达式\xA1\5值\xA1\4数据\xA1/序列化\xA1\aPoints3\xA1\t用户_E\0\xF0\16\b顶点\xA1\6双精度\xA1\b有属性\xA1\16\n\0\xC7对象ID\xA1\n\f\0\xF1M\4项\xA1\t是否活跃\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\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"
但是解压函数只返回未定义值。解压后的数据应该类似于(以下输出由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数据?


你正在使用哪种方法来压缩数据?看起来压缩算法不兼容。 - bolav
我不知道具体的方法,我所知道的唯一信息是它是LZ4压缩的。 - user2006190
看看这个关于魔法的邮件。你的例子看起来有一些魔法(LZ4),所以它看起来不像是标准压缩。 - bolav
1
嗯,嘿!所以,你有没有运气做这个?因为我正在做完全相同的事情。当然,一个Java库设法用12个字节的偏移量解压缩数据,但由于未压缩的数据是BXML,所以你得在C#中进行操作。无论如何,我希望你告诉我你是否已经把它搞定了。 - Mostafa Zeinali
1个回答

2

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

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

因此,理论上您应该能够编写以下代码:

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

我需要得到正确的结果。然而,这也导致了一个undef的值,这表明数据在某种程度上已经损坏。

可以确定的是,大部分数据最终未经压缩。紧随长度字段后面的两个字节是"\xF7\xD6",这表明接下来的数据是229个字节的文字数据(第一个字节的高四位为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"

“literal”是字面意思,很容易通过它所包含的可读文本量来猜测。

接下来的两个字节,“B\30”,应该表示从已翻译缓冲区中需要拷贝数据的偏移量。不幸的是,这将被解释为6210,而我们已经看到,目前缓冲区只有229个字节长。这很可能是导致decompress函数失败并返回undef的数据原因。

这就是我对你的数据所能理解的最好描述。希望它能有所帮助。


谢谢你指出方向。我花了一整天的时间试图理解LZ4压缩数据的结构,现在我明白为什么它不起作用了。 - user2006190

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接