2010-11-20 26 views
2

J'essaie de compresser un flux de fichier avec LZO et ne pas aller très loin. Plus précisément, j'obtiens une erreur de segmentation lors de l'extraction du fichier archive créé par ma fonction compressFileWithLzo1x.Comment faire fonctionner LZO avec un flux de fichier?

Mes fonctions main et déclarations prototypes sont:

#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; 
} 

Voici la mise en œuvre de ma fonction de compression:

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; 
} 

est ici la mise en œuvre de ma fonction de décompression:

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; 
} 

L'erreur de segmentation se produit ici:Quel est le problème avec cette approche qui provoque l'erreur de segmentation?

J'espère ne pas avoir laissé de code cette fois-ci. N'hésitez pas à me faire savoir si j'ai besoin d'ajouter plus d'informations. Merci d'avance pour votre conseil.

Répondre

1

Le code que vous avez donné ne compilera pas (= parasite dans le #defines, inFilePtr au lieu de inFnPtr en divers endroits, etc.). Mais:

  1. Lors de la compression, vous ne prenez pas en compte le montant réel des données renvoyées par le fread(), ce qui pourrait bien être inférieure à LZO_IN_CHUNK.

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

    devrait probablement

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

    (Il est peu probable d'être le problème, mais ajoutera indésirable faux à la fin du fichier.)

  2. lors du décompactage, vous avez problème similaire, et les arguments in/out sont à l'envers, ce qui est susceptible d'être la cause de votre segfault.

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

    devrait probablement

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

Se rapprocher, je pense, mais faire des déclarations 'fprintf()' avant et après la ' lzo1x_1_compress() 'call (qui regarde les tampons' in' et 'out') suggère que les données textuelles ne sont pas compressées. –

2

Vous comprimant des blocs indépendants. Le décompresseur LZO a besoin de la longueur en octets des données compressées car lorsqu'il décode EOF, il vérifie s'il a consommé tous les octets d'entrée (et renvoie une erreur si ce n'est pas le cas), donc vous devez stocker la longueur de chaque bloc compressé. . Vous avez donc besoin d'un format de fichier plus complexe. Par exemple:

# 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() 

Si vous voulez être en mesure de décompresser les morceaux sans sauter (soit pour la décompression dans un accès parallèle ou aléatoire) vous devez placer les longueurs des morceaux comprimés au début, avant le premier morceau. Faites-les précéder du nombre de morceaux.Le dernier morceau peut être plus court que 64k, et il peut être incompressible mais nous allons toujours stocker le formulaire compressé, même s'il est plus long que la forme non compressée, car seuls les blocs complets de 64k sont stockés tels quels. Si le fichier entier est plus court que 64k, il va augmenter.

1

Je pense que vous ouvrez le mauvais fichier dans int compressFileWithLzo1x:

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

il devrait être

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