Распакуйте файл gzip в память, используя zlib версии 1.1.3 - PullRequest
2 голосов
/ 07 января 2012

У меня есть файл gzip, который находится в памяти, и я хотел бы распаковать его, используя zlib, версия 1.1.3. Uncompress () возвращает -3, Z_DATA_ERROR, указывая, что исходные данные повреждены.

Я знаю, что мой буфер в памяти правильный - если я записываю буфер в файл, он совпадает с моим исходным gzip-файлом.

Формат файла gzip указывает на наличие 10-байтового заголовка, необязательных заголовков, данных и нижнего колонтитула. Можно ли определить, где начинаются данные, и удалить эту часть? Я выполнил поиск по этой теме, и несколько человек предложили использовать inflateInit2 (). Однако в моей версии zlib эта функция закомментирована. Есть ли другие варианты?

Ответы [ 2 ]

1 голос
/ 05 ноября 2012

Я сталкивался с той же проблемой, другая версия zlib (1.2.7)
Я не знаю, почему inflateInit2 () закомментирован.

Без вызова inflateInit2 вы можете сделать следующее:

err = inflateInit(&d_stream);
err = inflateReset2(&d_stream, 31);

inflateReset2 также вызывается inflateInit. Внутри inflateInit WindowBits установлены на 15 (1111 двоичных). Но вы должны установить их на 31 (11111), чтобы заставить работать gzip.

Причина здесь:

внутри inflateReset2 делается следующее:

wrap = (windowBits >> 4) + 1;

, что приводит к 1, если биты окна установлены 15 (1111 двоичный), и к 2, если биты окна установлены 31 (11111)

Теперь, если вы вызываете inflate (), следующая строка в состоянии HEAD проверяет значение состояния-> wrap вместе с магическим числом для gzip

if ((state->wrap & 2) && hold == 0x8b1f) {  /* gzip header */

Итак, с помощью следующего кода я смог выполнить распаковку gzip в памяти: (Примечание: этот код предполагает, что полные данные для распаковки находятся в памяти и что буфер для распакованных данных достаточно большой)

int err;
z_stream d_stream; // decompression stream



d_stream.zalloc = (alloc_func)0;
d_stream.zfree = (free_func)0;
d_stream.opaque = (voidpf)0;

d_stream.next_in  = deflated; // where deflated is a pointer the the compressed data buffer
d_stream.avail_in = deflatedLen; // where deflatedLen is the length of the compressed data
d_stream.next_out = inflated; // where inflated is a pointer to the resulting uncompressed data buffer
d_stream.avail_out = inflatedLen; // where inflatedLen is the size of the uncompressed data buffer

err = inflateInit(&d_stream);
err = inflateReset2(&d_stream, 31);
err = inflateEnd(&d_stream);

Просто комментирование в inflateInit2 () является решением проблемы. Здесь вы можете установить WindowBits напрямую

0 голосов
/ 07 января 2012

Можно ли определить, где начинаются данные, и вырезать эту часть?

Gzip имеет следующее магическое число :

static const unsigned char gzipMagicBytes[] = { 0x1f, 0x8b, 0x08, 0x00 };

Вы можете прочитать поток файлов и найти следующие байты:

static const int testElemSize = sizeof(unsigned char);
static const int testElemCount = sizeof(gzipMagicBytes);

const char *fn = "foo.bar";
FILE *fp = fopen(fn, "rbR");
char testMagicBuffer[testElemCount] = {0};
unsigned long long testMagicOffset = 0ULL;

if (fp != NULL) {
    do {
        if (memcmp(testMagicBuffer, gzipMagicBytes, sizeof(gzipMagicBytes)) == 0) {
            /* we found gzip magic bytes, do stuff here... */
            fprintf(stdout, "gzip stream found at byte offset: %llu\n", testMagicOffset);
            break;
        }
        testMagicOffset += testElemSize * testElemCount;
        fseek(fp, testMagicOffset - testElemCount + 1, SEEK_SET);
        testMagicOffset -= testElemCount + 1;
    } while (fread(testMagicBuffer, testElemSize, testElemCount, fp));
}

fclose(fp);

Получив смещение, вы можете выполнять операции копирования и вставки или перезаписывать другие байты и т. Д.

...