DragonNest/Common/ZipArchive/DeflateCompressor.cpp

237 lines
5.9 KiB
C++
Raw Normal View History

2024-12-19 09:48:26 +08:00
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyrighted 2000 - 2012 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)
{
UpdateFileCrc(pBuffer, uSize);
if (m_pFile->m_uMethod == methodDeflate)
{
m_stream.next_in = (zarch_Bytef*)pBuffer;
m_stream.avail_in = 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;
}
ZIP_ZLIB_TYPE uTotal = m_stream.total_out;
CheckForError(zarch_deflate(&m_stream, Z_NO_FLUSH));
m_uComprLeft += m_stream.total_out - uTotal;
}
}
else if (uSize > 0)
{
if (m_pCryptograph)
{
if (m_pBuffer.GetSize() < uSize)
{
m_pBuffer.Allocate(uSize);
}
memcpy(m_pBuffer, pBuffer, uSize);
WriteBuffer(m_pBuffer, uSize);
}
else
m_pStorage->Write(pBuffer, uSize, false);
m_stream.total_in += uSize;
m_stream.total_out += uSize;
}
}
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();
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;
DWORD uRead = 0;
if (m_pFile->m_uMethod == methodDeflate)
{
m_stream.next_out = (zarch_Bytef*)pBuffer;
m_stream.avail_out = uSize > m_uUncomprLeft ? (DWORD)m_uUncomprLeft : uSize;
// 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 = FillBuffer();
m_stream.next_in = (zarch_Bytef*)(char*)m_pBuffer;
m_stream.avail_in = uToRead;
}
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)
{
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);
}
}
else
{
if (m_uComprLeft < uSize)
uRead = (DWORD)m_uComprLeft;
else
uRead = uSize;
if (uRead > 0)
{
m_pStorage->Read(pBuffer, uRead, false);
if (m_pCryptograph)
m_pCryptograph->Decode((char*)pBuffer, uRead);
UpdateCrc(pBuffer, uRead);
m_uComprLeft -= uRead;
m_uUncomprLeft -= uRead;
m_stream.total_out += uRead;
}
}
return uRead;
}
void CDeflateCompressor::FinishDecompression(bool bAfterException)
{
if (!bAfterException && m_pFile->m_uMethod == methodDeflate)
zarch_inflateEnd(&m_stream);
EmptyPtrList();
ReleaseBuffer();
}
} // namespace