Мне нужно распаковать некоторые сжатые zlib файлы, найденные в данных сохранения игры.У меня нет доступа к источнику игры.Каждый файл начинается с 0x789C
, что говорит мне, что они действительно сжаты с помощью zlib.Однако все вызовы для раздувания этих файлов не могут полностью распаковать и вернуть Z_DATA_ERROR
.Использование zlib версий 1.2.5, 1.2.8 и 1.2.11 с одинаковыми результатами.
Несмотря на то, что zlib сообщает мне, что входные данные повреждены, я уверен, что это не так, поскольку игра способнараспаковывать эти файлы без проблем И это не изолировано ни одному потоку данных.У меня сотни тысяч уникальных потоков данных, сжатых одинаково, и все они выбрасывают Z_DATA_ERROR
где-то в середине декомпрессии.
Кроме того, частично распакованные данные, которые успешнораспакован, правильно.Вывод точно такой, как ожидалось.
Кроме того, примерно в 10% случаев zlib будет распаковывать весь файл, однако результат будет неправильным.Большие фрагменты распакованных данных содержат один и тот же байт, повторяемый снова и снова, что говорит мне, что это был ложный положительный результат.
Вот мой код декомпрессии:
//QByteArray is a Qt wrapper for a char *
QByteArray Compression::DecompressData(QByteArray data)
{
QByteArray result;
int ret;
z_stream strm;
static const int CHUNK_SIZE = 1;//set to 1 just for debugging
char out[CHUNK_SIZE];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = data.size();
strm.next_in = (Bytef*)(data.data());
ret = inflateInit2(&strm, -15);
if (ret != Z_OK)
{
qDebug() << "init error" << ret;
return QByteArray();
}
do
{
strm.avail_out = CHUNK_SIZE;
strm.next_out = (Bytef*)(out);
ret = inflate(&strm, Z_NO_FLUSH);
qDebug() << "debugging output: " << ret << QString::number(strm.total_in, 16);//This tells me which input byte caused the failure
Q_ASSERT(ret != Z_STREAM_ERROR);
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return result;
}
result.append(out, CHUNK_SIZE - strm.avail_out);
} while (strm.avail_out == 0);
inflateEnd(&strm);
return result;
}
Вот вставка изданные файла примера сжатые данные с удаленным 0x789C
и конечным CRC.Я могу предоставить буквально бесконечные примеры файлов.Все они имеют одну и ту же проблему.
Выполнение этих данных с помощью вышеуказанной функции правильно распаковывает начало потока, но приводит к сбою входного байта 0x18C
.Вы можете сказать, что он распакован правильно, когда начало файла начинается с 0x000B
, а распакованные данные длиннее входных данных.
Хотелось бы знать больше о сжатии с дефляцией, чтобы решить эту проблему самостоятельно.Мои первые мысли заключаются в том, что игра решила использовать пользовательскую версию zlib или чтобы zlib нужно было предоставить дополнительный параметр, чтобы правильно распаковать ее.Я много раз спрашивал и много раз пробовал, и мне действительно нужен кто-то со знанием предмета, чтобы взвесить здесь.Спасибо за ваше время!