当前位置:网站首页>Zlib realizes streaming decompression

Zlib realizes streaming decompression

2022-04-23 18:52:00 Brick Porter

#define CHUNK_SIZE 4096
class CZipFileStream {

	// zlib Support .
	z_stream m_stream;
	int m_last_inflate_;
	//  Decompression buffer .
	char m_zlib_buffer[CHUNK_SIZE];
	//  Number of bytes entered .
	std::size_t m_zlib_buffer_size;
	std::ifstream& m_fs;
	bool m_auto_close_fs;
public:
	/// <summary>
	///  Construct a decompression class 
	/// </summary>
	/// <param name="fs"> Input file stream </param>
	/// <param name="autoClosefs"> Do you want to close the file automatically , It is not automatically closed by default </param>
	CZipFileStream(std::ifstream& fs,bool autoClosefs=false) :m_fs(fs), m_auto_close_fs(autoClosefs), m_last_inflate_(Z_OK)
	{
		memset(&m_stream, 0, sizeof(z_stream));
		//inflateInit(&m_stream);
	}
	~CZipFileStream()
	{
		if (m_stream.zalloc)
			inflateEnd(&m_stream);
		if (m_auto_close_fs && m_fs.is_open())
			m_fs.close();
	}

	int Read(BYTE* buf, std::size_t bufsize)
	{
		if (!m_fs.is_open())
		{
			m_last_inflate_ = Z_DATA_ERROR;
			return 0;
		}
		if (IsBadReadPtr(buf, bufsize) || buf == 0)
		{
			m_last_inflate_ = Z_BUF_ERROR;
			return 0;
		}
		if (!m_stream.zalloc)
		{
			m_last_inflate_ = inflateInit(&m_stream);
			if (m_last_inflate_ != Z_OK)
			{
				return m_last_inflate_;
			}
		}
		m_stream.next_out = (Bytef*)buf;
 		m_stream.avail_out = bufsize;
		while (!m_fs.eof()|| m_stream.avail_in)
		{
			if (m_stream.avail_in == 0)
			{
				m_fs.read(m_zlib_buffer, CHUNK_SIZE);
				m_zlib_buffer_size = m_fs.gcount();
				m_stream.avail_in = (uInt)m_zlib_buffer_size;
				m_stream.next_in = (z_const Bytef*) & m_zlib_buffer[0];
			}
			// No data to read .
			if (m_zlib_buffer_size == 0)
			{
				if (m_stream.zalloc)
				{
					inflateEnd(&m_stream); 
					m_last_inflate_ = Z_STREAM_END;
				}
				break;
			}
			m_last_inflate_ = inflate(&m_stream, Z_SYNC_FLUSH);
			// After decompression, whether the output is full or not 
			if (m_last_inflate_ == Z_STREAM_END)
			{
				if (m_auto_close_fs)
					m_fs.close();
				if (m_stream.zalloc)
					inflateEnd(&m_stream);
				return bufsize-m_stream.avail_out;
			}
			// If the decompression is successful and the output is not filled, continue to read the data 
			else if (m_last_inflate_ == Z_OK)
			{
				if (m_stream.avail_out)
					continue;
				else 
					return bufsize-m_stream.avail_out;
			}
			else
			{// That means something went wrong 
				if (m_stream.zalloc)
				{
					if (m_auto_close_fs)
						m_fs.close();
					inflateEnd(&m_stream);
				}
				break;
			}
		}
		return 0;
	}
    // Judge whether the file has been decompressed 
	bool Eof()
	{
		return (m_last_inflate_ == Z_STREAM_END || m_last_inflate_!=Z_OK);
	}
    // Normally, when the decompression is completed, it should be Z_STREAM_END , This function can judge whether the decompressed data is successful in the end 
	bool IsOk()
	{
		return (m_last_inflate_ == Z_STREAM_END );
	}
	// Directly decompress all the data , You need to know the buffer size in advance .
	static bool UnCompress(const BYTE* pcCompBuf, uLong ulCompLen, BYTE* pcUnCompBuf, uLong& uncomprLen)
	{
		if (pcCompBuf == NULL)
		{
			return false;
		}
		int err = uncompress(pcUnCompBuf, &uncomprLen, (const Bytef*)pcCompBuf, ulCompLen);
		if (err != Z_OK)
		{
			return false;
		}
		return true;
	}
};

The call is roughly as follows . The preliminary test of the code passed . Static functions UnCompress Is to decompress all the data at once . You can use it to verify the extracted data , But its buffer needs to be large enough .

std::ifstream infile(inputPath.c_str(), std::ios_base::binary | std::ios_base::in);

CZipFileStream zipstreame(infile,true);
		std::vector<BYTE> outbuf;

		while (!zipstreame.Eof())
		{
			BYTE buf[1024];
			int readcount = zipstreame.Read(buf, sizeof(buf));
			outbuf.insert(outbuf.end(), buf, buf + readcount);			
		}

版权声明
本文为[Brick Porter]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204210603257433.html