繁体   English   中英

使用ZLIB库C ++膨胀(解压缩)PNG文件

[英]Inflate (decompress) PNG file using ZLIB library C++

我正在尝试使用ZLIB来膨胀(解压缩).FLA文件,从而提取其所有内容。 由于FLA文件使用ZIP格式,因此我可以从中读取本地文件头( https://en.wikipedia.org/wiki/Zip_(file_format) ),并使用内部信息解压缩文件。

对于常规的基于文本的文件,它似乎工作正常,但是当涉及二进制文件时(我仅尝试过PNG和DAT文件),它无法解压缩它们,返回“ Z_DATA_ERROR”。

我无法使用ZLIB中的minilib库,因为FLA文件中的中央目录文件头与普通zip文件略有不同(这就是为什么我手动读取本地文件头的原因)。

这是我用来解压缩数据块的代码:

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

我尝试过压缩单个PNG文件并将其扩展。 这不会从Inflate()返回任何错误,但也不会正确地将PNG膨胀,并且唯一对应的值似乎是前几个。

原始文件(左)和未压缩的通过代码文件(右):

两个PNG的十六进制编辑器版本

您所做的事情依赖于数据是文本和字符串,而不是二进制数据。

例如

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

如果readBuffer的内容是原始二进制数据,则其中间可能包含一个或多个零字节。 当您将其用作C风格的字符串时,第一个零将充当字符串终止符。

我建议您尝试将其概括化,并删除字符串的依赖性。 相反,我建议您使用例如std::vector<int8_t>

同时,在过渡到更通用的方式期间,您可以执行例如

std::string str(readBuffer, length);

这将创建一个指定长度的字符串,并且不会检查内容的终止符。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM