2016-11-10 4 views
0

ZLIBを使用して.FLAファイルを膨張(圧縮解除)して、その内容をすべて抽出しようとしています。 FLAファイルはZIP形式を使用しているので、ローカルファイルヘッダ(https://en.wikipedia.org/wiki/Zip_(file_format))を読み込み、その内部の情報を使用してファイルを解凍することができます。ZLIBライブラリを使用したPNGファイルの膨張(C)

普通のテキストベースのファイルではうまくいくようですが、バイナリ(PNGとDATファイルを試しただけです)では、圧縮解除に失敗して "Z_DATA_ERROR"を返します。

FLAファイル内のセントラルディレクトリファイルのヘッダーが通常のzipファイルとわずかに異なるため、ZLIB内でミニライブラリライブラリを使用することができません。私は、単一のPNGファイルをビュンして、それを試してみましたextracing

void DecompressBuffer(char* compressedBuffer, unsigned int compressedSize, std::string& out_decompressedBuffer) 
{ 
    // init the decompression stream 
    z_stream stream; 

    stream.zalloc = Z_NULL; 
    stream.zfree = Z_NULL; 
    stream.opaque = Z_NULL; 
    stream.avail_in = 0; 
    stream.next_in = Z_NULL; 
    if (int err = inflateInit2(&stream, -MAX_WBITS) != Z_OK) 
    { 
     printf("Error: inflateInit %d\n", err); 
     return; 
    } 

    // Set the starting point and total data size to be read 
    stream.avail_in = compressedSize; 
    stream.next_in = (Bytef*)&compressedBuffer[0]; 

    std::stringstream strStream; 

    // Start decompressing 
    while (stream.avail_in != 0) 
    { 
     unsigned char* readBuffer = (unsigned char*)malloc(MAX_READ_BUFFER_SIZE + 1); 
     readBuffer[MAX_READ_BUFFER_SIZE] = '\0'; 
     stream.next_out = readBuffer; 
     stream.avail_out = MAX_READ_BUFFER_SIZE; 

     int ret = inflate(&stream, Z_NO_FLUSH); 

     if (ret == Z_STREAM_END) 
     { 
      // only store the data we have left in the stream 
      size_t length = MAX_READ_BUFFER_SIZE - stream.avail_out; 
      std::string str((char*)readBuffer); 
      str = str.substr(0, length); 
      strStream << str; 
      break; 
     } 
     else 
     {  
      if (ret != Z_OK) 
      { 
       printf("Error: inflate %d\n", ret); // This is what it reaches when trying to inflate a PNG or DAT file 
       break; 
      } 

      // store the readbuffer in the stream 
      strStream << readBuffer; 
     } 

     free(readBuffer); 
    } 

    out_decompressedBuffer = strStream.str(); 

    inflateEnd(&stream); 
} 

は、ここで私は、データのチャンクを解凍するために使用するコードです。これは、Inflate()からのエラーは返しませんが、PNGも正しく膨張させることはなく、対応する唯一の値が最初の数に見えます。

元のファイル(左)と(右)コードファイルを経由して圧縮されていない:

Hex editor versions of both PNGs

答えて

1

あなたはデータがテキストと文字列ではなく、バイナリデータであることに依存していることを行います。 readBufferの内容は生のバイナリデータである場合、例えば

std::string str((char*)readBuffer); 

それはそれの中央における1つ以上のゼロバイトを含むかもしれません。 Cスタイルの文字列として使用すると、最初のゼロは文字列ターミネータ文字として機能します。

これを一般化し、文字列の依存関係を削除することをお勧めします。代わりに、 std::vector<int8_t>

一方、より一般化された方法への移行中は、たとえば次のようなことができます。

std::string str(readBuffer, length); 

これは指定した長さの文字列を作成し、内容はターミネータをチェックされることはありません。

+0

私はそれが理にかなっています。代わりにベクトルを使用するように変更し、PNGファイルを解凍できるようになりました。私はそれが.DATでも機能するかどうかをテストするとすぐにあなたの答えを受け入れます。 –

関連する問題