如何让 LZO 处理文件流?

发布于 2024-10-03 04:43:28 字数 2988 浏览 0 评论 0原文

我正在尝试使用 LZO 压缩文件流,但效果不佳。具体来说,在提取 compressFileWithLzo1x 函数创建的存档文件时出现分段错误。

我的 main 函数和原型声明是:

#include <stdio.h>
#include <stdlib.h>
#include "lzo/include/lzo/lzo1x.h"

#define LZO_IN_CHUNK (128*1024L)
#define LZO_OUT_CHUNK (LZO_IN_CHUNK + LZO_IN_CHUNK/16 + 64 + 3)

int compressFileWithLzo1x(const char *inFn, const char *outFn);
int extractFileWithLzo1x(const char *inFn);

int main(int argc, char **argv) {

    const char *inFilename = "test.txt";
    const char *outFilename = "test.txt.lzo1x";

    if ( compressFileWithLzo1x(inFilename, outFilename) != 0 )
        exit(EXIT_FAILURE);

    if ( extractFileWithLzo1x(outFilename) != 0 )
        exit(EXIT_FAILURE);

    return 0;
}

这是我的压缩函数的实现:

int compressFileWithLzo1x(const char *inFn, const char *outFn) {

    FILE *inFnPtr = fopen(outFn, "r");
    FILE *outFnPtr = fopen(outFn, "wb");
    int compressionResult;
    lzo_bytep in;
    lzo_bytep out;
    lzo_voidp wrkmem;
    lzo_uint out_len;
    size_t inResult;

    if (lzo_init() != LZO_E_OK)
        return -1;

    in = (lzo_bytep)malloc(LZO_IN_CHUNK);
    out = (lzo_bytep)malloc(LZO_OUT_CHUNK);
    wrkmem = (lzo_voidp)malloc(LZO1X_1_MEM_COMPRESS);

    do { 
        inResult = fread(in, sizeof(lzo_byte), LZO_IN_CHUNK, inFnPtr);
        if (inResult == 0)
            break;
        compressionResult = lzo1x_1_compress(in, LZO_IN_CHUNK, out, &out_len, wrkmem);
        if ((out_len >= LZO_IN_CHUNK) || (compressionResult != LZO_E_OK))
            return -1;
        if (fwrite(out, sizeof(lzo_byte), (size_t)out_len, outFnPtr) != (size_t)out_len || ferror(outFnPtr))
            return -1;
        fflush(outFnPtr);
    } while (!feof(inFnPtr) && !ferror(inFnPtr));

    free(wrkmem);
    free(out);
    free(in);
    fclose(inFnPtr);
    fclose(outFnPtr);

    return 0;
}

这是我的解压缩函数的实现:

int extractFileWithLzo1x(const char *inFn) {

    FILE *inFnPtr = fopen(inFn, "rb");
    lzo_bytep in = (lzo_bytep)malloc(LZO_IN_CHUNK);
    lzo_bytep out = (lzo_bytep)malloc(LZO_OUT_CHUNK);
    int extractionResult; 
    size_t inResult;
    lzo_uint new_length;

    if (lzo_init() != LZO_E_OK)
        return -1;

    do {
        new_length = LZO_IN_CHUNK;
        inResult = fread(in, sizeof(lzo_byte), LZO_IN_CHUNK, inFnPtr);
        extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);
        if ((extractionResult != LZO_E_OK) || (new_length != LZO_IN_CHUNK))
            return -1;
        fprintf(stderr, "out: [%s]\n", (unsigned char *)out);
    } while (!feof(inFnPtr) && (!ferror(inFnPtr));

    free(in);
    free(out);
    fclose(inFnPtr);

    return 0;
}

分段错误发生在这里:

extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);

这种导致分段的方法有什么问题过错?

我希望这次我没有遗漏任何代码。如果我需要添加更多信息,请随时告诉我。预先感谢您的建议。

I am trying to compress a file stream with LZO and not getting very far. Specifically, I get a segmentation fault when extracting the archive file created by my compressFileWithLzo1x function.

My main function and prototype declarations are:

#include <stdio.h>
#include <stdlib.h>
#include "lzo/include/lzo/lzo1x.h"

#define LZO_IN_CHUNK (128*1024L)
#define LZO_OUT_CHUNK (LZO_IN_CHUNK + LZO_IN_CHUNK/16 + 64 + 3)

int compressFileWithLzo1x(const char *inFn, const char *outFn);
int extractFileWithLzo1x(const char *inFn);

int main(int argc, char **argv) {

    const char *inFilename = "test.txt";
    const char *outFilename = "test.txt.lzo1x";

    if ( compressFileWithLzo1x(inFilename, outFilename) != 0 )
        exit(EXIT_FAILURE);

    if ( extractFileWithLzo1x(outFilename) != 0 )
        exit(EXIT_FAILURE);

    return 0;
}

Here is the implementation of my compression function:

int compressFileWithLzo1x(const char *inFn, const char *outFn) {

    FILE *inFnPtr = fopen(outFn, "r");
    FILE *outFnPtr = fopen(outFn, "wb");
    int compressionResult;
    lzo_bytep in;
    lzo_bytep out;
    lzo_voidp wrkmem;
    lzo_uint out_len;
    size_t inResult;

    if (lzo_init() != LZO_E_OK)
        return -1;

    in = (lzo_bytep)malloc(LZO_IN_CHUNK);
    out = (lzo_bytep)malloc(LZO_OUT_CHUNK);
    wrkmem = (lzo_voidp)malloc(LZO1X_1_MEM_COMPRESS);

    do { 
        inResult = fread(in, sizeof(lzo_byte), LZO_IN_CHUNK, inFnPtr);
        if (inResult == 0)
            break;
        compressionResult = lzo1x_1_compress(in, LZO_IN_CHUNK, out, &out_len, wrkmem);
        if ((out_len >= LZO_IN_CHUNK) || (compressionResult != LZO_E_OK))
            return -1;
        if (fwrite(out, sizeof(lzo_byte), (size_t)out_len, outFnPtr) != (size_t)out_len || ferror(outFnPtr))
            return -1;
        fflush(outFnPtr);
    } while (!feof(inFnPtr) && !ferror(inFnPtr));

    free(wrkmem);
    free(out);
    free(in);
    fclose(inFnPtr);
    fclose(outFnPtr);

    return 0;
}

Here is the implementation of my decompression function:

int extractFileWithLzo1x(const char *inFn) {

    FILE *inFnPtr = fopen(inFn, "rb");
    lzo_bytep in = (lzo_bytep)malloc(LZO_IN_CHUNK);
    lzo_bytep out = (lzo_bytep)malloc(LZO_OUT_CHUNK);
    int extractionResult; 
    size_t inResult;
    lzo_uint new_length;

    if (lzo_init() != LZO_E_OK)
        return -1;

    do {
        new_length = LZO_IN_CHUNK;
        inResult = fread(in, sizeof(lzo_byte), LZO_IN_CHUNK, inFnPtr);
        extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);
        if ((extractionResult != LZO_E_OK) || (new_length != LZO_IN_CHUNK))
            return -1;
        fprintf(stderr, "out: [%s]\n", (unsigned char *)out);
    } while (!feof(inFnPtr) && (!ferror(inFnPtr));

    free(in);
    free(out);
    fclose(inFnPtr);

    return 0;
}

The segmentation fault occurs here:

extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);

What is wrong with this approach that is causing the segmentation fault?

I hope I haven't left any code out this time. Feel free to let me know if I need to add more information. Thanks in advance for your advice.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

肤浅与狂妄 2024-10-10 04:43:28

您正在压缩独立的块。 LZO 解压缩器需要压缩数据的字节长度,因为当它解码 EOF 时,它会检查是否已消耗所有输入字节(如果没有,则返回错误),因此您还需要存储每个压缩块的长度。因此您需要更复杂的文件格式。例如:

# compressing, in python-like pseudocode
ifile = open("data", "rb")
ofile = open("data.mylzo", "wb")
input, input_len = ifile.read(65536)
while input_len > 0:
  compressed, compressed_len = lzo1x(input, input_len)
  compressed_len -= 1 # store len-1 of next block
  if compressed_len < 65536 - 1:
    ofile.write(compressed_len & 255) # be sure of endianess in file formats!
    ofile.write(compressed_len >> 8)
    ofile.write(compressed)
  else:
    ofile.write(255) # incompressible block stored it as-is (saves space & time).
    ofile.write(255)
    ofile.write(input)
  input, input_len = ifile.read(65536)
ofile.close()
ifile.close()

# decompressing, in python-like pseudocode
ifile = open("data.mylzo", "rb")
ofile = open("data", "wb")
compressed_len_s = ifile.read(2)
while len(compressed_len_s) == 2:
  compressed_len = (compressed_len_s[0] | (compressed_len_s[1] << 8)) + 1
  if compressed_len == 65536:
    ofile.write(ifile.read(65536)) # this can be done without copying
  else:
    compressed = ifile.read(compressed_len)
    decompressed = lzo1x_decompress(compressed, compressed_len)
    ofile.write(decompressed)
  compressed_len_s = ifile.read(2)
ofile.close()
ifile.close()

如果您希望能够解压缩块而不跳过(无论是并行解压缩还是随机访问),您应该将压缩块的长度放在第一个块之前的开头。在它们前面加上块的数量。

最后一个块可以短于 64k,并且它可以是不可压缩的,但我们仍然会存储压缩形式,即使它比非压缩形式长,因为只有完整的 64k 块按原样存储。如果整个文件小于 64k,它将增长。

You're compressing independent blocks. The LZO decompressor needs the byte length of the compressed data because when it decodes EOF it checks whether it has consumed all the input bytes (and returns an error if it hasn't) so you need to store the length of each compressed chunk as well. Thus you need a more complex file format. For example:

# compressing, in python-like pseudocode
ifile = open("data", "rb")
ofile = open("data.mylzo", "wb")
input, input_len = ifile.read(65536)
while input_len > 0:
  compressed, compressed_len = lzo1x(input, input_len)
  compressed_len -= 1 # store len-1 of next block
  if compressed_len < 65536 - 1:
    ofile.write(compressed_len & 255) # be sure of endianess in file formats!
    ofile.write(compressed_len >> 8)
    ofile.write(compressed)
  else:
    ofile.write(255) # incompressible block stored it as-is (saves space & time).
    ofile.write(255)
    ofile.write(input)
  input, input_len = ifile.read(65536)
ofile.close()
ifile.close()

# decompressing, in python-like pseudocode
ifile = open("data.mylzo", "rb")
ofile = open("data", "wb")
compressed_len_s = ifile.read(2)
while len(compressed_len_s) == 2:
  compressed_len = (compressed_len_s[0] | (compressed_len_s[1] << 8)) + 1
  if compressed_len == 65536:
    ofile.write(ifile.read(65536)) # this can be done without copying
  else:
    compressed = ifile.read(compressed_len)
    decompressed = lzo1x_decompress(compressed, compressed_len)
    ofile.write(decompressed)
  compressed_len_s = ifile.read(2)
ofile.close()
ifile.close()

If you want to be able to decompress the chunks without skipping (either for decompression in parallel or random access) you should place the lengths of compressed chunks at the beginning, before the first chunk. Precede them with the number of chunks.

The last chunk can be shorter than 64k, and it can be incompressible but we'll still store the compressed form, even though it's longer than the non-compressed form, because only full 64k blocks are stored as-is. If entire file is shorter than 64k, it will grow.

不美如何 2024-10-10 04:43:28

您给出的代码将无法编译(#defines 中的虚假 =inFilePtr 而不是 inFnPtr各地等)。但是:

  1. 压缩时,您没有考虑fread()返回的实际数据量,它很可能小于LZO_IN_CHUNK。 p>

    compressionResult = lzo1x_1_compress(in, LZO_IN_CHUNK, out, &out_len, wrkmem);
    

    应该是

    compressionResult = lzo1x_1_compress(in, inResult, out, &out_len, wrkmem);
    

    (这不太可能是问题,但会在文件末尾添加虚假垃圾。)

  2. 解压缩时,您遇到类似的问题,输入/输出参数是错误的方式,这可能是您的段错误的原因。

    extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);
    

    应该是

    extractionResult = lzo1x_decompress(in, inResult, out, &new_length, NULL);
    

The code you've given won't compile (spurious = in the #defines; inFilePtr instead of inFnPtr in various places, etc.). But:

  1. When compressing, you are not taking account of the actual amount of data returned by the fread(), which might well be less than LZO_IN_CHUNK.

    compressionResult = lzo1x_1_compress(in, LZO_IN_CHUNK, out, &out_len, wrkmem);
    

    should probably be

    compressionResult = lzo1x_1_compress(in, inResult, out, &out_len, wrkmem);
    

    (This is unlikely to be the problem, but will add bogus junk at the end of the file.)

  2. When decompressing, you have a similar problem, and the in / out arguments are the wrong way round, which is likely to be the cause of your segfault.

    extractionResult = lzo1x_decompress(out, LZO_OUT_CHUNK, in, &new_length, NULL);
    

    should probably be

    extractionResult = lzo1x_decompress(in, inResult, out, &new_length, NULL);
    
夜空下最亮的亮点 2024-10-10 04:43:28

我认为您在 int compressFileWithLzo1x 中打开了错误的文件:

FILE *inFnPtr = fopen(outFn, "r");

它应该是

FILE *inFnPtr = fopen(inFn, "r");

I think you are opening the wrong file in int compressFileWithLzo1x:

FILE *inFnPtr = fopen(outFn, "r");

it should be

FILE *inFnPtr = fopen(inFn, "r");
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文