📄 ziparchive.cpp
字号:
///////////////////////////////////////////////////////////////////////////////
// $Workfile: ZipArchive.cpp $
// $Archive: /ZipArchive/ZipArchive.cpp $
// $Date: 03-01-09 10:30 $ $Author: Tadeusz Dracz $
////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyright 2000-2003 by Tadeusz Dracz (http://www.artpol-software.com/)
//
// 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 see the file License.txt
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ZipArchive.h"
// #include "ZipPathComponent.h"
#include "ZipPlatform.h"
#include "ZipCompatibility.h"
#include <time.h>
#ifndef DEF_MEM_LEVEL
#if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
#else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
#endif
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define ZIP_COMPR_REPL_MASK 0xffffff00
#define ZIP_COMPR_REPL_SIGN 0x0100 // first 8 bits should be 00 (reserved for compression level), next 8 should be different from ff (to distinguish from -1)
const TCHAR CZipArchive::m_gszCopyright[] = {_T("ZipArchive library Copyright 2000 - 2002 Tadeusz Dracz")};
void CZipAddNewFileInfo::Defaults()
{
m_iSmartLevel = CZipArchive::zipsmSafeSmart;
m_iReplaceIndex = -1;
m_nBufSize = 65536;
m_iComprLevel = -1; // default
}
CZipArchive::CZipArchive()
{
m_bRemoveDriveLetter = m_bDetectZlibMemoryLeaks = true;
m_bIgnoreCRC = m_bAutoFlush = false;
m_centralDir.m_pStorage= &m_storage;
m_info.m_stream.zalloc = (alloc_func)_zliballoc;
m_info.m_stream.zfree = (free_func)_zlibfree;
m_iFileOpened = nothing;
SetCaseSensitivity(ZipPlatform::GetSystemCaseSensitivity());
}
CZipArchive::~CZipArchive()
{
// Close(); // cannot be here: if an exception is thrown strange things can happen
EmptyPtrList();
}
void CZipArchive::Open(LPCTSTR szPathName, int iMode, int iVolumeSize)
{
if (!IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive already opened.\n"),__FILE__,__LINE__);
return;
}
m_storage.Open(szPathName, iMode, iVolumeSize);
OpenInternal(iMode);
}
void CZipArchive::Open(CZipMemFile& mf,int iMode)
{
if (!IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive already opened.\n"),__FILE__,__LINE__);
return;
}
if (iMode != zipOpen && iMode != zipOpenReadOnly && iMode != zipCreate)
{
TRACE(_T("%s(%i) : Mode not supported.\n"),__FILE__,__LINE__);
return;
}
m_storage.Open(mf, iMode);
OpenInternal(iMode);
}
void CZipArchive::OpenInternal(int iMode)
{
m_pszPassword.Release();
m_iFileOpened = nothing;
m_centralDir.Init();
m_iArchiveSystCompatib = ZipPlatform::GetSystemID();
m_szRootPath.Empty();
if ((iMode == zipOpen) ||(iMode == zipOpenReadOnly))
{
m_centralDir.Read();
// if there is at least one file, get system comp. from the first one
if (m_centralDir.IsValidIndex(0))
{
int iSystemComp = m_centralDir[0]->GetSystemCompatibility();
if (ZipCompatibility::IsPlatformSupported(iSystemComp))
m_iArchiveSystCompatib = iSystemComp;
}
}
}
bool CZipArchive::IsClosed(bool bArchive) const
{
return bArchive ?(m_storage.GetCurrentDisk() == -1):(!m_storage.m_pFile || m_storage.m_pFile->IsClosed());
}
void CZipArchive::ThrowError(int err, bool bZlib)
{
if (bZlib)
err = CZipException::ZlibErrToZip(err);
CZipException::Throw(err, IsClosed() ? _T("") : (LPCTSTR)m_storage.m_pFile->GetFilePath());
}
bool CZipArchive::GetFileInfo(CZipFileHeader & fhInfo, WORD uIndex) const
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return false;
}
if (!m_centralDir.IsValidIndex(uIndex))
return false;
fhInfo = *(m_centralDir[uIndex]);
m_centralDir.ConvertFileName(true, false, &fhInfo);
return true;
}
int CZipArchive::FindFile(LPCTSTR lpszFileName, int iCaseSensitive, bool bFileNameOnly)
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return (int)-1;
}
bool bCS;
bool bSporadically;
switch (iCaseSensitive)
{
case ffCaseSens:
bCS = true;
bSporadically = true;
break;
case ffNoCaseSens:
bCS = false;
bSporadically = true;
break;
default:
bCS = m_bCaseSensitive;
bSporadically = false;
}
return m_centralDir.FindFile(lpszFileName, bCS, bSporadically, bFileNameOnly);
}
bool CZipArchive::OpenFile(WORD uIndex)
{
if (!m_centralDir.IsValidIndex(uIndex))
{
ASSERT(FALSE);
return false;
}
if (m_storage.IsSpanMode() == 1)
{
TRACE(_T("%s(%i) : You cannot extract from the span in creation.\n"),__FILE__,__LINE__);
return false;
}
if (m_iFileOpened)
{
TRACE(_T("%s(%i) : A file already opened.\n"),__FILE__,__LINE__);
return false;
}
m_info.Init();
m_centralDir.OpenFile(uIndex);
if (CurrentFile()->IsEncrypted())
{
if (m_pszPassword.GetSize() == 0)
{
TRACE(_T("%s(%i) : Password not set for the encrypted file.\n"),__FILE__,__LINE__);
ThrowError(CZipException::badPassword);
}
CryptInitKeys();
if (!CryptCheck())
ThrowError(CZipException::badPassword);
}
else if (m_pszPassword.GetSize() != 0)
{
TRACE(_T("%s(%i) : Password set for a not encrypted file. Ignoring password.\n"),__FILE__,__LINE__);
}
WORD uMethod = CurrentFile()->m_uMethod;
if ((uMethod != 0) &&(uMethod != Z_DEFLATED))
ThrowError(CZipException::badZipFile);
if (uMethod == Z_DEFLATED)
{
m_info.m_stream.opaque = m_bDetectZlibMemoryLeaks ? &m_list : 0;
int err = inflateInit2(&m_info.m_stream, -MAX_WBITS);
// * windowBits is passed < 0 to tell that there is no zlib header.
// * Note that in this case inflate *requires* an extra "dummy" byte
// * after the compressed stream in order to complete decompression and
// * return Z_STREAM_END.
CheckForError(err);
}
m_info.m_uComprLeft = CurrentFile()->m_uComprSize;
if (CurrentFile()->IsEncrypted())
m_info.m_uComprLeft -= ZIPARCHIVE_ENCR_HEADER_LEN;
m_info.m_uUncomprLeft = CurrentFile()->m_uUncomprSize;
m_info.m_uCrc32 = 0;
m_info.m_stream.total_out = 0;
m_info.m_stream.avail_in = 0;
m_iFileOpened = extract;
return true;
}
int CZipArchive::GetLocalExtraField(char *pBuf, int iSize)const
{
if (IsClosed())
{
TRACE(_T("%s(%i) : ZipArchive is closed.\n"),__FILE__,__LINE__);
return -1;
}
if (m_iFileOpened != extract)
{
TRACE(_T("%s(%i) : A file must be opened to get the local extra field.\n"),__FILE__,__LINE__);
return -1;
}
int size = m_centralDir.m_pLocalExtraField.GetSize();
if (!pBuf|| !size)
return size;
if (iSize < size)
size = iSize;
memcpy(pBuf, m_centralDir.m_pLocalExtraField, size);
return size;
}
void* CZipArchive::_zliballoc(void* opaque, UINT items, UINT size)
{
void* p = new char[size * items];
if (opaque)
{
CZipPtrList<void*>* list = (CZipPtrList<void*>*) opaque;
list->AddTail(p);
}
return p;
}
void CZipArchive::_zlibfree(void* opaque, void* address)
{
if (opaque)
{
CZipPtrList<void*>* list = (CZipPtrList<void*>*) opaque;
CZipPtrListIter iter = list->Find(address);
if (list->IteratorValid(iter))
list->RemoveAt(iter);
}
delete[] (char*) address;
}
void CZipArchive::CheckForError(int iErr)
{
if ((iErr == Z_OK) ||(iErr == Z_NEED_DICT))
return;
ThrowError(iErr, true);
}
CZipFileHeader* CZipArchive::CurrentFile()
{
ASSERT(m_centralDir.m_pOpenedFile);
return m_centralDir.m_pOpenedFile;
}
DWORD CZipArchive::ReadFile(void *pBuf,
DWORD iSize)
{
if (m_iFileOpened != extract)
{
TRACE(_T("%s(%i) : Current file must be opened.\n"),__FILE__,__LINE__);
return 0;
}
if (!pBuf || !iSize)
return 0;
m_info.m_stream.next_out = (Bytef*)pBuf;
m_info.m_stream.avail_out = iSize > m_info.m_uUncomprLeft
? m_info.m_uUncomprLeft : iSize;
DWORD iRead = 0;
// may happen when the file is 0 sized
bool bForce = m_info.m_stream.avail_out == 0 && m_info.m_uComprLeft > 0;
while (m_info.m_stream.avail_out > 0 || (bForce && m_info.m_uComprLeft > 0))
{
if ((m_info.m_stream.avail_in == 0) &&
(m_info.m_uComprLeft > 0))
{
DWORD uToRead = m_info.m_pBuffer.GetSize();
if (m_info.m_uComprLeft < uToRead)
uToRead = m_info.m_uComprLeft;
if (uToRead == 0)
return 0;
m_storage.Read(m_info.m_pBuffer, uToRead, false);
CryptDecodeBuffer(uToRead);
m_info.m_uComprLeft -= uToRead;
m_info.m_stream.next_in = (Bytef*)(char*)m_info.m_pBuffer;
m_info.m_stream.avail_in = uToRead;
}
if (CurrentFile()->m_uMethod == 0)
{
DWORD uToCopy = m_info.m_stream.avail_out < m_info.m_stream.avail_in
? m_info.m_stream.avail_out : m_info.m_stream.avail_in;
memcpy(m_info.m_stream.next_out, m_info.m_stream.next_in, uToCopy);
m_info.m_uCrc32 = crc32(m_info.m_uCrc32, m_info.m_stream.next_out, uToCopy);
m_info.m_uUncomprLeft -= uToCopy;
m_info.m_stream.avail_in -= uToCopy;
m_info.m_stream.avail_out -= uToCopy;
m_info.m_stream.next_out += uToCopy;
m_info.m_stream.next_in += uToCopy;
m_info.m_stream.total_out += uToCopy;
iRead += uToCopy;
}
else
{
DWORD uTotal = m_info.m_stream.total_out;
Bytef* pOldBuf = m_info.m_stream.next_out;
int err = inflate(&m_info.m_stream, Z_SYNC_FLUSH);
DWORD uToCopy = m_info.m_stream.total_out - uTotal;
m_info.m_uCrc32 = crc32(m_info.m_uCrc32, pOldBuf, uToCopy);
m_info.m_uUncomprLeft -= uToCopy;
iRead += uToCopy;
if (err == Z_STREAM_END)
return iRead;
CheckForError(err);
}
}
return iRead;
}
void CZipArchive::Close(int iAfterException, bool bUpdateTimeStamp)
{
// if after an exception - the archive may be closed, but the file may be opened
if (IsClosed() && (!iAfterException || IsClosed(false)))
{
TRACE(_T("%s(%i) : ZipArchive is already closed.\n"),__FILE__,__LINE__);
return;
}
if (m_iFileOpened == extract)
CloseFile(NULL, iAfterException != afNoException);
if (m_iFileOpened == compress)
CloseNewFile(iAfterException != afNoException);
if (iAfterException != afAfterException && !IsClosed(false)) // in disk spanning when user aborts
WriteCentralDirectory(false); // we will flush in CZipStorage::Close
time_t tNewestTime = 0;
if (bUpdateTimeStamp)
{
int iSize = m_centralDir.m_headers.GetSize();
for (int i = 0; i< iSize; i++)
{
time_t tFileInZipTime = m_centralDir[i]->GetTime();
if (tFileInZipTime > tNewestTime)
tNewestTime = tFileInZipTime;
}
}
m_centralDir.Clear();
CZipString szFileName = m_storage.Close(iAfterException == afAfterException);
if (bUpdateTimeStamp && !szFileName.IsEmpty())
ZipPlatform::SetFileModTime(szFileName, tNewestTime);
}
void CZipArchive::WriteCentralDirectory(bool bFlush)
{
m_centralDir.Write(GetCallback(cbSave));
if (bFlush)
m_storage.Flush();
}
void CZipArchive::SetCallback(CZipActionCallback* pCallback, int iWhich)
{
CallbackType cbs[] = {cbAdd, cbAddTmp, cbAddStore,cbExtract,cbDeleteCnt,cbDelete,cbTest,cbSave, cbGetFromArchive, cbRename, cbReplace};
int iCount = sizeof(cbs)/sizeof(CallbackType);
for (int i = 0; i < iCount; i++)
{
CallbackType iCallback = cbs[i];
if (iWhich & iCallback)
m_callbacks.Set(pCallback, iCallback);
}
}
void CZipArchive::SetAdvanced(int iWriteBuffer, int iGeneralBuffer, int iSearchBuffer)
{
if (!IsClosed())
{
TRACE(_T("%s(%i) : Set this options before opening the archive.\n"),__FILE__,__LINE__);
return;
}
m_storage.m_iWriteBufferSize = iWriteBuffer < 1024 ? 1024 : iWriteBuffer;
m_info.m_iBufferSize = iGeneralBuffer < 1024 ? 1024 : iGeneralBuffer;
m_centralDir.m_iBufferSize = iSearchBuffer < 1024 ? 1024 : iSearchBuffer;
}
int CZipArchive::CloseFile(CZipFile &file)
{
CZipString temp = file.GetFilePath();
file.Close();
return CloseFile(temp);
}
int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException)
{
if (m_iFileOpened != extract)
{
TRACE(_T("%s(%i) : No opened file.\n"),__FILE__,__LINE__);
return false;
}
int iRet = 1;
if (!bAfterException)
{
if (m_info.m_uUncomprLeft == 0)
{
if (!m_bIgnoreCRC && m_info.m_uCrc32 != CurrentFile()->m_uCrc32)
ThrowError(CZipException::badCrc);
}
else
iRet = -1;
if (CurrentFile()->m_uMethod == Z_DEFLATED)
inflateEnd(&m_info.m_stream);
if (lpszFilePath)
{
if (!ZipPlatform::SetFileModTime(lpszFilePath, CurrentFile()->GetTime())
||!ZipPlatform::SetFileAttr(lpszFilePath, CurrentFile()->GetSystemAttr()))
iRet = -2;
}
}
m_centralDir.CloseFile(bAfterException);
m_iFileOpened = nothing;
m_info.ReleaseBuf();
EmptyPtrList();
return iRet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -