0
votes

The zlib uncompress() return -3 (z_data_error) when I decompress data. From doc: returns Z_DATA_ERROR if the input data was corrupted or incomplete,

uncompress((Bytef*)uncompressbuffer, &uncompressbuffersize, (const Bytef*)compressbuffer, &compressbuffersize)

In another application, where I use deflate/inflate I get the same error.

strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = inputLength;
strm.next_in = (unsigned char*) inputBuffer;

ret = inflateInit(&strm);
if (ret != Z_OK)
{
    delete[] uncompressedData;
    return ERROR;
}
/******************************************************/


strm.avail_out = unusedData; 
strm.next_out = (uncompressedData + MIN_CHUNK) - unusedData;

/* run inflate() on input until output buffer not full */
do {
    ret = inflate(&strm, Z_NO_FLUSH);
    assert(ret != Z_STREAM_ERROR);  /* state not clobbered */

    switch (ret)
    {
    case Z_NEED_DICT:
        ret = Z_DATA_ERROR;     /* and fall through */
    case Z_DATA_ERROR:
    case Z_MEM_ERROR:
        (void)inflateEnd(&strm);
        return ret;
    }

} while (strm.avail_out != 0 && ret == Z_OK);

but

this error happens only with x64 version of my software. A x86 working properly. The unzipped data is intact. The buffer size of compressed and uncompressed data are correct. Zlib is correctly compiled to x64. What else could be causing this problem? Any hint?

Sample code with "uncompress":

#include <iostream>
#include <fstream>
#include <cstdio>
#include <vector>
#include <zlib.h>
#include <assert.h>
#include <cstdlib>

#define CHUNK 16384

const int BUFFERSIZE = 4096;

using namespace std;

void compress(FILE* fin, FILE* fout) {

    char buffer[BUFFERSIZE];
    
    int byte_read = fread(buffer, sizeof(char), BUFFERSIZE, fin);

    
    z_stream strm;
    int ret;
    unsigned have;
    unsigned char* tmp = new unsigned char[CHUNK];

    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.next_in = (unsigned char*)buffer;
    strm.avail_in = byte_read;
    strm.next_out = tmp;
    strm.avail_out = CHUNK;

    ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);

    //first loop: compress input data stream and write on RTDB file
    do
    {

        ret = deflate(&strm, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);

        have = BUFFERSIZE - strm.avail_out;
        fwrite(tmp, sizeof(char), BUFFERSIZE, fout);

    } while (strm.avail_out == 0);
    //assert(strm.avail_in == 0);

    //second loop: all input data consumed. Flush everything...
    do
    {
        strm.next_out = tmp;
        strm.avail_out = BUFFERSIZE;

        ret = deflate(&strm, Z_FINISH);
        assert(ret != Z_STREAM_ERROR);

        have = BUFFERSIZE - strm.avail_out;
        fwrite(tmp, sizeof(char), BUFFERSIZE, fout);

    } while (ret != Z_STREAM_END);

    (void)deflateEnd(&strm);
    delete tmp;
}

void decompress(FILE* fin, FILE* fout) {

    int status;

    char buffer[BUFFERSIZE];

    int byte_read = fread(buffer, sizeof(char), BUFFERSIZE, fin);

    void* compressedBuffer;
    void* uncompressedBuffer;
    uLongf  compressedBufferSize = BUFFERSIZE;
    uLongf  uncompressedBufferSize = BUFFERSIZE;

    compressedBuffer = malloc(compressedBufferSize);
    uncompressedBuffer = malloc(uncompressedBufferSize);

    status = uncompress((Bytef*)uncompressedBuffer, &uncompressedBufferSize, (const Bytef*)buffer, compressedBufferSize);

    fwrite(uncompressedBuffer, sizeof(char), BUFFERSIZE, fout);

    cout << "Status " << status << endl;
}

int main(int argc, char *argv[]) {
    
    //if (argc == 2)
    //{
    //  if (strcmp(argv[1], "/?") == 0 || strcmp(argv[1], "--help") == 0)
    //  {
    //      cout << "Please give me 1 argument" << endl;
    //      //getchar();
    //      return -1;
    //  }
    //}
    //else
    //{
    //  cout << "Please give me 1 argument" << endl;
    //  //getchar();
    //  return -1;
    //}
    //char *inputdata = argv[1];
    
    //const char *inputdata = "C:\\Users\\Francesco\\source\\repos\\zlibtest\\P0000P0000_no_com-alt.rtdb";
    const char *inputdata = "C:\\Users\\Francesco\\source\\repos\\zlibtest\\AAA.txt";
    //const char *inputdata = "C:\\Users\\Francesco\\source\\repos\\zlibtest\\P0000P0000_no_com-alt.rtdb";
    
    cout << inputdata << endl;
    FILE *fin, *fout, *fdec;
    fopen_s(&fin, inputdata, "r+");

    fopen_s(&fout, "output.txt", "w+");

    compress(fin, fout);

    fclose(fin);
    fclose(fout);

    fopen_s(&fout, "output.txt", "r");

    fopen_s(&fdec, "dec.txt", "w");

    decompress(fout, fdec);
    
    fclose(fout);
    fclose(fdec);
}
1
I cannot provide the complete code for business reasons (input data are in "internal" format). For compression/decompression I use the code provided by zlib documentation (zlib.net/zlib_how.html)valeriot90
if you want us to debug your code for you, you need to show us the code (not all your code just a minimal reproducible example)Alan Birtles
I've added the example. The input data is a .txt with some chars.valeriot90

1 Answers

2
votes

Your first problem is that as you are using windows you must open the compressed file in binary mode otherwise it will be corrupted:

fopen_s(&fout, "output.txt", "w+b");
fopen_s(&fout, "output.txt", "rb");

if the file you are compressing isn't text or if it is text and you want to perfectly preserve it you should also open the input and dec files in binary mode.

Next in compress you confuse BUFFERSIZE and CHUNK, have = BUFFERSIZE - strm.avail_out; should be have = CHUNK - strm.avail_out;, you then need to pass have to fwrite: fwrite(tmp, sizeof(char), have, fout);.

In decompress you need to pass uncompressedBufferSize to fwrite instead of BUFFERSIZE.

Fully working code (with some additional changes to fix memory leaks):

#include <iostream>
#include <fstream>
#include <cstdio>
#include <vector>
#include <zlib.h>
#include <assert.h>
#include <cstdlib>
#include <array>

const size_t CHUNK_SIZE = 16384;

const size_t BUFFER_SIZE = 4096;

void compress(FILE* fin, FILE* fout) {

    std::array<Bytef, BUFFER_SIZE> buffer;

    int byte_read = fread(buffer.data(), sizeof(char), buffer.size(), fin);


    z_stream strm;
    int ret;
    unsigned have;
    std::vector<Bytef> tmp(CHUNK_SIZE);

    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.next_in = buffer.data();
    strm.avail_in = byte_read;
    strm.next_out = tmp.data();
    strm.avail_out = tmp.size();

    ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);

    //first loop: compress input data stream and write on RTDB file
    do
    {

        ret = deflate(&strm, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);

        have = tmp.size() - strm.avail_out;
        fwrite(tmp.data(), sizeof(char), have, fout);

    } while (strm.avail_out == 0);
    //assert(strm.avail_in == 0);

    //second loop: all input data consumed. Flush everything...
    do
    {
        strm.next_out = tmp.data();
        strm.avail_out = tmp.size();

        ret = deflate(&strm, Z_FINISH);
        assert(ret != Z_STREAM_ERROR);

        have = tmp.size() - strm.avail_out;
        fwrite(tmp.data(), sizeof(char), have, fout);

    } while (ret != Z_STREAM_END);

    (void)deflateEnd(&strm);
}

void decompress(FILE* fin, FILE* fout) {

    int status;

    std::array<Bytef, BUFFER_SIZE> compressedBuffer;
    std::array<Bytef, BUFFER_SIZE> uncompressedBuffer;

    int byte_read = fread(compressedBuffer.data(), sizeof(char), compressedBuffer.size(), fin);

    uLongf  compressedBufferSize = compressedBuffer.size();
    uLongf  uncompressedBufferSize = uncompressedBuffer.size();

    status = uncompress(uncompressedBuffer.data(), &uncompressedBufferSize, compressedBuffer.data(), compressedBufferSize);

    fwrite(uncompressedBuffer.data(), sizeof(char), uncompressedBufferSize, fout);

    std::cout << "Status " << status << "\n";
}

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

    const char* inputdata = "C:\\Users\\alan\\source\\repos\\ConanScratch\\main.cpp";

    std::cout << inputdata << "\n";
    FILE* fin, * fout, * fdec;
    fopen_s(&fin, inputdata, "r+b");
    if (!fin)
    {
        std::cout << "unable to open input\n";
        return -1;
    }

    fopen_s(&fout, "output.txt", "w+b");
    if (!fout)
    {
        std::cout << "unable to open output\n";
        return -1;
    }

    compress(fin, fout);

    fclose(fin);
    fclose(fout);

    fopen_s(&fout, "output.txt", "r+b");
    if (!fout)
    {
        std::cout << "unable to open output\n";
        return -1;
    }

    fopen_s(&fdec, "dec.txt", "wb");
    if (!fdec)
    {
        std::cout << "unable to open dec\n";
        return -1;
    }

    decompress(fout, fdec);

    fclose(fout);
    fclose(fdec);
}

Your code can be greatly simplified with boost::iostreams:

#include <iostream>
#include <fstream>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filter/zlib.hpp>

int main(int argc, char* argv[])
{
    {
        std::ifstream input("C:\\Users\\alan\\source\\repos\\ConanScratch\\main.cpp", std::ios_base::binary);
        boost::iostreams::filtering_ostream output;
        output.push(boost::iostreams::zlib_compressor{});
        output.push(boost::iostreams::file_sink("output.txt", std::ios_base::out | std::ios_base::binary));
        output << input.rdbuf();
    }
    {
        boost::iostreams::filtering_istream input;
        input.push(boost::iostreams::zlib_decompressor{});
        input.push(boost::iostreams::file_source("output.txt", std::ios_base::in | std::ios_base::binary));
        std::ofstream output("dec.txt", std::ios_base::binary);
        output << input.rdbuf();
    }
}