Распаковка капли LZ4 с помощью Perl
У меня есть таблица в базе данных 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;
Для конкретного большого двоичного объекта, который я выбираю в этом примере кода (data_fk=6), dd выводит следующее:
"LZ4 \ 1> \ 1 \ 0 \ 0 \ xF7 \ xD6df \ xF1mBXML \ 1 \ xÀ1 \ Отвращение \ xÀ1\4Type\xÀ1\2ID \ xÀ1\3Ref\xÀ1 \ 4size\xÀ1 \ 3Use \ xÀ1 \ 4expr \ xÀ1\5значение \xA1\4data\xA1/ Сериализация \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~ В \ 20 \ N \22\6\4\x8C\1\0\0\0\6\2\ Хаа \ 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>
Как правильно получить несжатые данные BLOB-объектов из этой базы данных SQLite?
1 ответ
Ваши данные выглядят так, как будто они сжаты 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"
буквально, как можно догадаться по количеству читаемого текста, который он содержит
Следующие два байта, "B\30"
должен указывать смещение в преобразованном буфере, из которого должны быть скопированы данные. К сожалению, это оценивается в 6210, тогда как, как мы видели, буфер до сих пор имеет длину всего 229 байт. Это, вероятно, где данные вызывают decompress
функция препятствовать и возвращаться undef
Это лучшее, что я могу сделать из ваших данных. Я надеюсь, что это помогает