From 16f738ecee689c6feb2acb7e4ef4d9bb4144ae7d Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sun, 8 Jun 2008 11:04:43 +0200 Subject: Initial commit --- zip/ZipArchive/DeflateCompressor.cpp | 251 +++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 zip/ZipArchive/DeflateCompressor.cpp (limited to 'zip/ZipArchive/DeflateCompressor.cpp') diff --git a/zip/ZipArchive/DeflateCompressor.cpp b/zip/ZipArchive/DeflateCompressor.cpp new file mode 100644 index 0000000..edaadf4 --- /dev/null +++ b/zip/ZipArchive/DeflateCompressor.cpp @@ -0,0 +1,251 @@ +//////////////////////////////////////////////////////////////////////////////// +// This source file is part of the ZipArchive library source distribution and +// is Copyrighted 2000 - 2007 by Artpol Software - Tadeusz Dracz +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// For the licensing details refer to the License.txt file. +// +// Web Site: http://www.artpol-software.com +//////////////////////////////////////////////////////////////////////////////// + +#include "stdafx.h" +#include "DeflateCompressor.h" +#include "zlib/deflate.h" + +namespace ZipArchiveLib +{ + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif + + +CDeflateCompressor::CDeflateCompressor(CZipStorage* pStorage) + :CBaseLibCompressor(pStorage) +{ + m_stream.zalloc = (zarch_alloc_func)_zipalloc; + m_stream.zfree = (zarch_free_func)_zipfree; +} + + +void CDeflateCompressor::InitCompression(int iLevel, CZipFileHeader* pFile, CZipCryptograph* pCryptograph) +{ + CZipCompressor::InitCompression(iLevel, pFile, pCryptograph); + + m_stream.avail_in = (zarch_uInt)0; + m_stream.avail_out = (zarch_uInt)m_pBuffer.GetSize(); + m_stream.next_out = (zarch_Bytef*)(char*)m_pBuffer; + m_stream.total_in = 0; + m_stream.total_out = 0; + + if (pFile->m_uMethod == methodDeflate) + { + SetOpaque(&m_stream.opaque, &m_options); + + int err = zarch_deflateInit2_(&m_stream, iLevel, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(zarch_z_stream)); + + CheckForError(err); + } +} + +void CDeflateCompressor::Compress(const void *pBuffer, DWORD uSize) +{ + m_stream.next_in = (zarch_Bytef*)pBuffer; + m_stream.avail_in = uSize; + UpdateFileCrc(pBuffer, uSize); + + + while (m_stream.avail_in > 0) + { + if (m_stream.avail_out == 0) + { + FlushWriteBuffer(); + m_stream.avail_out = m_pBuffer.GetSize(); + m_stream.next_out = (zarch_Bytef*)(char*)m_pBuffer; + } + + if (m_pFile->m_uMethod == methodDeflate) + { + ZIP_ZLIB_TYPE uTotal = m_stream.total_out; + CheckForError(zarch_deflate(&m_stream, Z_NO_FLUSH)); + m_uComprLeft += m_stream.total_out - uTotal; + } + else + { + DWORD uToCopy = (m_stream.avail_in < m_stream.avail_out) + ? m_stream.avail_in : m_stream.avail_out; + + memcpy(m_stream.next_out, m_stream.next_in, uToCopy); + + m_stream.avail_in -= uToCopy; + m_stream.avail_out -= uToCopy; + m_stream.next_in += uToCopy; + m_stream.next_out += uToCopy; + m_stream.total_in += uToCopy; + m_stream.total_out += uToCopy; + m_uComprLeft += uToCopy; + } + } +} + +void CDeflateCompressor::FinishCompression(bool bAfterException) +{ + m_stream.avail_in = 0; + if (!bAfterException) + { + if (m_pFile->m_uMethod == methodDeflate) + { + int err; + do + { + if (m_stream.avail_out == 0) + { + FlushWriteBuffer(); + m_stream.avail_out = m_pBuffer.GetSize(); + m_stream.next_out = (zarch_Bytef*)(char*)m_pBuffer; + } + ZIP_SIZE_TYPE uTotal = m_stream.total_out; + err = zarch_deflate(&m_stream, Z_FINISH); + m_uComprLeft += m_stream.total_out - uTotal; + } + while (err == Z_OK); + + if (err == Z_STREAM_END) + err = Z_OK; + CheckForError(err); + } + + if (m_uComprLeft > 0) + FlushWriteBuffer(); + + if (m_pFile->m_uMethod == methodDeflate) + CheckForError(zarch_deflateEnd(&m_stream)); + + + // it may be increased by the encrypted header size in CZipFileHeader::PrepareData + m_pFile->m_uComprSize += m_stream.total_out; + m_pFile->m_uUncomprSize = m_stream.total_in; + } + EmptyPtrList(); + ReleaseBuffer(); +} + +void CDeflateCompressor::InitDecompression(CZipFileHeader* pFile, CZipCryptograph* pCryptograph) +{ + CBaseLibCompressor::InitDecompression(pFile, pCryptograph); + if (m_pFile->m_uMethod == methodDeflate) + { + SetOpaque(&m_stream.opaque, &m_options); + CheckForError(zarch_inflateInit2_(&m_stream, -MAX_WBITS, ZLIB_VERSION, sizeof(zarch_z_stream))); + } + m_stream.total_out = 0; + m_stream.avail_in = 0; +} + +DWORD CDeflateCompressor::Decompress(void *pBuffer, DWORD uSize) +{ + if (m_bDecompressionDone) + return 0; + + m_stream.next_out = (zarch_Bytef*)pBuffer; + m_stream.avail_out = uSize > m_uUncomprLeft + ? (DWORD)m_uUncomprLeft : uSize; + + DWORD uRead = 0; + + // may happen when the file is 0 sized + bool bForce = m_stream.avail_out == 0 && m_uComprLeft > 0; + while (m_stream.avail_out > 0 || (bForce && m_uComprLeft > 0)) + { + if ((m_stream.avail_in == 0) && + (m_uComprLeft >= 0)) // Also when there are zero bytes left + { + DWORD uToRead = m_pBuffer.GetSize(); + if (m_uComprLeft < uToRead) + uToRead = (DWORD)m_uComprLeft; + + if (uToRead == 0) + uToRead = 1; // Add dummy byte at end of compressed data. + else + { + m_pStorage->Read(m_pBuffer, uToRead, false); + if (m_pCryptograph) + m_pCryptograph->Decode(m_pBuffer, uToRead); + } + + m_uComprLeft -= uToRead; + + m_stream.next_in = (zarch_Bytef*)(char*)m_pBuffer; + m_stream.avail_in = uToRead; + } + + if (m_pFile->m_uMethod == methodStore) + { + DWORD uToCopy = m_stream.avail_out < m_stream.avail_in + ? m_stream.avail_out : m_stream.avail_in; + + memcpy(m_stream.next_out, m_stream.next_in, uToCopy); + + UpdateCrc(m_stream.next_out, uToCopy); + + m_uUncomprLeft -= uToCopy; + m_stream.avail_in -= uToCopy; + m_stream.avail_out -= uToCopy; + m_stream.next_out += uToCopy; + m_stream.next_in += uToCopy; + m_stream.total_out += uToCopy; + uRead += uToCopy; + } + else + { + ZIP_SIZE_TYPE uTotal = m_stream.total_out; + zarch_Bytef* pOldBuf = m_stream.next_out; + int ret = zarch_inflate(&m_stream, Z_SYNC_FLUSH); + // will not exceed DWORD + DWORD uToCopy = (DWORD)(m_stream.total_out - uTotal); + + UpdateCrc(pOldBuf, uToCopy); + + m_uUncomprLeft -= uToCopy; + uRead += uToCopy; + + if (ret == Z_STREAM_END) + { + m_bDecompressionDone = true; + return uRead; + } + else + CheckForError(ret); + } + } + + if (!uRead && m_options.m_bCheckLastBlock && uSize != 0 && m_pFile->m_uMethod == methodDeflate) + { + if (zarch_inflate(&m_stream, Z_SYNC_FLUSH) != Z_STREAM_END) + // there were no more bytes to read and there was no ending block, + // otherwise the method would return earlier + ThrowError(CZipException::badZipFile); + } + + return uRead; +} + +void CDeflateCompressor::FinishDecompression(bool bAfterException) +{ + if (!bAfterException && m_pFile->m_uMethod == methodDeflate) + zarch_inflateEnd(&m_stream); + EmptyPtrList(); + ReleaseBuffer(); +} + + +} // namespace -- cgit v1.2.3