LzmaLib: сжать/распаковать буфер в C

Я пытаюсь использовать LzmaLib LzmaCompress() и LzmaDecompress() с буферами, адаптируя предоставленные примеры здесь.

Я тестирую с буфером ~ 3 МБ, и функция сжатия работает нормально (создает сжатый буфер ~ 1,2 МБ), но когда я пытаюсь распаковать, он просто извлекает ~ 300 байт и возвращает SZ_ERROR_DATA.

Несколько извлеченных байтов верны, но я не знаю, почему на этом все останавливается.

Мой код:

#include <stdio.h>
#include <stdlib.h>

#include "LzmaLib.h"

void compress(
    unsigned char **outBuf, size_t *dstLen,
    unsigned char *inBuf, size_t srcLen)
{
    unsigned propsSize = LZMA_PROPS_SIZE;
    *dstLen = srcLen + srcLen / 3 + 128;

    *outBuf = (unsigned char*)malloc(propsSize + *dstLen);

    int res = LzmaCompress(
        (unsigned char*)(*outBuf + LZMA_PROPS_SIZE), dstLen,
        inBuf, srcLen,
        *outBuf, &propsSize,
        -1, 0, -1, -1, -1, -1, -1);

    assert(res == SZ_OK);

    *dstLen = *dstLen + LZMA_PROPS_SIZE;
}

void uncompress(
    unsigned char **outBuf, size_t *dstLen,
    unsigned char *inBuf,  size_t srcLen
) {
    *dstLen = 5000000;
    *outBuf = (unsigned char*)malloc(*dstLen);

    srcLen = srcLen - LZMA_PROPS_SIZE;
    int res = LzmaUncompress(
        *outBuf, dstLen,
        (unsigned char*)(inBuf + LZMA_PROPS_SIZE), &srcLen,
        inBuf, LZMA_PROPS_SIZE);

    assert(res == SZ_OK);
}

void do_compress() {
    FILE* file = fopen("Module.dll", "r");
    size_t size, decSize;
    unsigned char *data, *dec = NULL;

    fseek(file, 0L, SEEK_END);
    size = ftell(file);
    fseek(file, 0L, SEEK_SET);

    data = (unsigned char*)malloc(size);
    fread(data, 1, size, file);
    fclose(file);

    compress((unsigned char**)&dec, &decSize, data, size);

    file = fopen("Module.lzma", "w");
    fwrite(dec, 1, decSize, file);
    fclose(file);
}

void do_uncompress() {
    FILE* file = fopen("Module.lzma", "r");
    size_t size, decSize;
    unsigned char *data, *dec = NULL;

    fseek(file, 0L, SEEK_END);
    size = ftell(file);
    fseek(file, 0L, SEEK_SET);

    data = (unsigned char*)malloc(size);
    fread(data, 1, size, file);
    fclose(file);

    uncompress((unsigned char**)&dec, &decSize, data, size);

    file = fopen("Module_DEC.dll", "w");
    fwrite(dec, 1, decSize, file);
    fclose(file);
}

int main()
{
    do_compress();
    do_uncompress();

    return 0;
}

Если этот код не является лучшим способом сжатия буферов с помощью LzmaLib, я буду рад принять предложения.


person karliwson    schedule 22.11.2016    source источник
comment
Я прохожу dstLen, и проблема сохраняется. Распаковывается только несколько байтов и возвращается ошибка 1 (SZ_ERROR_DATA).   -  person karliwson    schedule 25.11.2016


Ответы (3)


Бьюсь об заклад, проблема скрывается в том, как вы читаете/пишете свои файлы. Вам нужно открыть их в двоичном режиме, чтобы предотвратить любые замены во время операций чтения/записи.

Изменить все экземпляры:

  • fopen(xxx, "r") -> fopen(xxx, "rb")
  • fopen(xxx, "w") -> fopen(xxx, "wb")
person Codeguard    schedule 25.11.2016
comment
Чувак, я не могу сказать слова, о которых сейчас думаю. Это была точная проблема. Спасибо большое. - person karliwson; 25.11.2016
comment
Маленькие ошибки труднее всего найти :) - person Codeguard; 25.11.2016

Я не проверял это специально для LzmaCompress, но большинство других библиотек сжатия, таких как libz, обрабатывают эту функцию, аналогичную стандартным функциям чтения/записи или fread/fwrite, т. е. позволяя вам непрерывно вызывать функции для сжатия все большего количества данных в одном файле. поток. Поэтому в какой-то момент вам придется сказать: «Я закончил, пожалуйста, сбросьте все, что еще не написано». Возможно, вы забыли эту часть. Если нет, то минимальный, полный и проверяемый пример был бы интересен.

person Bodo Thiesen    schedule 22.11.2016
comment
Я понимаю, но LzmaCompress() и LzmaDecompress() — это вспомогательные функции, которые сжимают/распаковывают полный блок данных одним вызовом. - person karliwson; 22.11.2016
comment
тогда часть о MCVE остается. - person Bodo Thiesen; 22.11.2016

При сжатии вы передаете количество сжатых выходных байтов вызывающей стороне. Но ваш буфер содержит LZMA_PROPS_SIZE дополнительных байтов. Таким образом, при записи файла lzma вы фактически забываете последние LZMA_PROPS_SIZE байта, а при последующем чтении они отсутствуют.

person Bodo Thiesen    schedule 22.11.2016
comment
Это правда. Я добавил LZMA_PROPS_SIZE к размеру результата, но проблема осталась. - person karliwson; 22.11.2016