diff options
Diffstat (limited to 'zip/ZipArchive/ZipArchive.cpp')
| -rw-r--r-- | zip/ZipArchive/ZipArchive.cpp | 1454 |
1 files changed, 909 insertions, 545 deletions
diff --git a/zip/ZipArchive/ZipArchive.cpp b/zip/ZipArchive/ZipArchive.cpp index 8e29c3a..d2fe23e 100644 --- a/zip/ZipArchive/ZipArchive.cpp +++ b/zip/ZipArchive/ZipArchive.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////////
-// This source file is part of the ZipArchive library source distribution and
-// is Copyrighted 2000 - 2007 by Artpol Software - Tadeusz Dracz
+// This source file is part of the ZipArchive Library Open Source distribution
+// and is Copyrighted 2000 - 2022 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
@@ -9,9 +9,9 @@ //
// For the licensing details refer to the License.txt file.
//
-// Web Site: http://www.artpol-software.com
+// Web Site: https://www.artpol-software.com
////////////////////////////////////////////////////////////////////////////////
-
+// TODO: remove warnings with zlib compilation (exposed at least in VS 2005 Release compilation)
#include "stdafx.h"
#include "ZipArchive.h"
#include "ZipPlatform.h"
@@ -23,29 +23,82 @@ using namespace ZipArchiveLib;
-const char CZipArchive::m_gszCopyright[] = {"ZipArchive Library Copyright (C) 2000 - 2007 Artpol Software - Tadeusz Dracz"};
-const char CZipArchive::m_gszVersion[] = {"3.2.0"};
+const char CZipArchive::m_gszCopyright[] = {"The ZipArchive Library Copyright (c) 2000 - 2022 Artpol Software - Tadeusz Dracz"};
+const char CZipArchive::m_gszVersion[] = {"4.6.9"};
void CZipAddNewFileInfo::Defaults()
{
- m_iSmartLevel = CZipArchive::zipsmSafeSmart;
+ m_iSmartLevel = CZipArchive::zipsmSafeSmart;
m_uReplaceIndex = ZIP_FILE_INDEX_UNSPECIFIED;
m_nBufSize = 65536;
m_iComprLevel = -1; // default
+ m_szFileNameInZip = _T("");
+ m_szFilePath = _T("");
+ m_bFullPath = true;
+ m_pFile = NULL;
+}
+
+CZipAddFilesEnumerator::CZipAddFilesEnumerator(LPCTSTR lpszDirectory,
+ bool bRecursive,
+ int iComprLevel,
+ int iSmartLevel,
+ unsigned long nBufSize)
+ :ZipArchiveLib::CDirEnumerator(lpszDirectory, bRecursive)
+{
+ m_iComprLevel = iComprLevel;
+ m_nBufSize = nBufSize;
+ m_iSmartLevel = iSmartLevel;
+ m_pZip = NULL;
+ m_pMultiCallback = NULL;
}
+bool CZipAddFilesEnumerator::Process(LPCTSTR lpszPath, const ZipArchiveLib::CFileInfo& info)
+{
+ if (info.IsDirectory() && ((m_iSmartLevel & CZipArchive::zipsmIgnoreDirectories) != 0))
+ return true;
+#if defined _MSC_VER && _MSC_VER < 1300
+ CZipAddNewFileInfo zanfi(lpszPath, m_pZip->GetRootPath().IsEmpty() == TRUE);
+#else
+ CZipAddNewFileInfo zanfi(lpszPath, m_pZip->GetRootPath().IsEmpty());
+#endif
+
+ zanfi.m_iComprLevel = m_iComprLevel;
+ zanfi.m_iSmartLevel = m_iSmartLevel;
+ zanfi.m_nBufSize = m_nBufSize;
+ UpdateAddNewFileInfo(&zanfi);
+ bool ret = m_pZip->AddNewFile(zanfi);
+ if (ret && m_pMultiCallback)
+ {
+ if (!m_pMultiCallback->MultiActionsNext(zanfi.m_szFileNameInZip))
+ CZipException::Throw(CZipException::abortedSafely);
+ }
+ return ret;
+}
- CZipArchive:: CZipArchive()
+void CReplacingAddFilesEnumerator::UpdateAddNewFileInfo(CZipAddNewFileInfo* info)
{
+ CZipArchive* zip = GetZip();
+ CZipString fileName = zip->PredictFileNameInZip(info->m_szFilePath, info->m_bFullPath);
+ ZIP_INDEX_TYPE index = zip->FindFile(fileName);
+
+ if (index != ZIP_FILE_INDEX_NOT_FOUND)
+ info->m_uReplaceIndex = index;
+}
+
+
+#pragma warning(suppress: 26495)
+CZipArchive:: CZipArchive()
+{
Initialize();
}
-void CZipArchive::Initialize()
+void CZipArchive::Initialize()
{
- m_bRemoveDriveLetter = true;
- m_bExhaustiveRead = false;
- m_bAutoFlush = false;
+ m_bSafePaths = true;
+ m_bAutoFinalize = false;
+ // use the default
+ SetCommitMode();
m_iFileOpened = nothing;
SetCaseSensitivity(ZipPlatform::GetSystemCaseSensitivity());
m_uCompressionMethod = CZipCompressor::methodDeflate;
@@ -53,6 +106,9 @@ void CZipArchive::Initialize() m_pCryptograph = NULL;
m_pCompressor = NULL;
m_iBufferSize = 65536;
+ m_centralDir.InitOnCreate(this);
+ m_bStoreFullFileTimes = false;
+ m_bUseUtcFileTimes = true;
}
@@ -63,7 +119,7 @@ void CZipArchive::Initialize() ClearCryptograph();
}
-bool CZipArchive::Open(LPCTSTR szPathName, int iMode, ZIP_SIZE_TYPE uVolumeSize)
+bool CZipArchive::Open(LPCTSTR szPathName, int iMode, ZIP_SIZE_TYPE uVolumeSize)
{
if (!IsClosed())
{
@@ -75,62 +131,92 @@ bool CZipArchive::Open(LPCTSTR szPathName, int iMode, ZIP_SIZE_TYPE uVolumeSize return true;
}
-bool CZipArchive::Open(CZipAbstractFile& af, int iMode)
+bool CZipArchive::IsZipArchive(LPCTSTR lpszPathName)
+{
+ CZipArchive zip;
+ zip.m_storage.Open(lpszPathName, zipOpenReadOnly, 0);
+ return zip.m_centralDir.LocateSignature() != CZipStorage::SignatureNotFound;
+}
+
+
+bool CZipArchive::IsZipArchive(CZipAbstractFile& af, bool bAutoClose)
+{
+ CZipArchive zip;
+ zip.m_storage.Open(af, zipOpenReadOnly, bAutoClose);
+ return zip.m_centralDir.LocateSignature() != CZipStorage::SignatureNotFound;
+}
+
+bool CZipArchive::Open(CZipAbstractFile& af, int iMode, bool bAutoClose)
{
if (!IsClosed())
{
ZIPTRACE("%s(%i) : ZipArchive is already opened.\n");
return false;
}
+
if (iMode != zipOpen && iMode != zipOpenReadOnly && iMode != zipCreate && iMode != zipCreateAppend)
{
- ZIPTRACE("%s(%i) : Mode is not supported.\n");
+ ZIPTRACE("%s(%i) : The open mode is not supported.\n");
return false;
}
- m_storage.Open(af, iMode);
+ m_storage.Open(af, iMode, bAutoClose);
OpenInternal(iMode);
return true;
}
-bool CZipArchive::OpenFrom( CZipArchive& zip)
+bool CZipArchive::OpenFrom(CZipArchive& zip, CZipAbstractFile* pArchiveFile, bool bAllowNonReadOnly)
{
if (zip.IsClosed())
{
ZIPTRACE("%s(%i) : The source archive must be opened.\n");
return false;
}
- if (!zip.IsReadOnly())
+ if (!bAllowNonReadOnly && !zip.IsReadOnly())
{
ZIPTRACE("%s(%i) : The source archive must be opened in the read-only mode.\n");
return false;
}
- if (zip.m_storage.m_bInMemory)
+
+ if (pArchiveFile != NULL && zip.m_storage.IsSegmented())
{
- ZIPTRACE("%s(%i) : ZipArchive cannot share an archive in memory.\n");
+ ZIPTRACE("%s(%i) : ZipArchive cannot share a segmented archive using a file that is not on a disk.\n");
return false;
}
- m_storage.Open(zip.GetArchivePath(), CZipArchive::zipOpenReadOnly, zip.m_storage.IsSplit() ? 1 : 0);
+ int mode = CZipArchive::zipOpenReadOnly;
+ if (zip.m_storage.IsBinarySplit())
+ mode |= CZipArchive::zipOpenBinSplit;
+ else if (zip.m_storage.IsSplit())
+ mode |= CZipArchive::zipOpenSplit;
+
+ if (pArchiveFile != NULL)
+ m_storage.Open(*pArchiveFile, mode, false);
+ else if (zip.m_storage.m_pFile->HasFilePath())
+ m_storage.Open(zip.GetArchivePath(), mode, 0);
+ else
+ m_storage.Open(*zip.m_storage.m_pFile, mode, false);
InitOnOpen(zip.GetSystemCompatibility(), &zip.m_centralDir);
return true;
}
-void CZipArchive::InitOnOpen(int iArchiveSystCompatib, CZipCentralDir* pSource)
+void CZipArchive::InitOnOpen(int iArchiveSystCompatib, CZipCentralDir* pSource)
{
m_pszPassword.Release();
m_iFileOpened = nothing;
m_szRootPath.Empty();
- m_centralDir.Init(&m_storage, &m_callbacks, &m_stringSettings, pSource);
+ m_centralDir.Init(pSource);
m_iArchiveSystCompatib = iArchiveSystCompatib;
+ m_bStoreFullFileTimes = false;
}
-void CZipArchive::OpenInternal(int iMode)
+void CZipArchive::OpenInternal(int iMode)
{
- InitOnOpen(ZipPlatform::GetSystemID());
- if ((iMode == zipOpen) ||(iMode == zipOpenReadOnly))
+ InitOnOpen(ZipPlatform::GetSystemID());
+ const CBitFlag mode(iMode);
+ if (mode.IsSetAny(zipOpen) || mode.IsSetAll(zipOpenReadOnly))
{
- m_centralDir.Read(m_bExhaustiveRead);
+ m_centralDir.Read();
// if there is at least one file, get system comp. from the first one
if (m_centralDir.IsValidIndex(0))
{
@@ -141,12 +227,12 @@ void CZipArchive::OpenInternal(int iMode) }
}
-void CZipArchive::ThrowError(int err)
+void CZipArchive::ThrowError(int err, LPCTSTR lpszFilePath) const
{
- CZipException::Throw(err, IsClosed() ? _T("") : (LPCTSTR)m_storage.m_pFile->GetFilePath());
+ CZipException::Throw(err, lpszFilePath != NULL ? lpszFilePath : (IsClosed() ? _T("") : (LPCTSTR)m_storage.m_pFile->GetFilePath()));
}
-bool CZipArchive::GetFileInfo(CZipFileHeader & fhInfo, ZIP_INDEX_TYPE uIndex) const
+bool CZipArchive::GetFileInfo(CZipFileHeader & fhInfo, ZIP_INDEX_TYPE uIndex) const
{
if (IsClosed())
{
@@ -161,7 +247,7 @@ bool CZipArchive::GetFileInfo(CZipFileHeader & fhInfo, ZIP_INDEX_TYPE uIndex) c return true;
}
-CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex)
+CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex)
{
if (IsClosed())
{
@@ -174,7 +260,7 @@ CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex) return m_centralDir[uIndex];
}
-const CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex) const
+const CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex) const
{
if (IsClosed())
{
@@ -187,9 +273,7 @@ const CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex) const return m_centralDir[uIndex];
}
-
-
-ZIP_INDEX_TYPE CZipArchive::FindFile(LPCTSTR lpszFileName, int iCaseSensitive, bool bFileNameOnly)
+ZIP_INDEX_TYPE CZipArchive::FindFile(LPCTSTR lpszFileName, int iCaseSensitive, bool bFileNameOnly)
{
if (IsClosed())
{
@@ -215,7 +299,7 @@ ZIP_INDEX_TYPE CZipArchive::FindFile(LPCTSTR lpszFileName, int iCaseSensitive, return m_centralDir.FindFile(lpszFileName, bCS, bSporadically, bFileNameOnly);
}
-bool CZipArchive::OpenFile(ZIP_INDEX_TYPE uIndex)
+bool CZipArchive::OpenFile(ZIP_INDEX_TYPE uIndex)
{
if (IsClosed())
{
@@ -228,7 +312,7 @@ bool CZipArchive::OpenFile(ZIP_INDEX_TYPE uIndex) ASSERT(FALSE);
return false;
}
- if (m_storage.IsSegmented() == 1)
+ if (m_storage.IsNewSegmented())
{
ZIPTRACE("%s(%i) : ZipArchive Library cannot extract from a segmented archive in creation.\n");
return false;
@@ -242,8 +326,9 @@ bool CZipArchive::OpenFile(ZIP_INDEX_TYPE uIndex) m_centralDir.OpenFile(uIndex);
- // check it now, not when reading central to allow reading information
- // but disallow extraction now - unsupported method
+ // Check it now, not when reading central information
+ // but disallow extraction now - unsupported method.
+ // This is to allow reading of local information without throwing an exception.
if (!CZipCompressor::IsCompressionSupported(CurrentFile()->m_uMethod))
{
m_centralDir.CloseFile(true);
@@ -259,7 +344,7 @@ bool CZipArchive::OpenFile(ZIP_INDEX_TYPE uIndex) ThrowError(CZipException::badPassword);
}
CreateCryptograph(CurrentFile()->m_uEncryptionMethod);
- if (!m_pCryptograph->InitDecode(m_pszPassword, *CurrentFile(), m_storage))
+ if (!m_pCryptograph->InitDecode(m_pszPassword, *CurrentFile(), m_storage, !m_centralDir.IsConsistencyCheckOn(checkDecryptionVerifier)))
ThrowError(CZipException::badPassword);
}
@@ -279,13 +364,13 @@ bool CZipArchive::OpenFile(ZIP_INDEX_TYPE uIndex) return true;
}
-CZipFileHeader* CZipArchive::CurrentFile()
+CZipFileHeader* CZipArchive::CurrentFile()
{
ASSERT(m_centralDir.m_pOpenedFile);
return m_centralDir.m_pOpenedFile;
}
-DWORD CZipArchive::ReadFile(void *pBuf, DWORD uSize)
+DWORD CZipArchive::ReadFile(void *pBuf, DWORD uSize)
{
if (m_iFileOpened != extract)
{
@@ -300,22 +385,30 @@ DWORD CZipArchive::ReadFile(void *pBuf, DWORD uSize) }
-void CZipArchive::Close(int iAfterException, bool bUpdateTimeStamp)
+CZipString 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)))
{
ZIPTRACE("%s(%i) : ZipArchive is already closed.\n");
- return;
+ return _T("");
}
if (m_iFileOpened == extract)
+ // when CloseFile returns -1, it doesn't necessarily mean error here (e.g. when using multi seek feature)
+ // if (CloseFile(NULL, iAfterException != afNoException) == -1)
+ // ThrowError(CZipException::badZipFile);
CloseFile(NULL, iAfterException != afNoException);
if (m_iFileOpened == compress)
CloseNewFile(iAfterException != afNoException);
- bool bWrite = iAfterException != afAfterException && !IsClosed(false);// in segmented archive when user aborts
+ if (iAfterException == afNoException)
+ {
+ CommitChanges();
+ }
+
+ bool bWrite = iAfterException != afAfterException && !IsReadOnly() && !IsClosed(false);// in segmented archive when user aborts
if (bWrite)
WriteCentralDirectory(false); // we will flush in CZipStorage::Close
@@ -327,26 +420,30 @@ void CZipArchive::Close(int iAfterException, bool bUpdateTimeStamp) ZIP_INDEX_TYPE iSize = (ZIP_INDEX_TYPE)m_centralDir.GetCount();
for (ZIP_INDEX_TYPE i = 0; i < iSize; i++)
{
- time_t tFileInZipTime = m_centralDir[i]->GetTime();
+ time_t tFileInZipTime = m_centralDir[i]->GetModificationTime();
if (tFileInZipTime > tNewestTime)
tNewestTime = tFileInZipTime;
}
}
- m_centralDir.Close();
- m_stringSettings.Reset();
- CZipString szFileName = m_storage.Close(!bWrite);
+#ifdef _ZIP_UNICODE_CUSTOM
+ ResetStringStoreSettings();
+#endif
+ m_centralDir.Close();
+ CZipString szFileName = m_storage.Close(bWrite, iAfterException != afAfterException);
+ m_pszPassword.Release();
if (bUpdateTimeStamp && !szFileName.IsEmpty())
- ZipPlatform::SetFileModTime(szFileName, tNewestTime);
+ ZipPlatform::SetFileTimes(szFileName, &tNewestTime);
+ return szFileName;
}
-void CZipArchive::WriteCentralDirectory(bool bFlush)
+void CZipArchive::WriteCentralDirectory(bool bFlush)
{
m_centralDir.Write();
if (bFlush)
m_storage.Flush();
}
-void CZipArchive::SetAdvanced(int iWriteBuffer, int iGeneralBuffer, int iSearchBuffer)
+void CZipArchive::SetAdvanced(int iWriteBuffer, int iGeneralBuffer, int iSearchBuffer)
{
if (!IsClosed())
{
@@ -359,21 +456,35 @@ void CZipArchive::SetAdvanced(int iWriteBuffer, int iGeneralBuffer, int iSearch m_storage.m_iLocateBufferSize = iSearchBuffer < 1024 ? 1024 : iSearchBuffer;
}
-int CZipArchive::CloseFile(CZipFile &file)
-{
+int CZipArchive::CloseFile(CZipFile &file)
+{
+#ifdef _ZIP_SYSTEM_WIN
+ CZipFileHeader* pCurrentFile = CurrentFile();
+ time_t tModificationTime = pCurrentFile->GetModificationTime();
+ time_t tCreationTime = pCurrentFile->GetCreationTime();
+ time_t tLastAccessTime = pCurrentFile->GetLastAccessTime();
+ int iRet = ZipPlatform::SetFileTimes((HANDLE)file, &tModificationTime, &tCreationTime, &tLastAccessTime)
+ && ZipPlatform::SetFileAttr(file.GetFilePath(), pCurrentFile->GetSystemAttr()) ? 1 : -2;
+ file.Close();
+ int iCloseRet = CloseFile(NULL);
+ return iCloseRet == 1 ? iRet : iCloseRet;
+#else
CZipString temp = file.GetFilePath();
file.Close();
return CloseFile(temp);
+#endif
+
+
}
-int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException)
+int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException)
{
if (m_iFileOpened != extract)
{
- ZIPTRACE("%s(%i) : No opened file.\n");
+ ZIPTRACE("%s(%i) : There is no opened file.\n");
return 0;
}
-
+ CZipFileHeader* pCurrentFile = CurrentFile();
int iRet = 1;
if (bAfterException)
m_pCompressor->FinishDecompression(true);
@@ -382,7 +493,7 @@ int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException) if (m_pCompressor->m_uUncomprLeft == 0)
{
if (m_centralDir.IsConsistencyCheckOn(checkCRC)
- && !CurrentFile()->m_bIgnoreCrc32
+ && !pCurrentFile->m_bIgnoreCrc32
&& m_pCompressor->m_uCrc32 != CurrentFile()->m_uCrc32)
ThrowError(CZipException::badCrc);
}
@@ -393,12 +504,15 @@ int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException) if (lpszFilePath)
{
- if (!ZipPlatform::SetFileModTime(lpszFilePath, CurrentFile()->GetTime())
- ||!ZipPlatform::SetFileAttr(lpszFilePath, CurrentFile()->GetSystemAttr()))
+ time_t tModificationTime = pCurrentFile->GetModificationTime();
+ time_t tCreationTime = pCurrentFile->GetCreationTime();
+ time_t tLastAccessTime = pCurrentFile->GetLastAccessTime();
+ if (!ZipPlatform::SetFileTimes(lpszFilePath, &tModificationTime, &tCreationTime, &tLastAccessTime )
+ ||!ZipPlatform::SetFileAttr(lpszFilePath, pCurrentFile->GetSystemAttr()))
iRet = -2;
}
if (m_pCryptograph)
- m_pCryptograph->FinishDecode(*CurrentFile(), m_storage);
+ m_pCryptograph->FinishDecode(*pCurrentFile, m_storage);
}
m_centralDir.CloseFile(bAfterException);
@@ -408,26 +522,11 @@ int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException) return iRet;
}
-bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpszFilePath,
+bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpszFilePath,
ZIP_INDEX_TYPE uReplaceIndex)
{
- if (IsClosed())
- {
- ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
- return false;
- }
-
- if (m_iFileOpened)
- {
- ZIPTRACE("%s(%i) : A file already opened.\n");
- return false;
- }
-
- if (m_storage.IsSegmented() == -1)
- {
- ZIPTRACE("%s(%i) : ZipArchive Library cannot add files to an existing segmented archive.\n");
+ if (!CanModify(true))
return false;
- }
if (GetCount() ==(WORD)USHRT_MAX)
{
@@ -435,27 +534,46 @@ bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpsz return false;
}
- DWORD uAttr = 0;
- time_t ttime;
+
if (lpszFilePath)
{
+ DWORD uAttr = 0;
if (!ZipPlatform::GetFileAttr(lpszFilePath, uAttr))
+ {
// do not continue - if the file was a directory then not recognizing it will cause
// serious errors (need uAttr to recognize it)
- return false;
- ZipPlatform::GetFileModTime(lpszFilePath, ttime);
- }
-
- if (lpszFilePath)
- {
- header.SetTime(ttime);
- SetFileHeaderAttr(header, uAttr); // set system compatibility as well
+ ThrowError(CZipException::fileError, lpszFilePath);
+ }
+ if (m_bStoreFullFileTimes)
+ {
+ time_t tModTime = (time_t)0, tCreateTime = (time_t)0, tLastAccessTime = (time_t)0;
+ ZipPlatform::GetFileTimes(lpszFilePath, &tModTime, &tCreateTime, &tLastAccessTime);
+ header.SetModificationTime(tModTime, true, m_bUseUtcFileTimes);
+ header.SetCreationTime(tCreateTime);
+ header.SetLastAccessTime(tLastAccessTime);
+ }
+ else
+ {
+ time_t ttime;
+ ZipPlatform::GetFileTimes(lpszFilePath, &ttime);
+ header.SetModificationTime(ttime, false, m_bUseUtcFileTimes);
+ }
+ header.SetSystemCompatibility(m_iArchiveSystCompatib);
+ header.SetSystemAttr(uAttr);
}
else
{
- header.SetSystemCompatibility(m_iArchiveSystCompatib);
+ header.SetSystemCompatibility(m_iArchiveSystCompatib, true);
if (!header.HasTime())
- header.SetTime(time(NULL));
+ {
+ time_t tNow = time(NULL);
+ header.SetModificationTime(tNow, m_bStoreFullFileTimes, m_bUseUtcFileTimes);
+ if (m_bStoreFullFileTimes)
+ {
+ header.SetCreationTime(tNow);
+ header.SetLastAccessTime(tNow);
+ }
+ }
}
CZipString szFileName = header.GetFileName();
@@ -486,9 +604,6 @@ bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpsz #endif
bool bReplace = uReplaceIndex != ZIP_FILE_INDEX_UNSPECIFIED;
-
- if (iLevel < -1 || iLevel > 9)
- iLevel = -1;
if (bEncrypted)
{
@@ -501,10 +616,22 @@ bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpsz ClearCryptograph();
}
- if (iLevel == 0 || bIsDirectory)
+ if (iLevel < -1 || iLevel > 9)
+ iLevel = -1;
+
+ header.m_uMethod = m_uCompressionMethod;
+
+ if (iLevel != 0 && m_uCompressionMethod == CZipCompressor::methodStore)
+ iLevel = 0;
+ else if (iLevel == 0 && m_uCompressionMethod != CZipCompressor::methodStore)
header.m_uMethod = CZipCompressor::methodStore;
- else
- header.m_uMethod = m_uCompressionMethod;
+
+ if (bIsDirectory && iLevel != 0)
+ {
+ iLevel = 0;
+ if (m_uCompressionMethod != CZipCompressor::methodStore)
+ header.m_uMethod = CZipCompressor::methodStore;
+ }
CreateCompressor(header.m_uMethod);
CZipFileHeader* pHeader = m_centralDir.AddNewFile(header, uReplaceIndex, iLevel);
@@ -513,9 +640,9 @@ bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpsz if (bReplace)
{
// this will be used in GetLocalSize and WriteLocal
- pHeader->PrepareFileName();
+ pHeader->PrepareStringBuffers();
// we use the local size, because the real does not exist yet
- ZIP_SIZE_TYPE uFileSize = pHeader->GetDataSize(true, false) + pHeader->GetLocalSize(false) + pHeader->GetDataDescriptorSize(&m_storage);
+ ZIP_SIZE_TYPE uFileSize = pHeader->m_uLocalComprSize + pHeader->GetLocalSize(false) + pHeader->GetDataDescriptorSize(&m_storage);
InitBuffer();
MakeSpaceForReplace(uReplaceIndex, uFileSize, szFileName);
ReleaseBuffer();
@@ -532,11 +659,11 @@ bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpsz return true;
}
-
-bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex,
+bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex,
LPCTSTR lpszPath,
bool bFullPath,
LPCTSTR lpszNewName,
+ ZipPlatform::FileOverwriteMode iOverwriteMode,
DWORD nBufSize)
{
@@ -544,6 +671,8 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, return false;
CZipFileHeader* pHeader = (*this)[uIndex];
+ if (!pHeader)
+ return false;
CZipString szFileNameInZip = pHeader->GetFileName();
CZipString szFile = PredictExtractedFileName(szFileNameInZip, lpszPath, bFullPath, lpszNewName);
CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbExtract);
@@ -565,18 +694,49 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, }
else
{
+ int iAborted = 0;
+
+ if (ZipPlatform::FileExists(szFile) != 0)
+ {
+ if ((iOverwriteMode & ZipPlatform::fomOnlyIfNewer) != 0)
+ {
+ time_t fileInZipTime = pHeader->GetModificationTime();
+ if (fileInZipTime > 0)
+ {
+ time_t fileTime;
+ if (ZipPlatform::GetFileTimes(szFile, &fileTime) && fileTime > 0 && fileTime >= fileInZipTime)
+ {
+ if (pCallback)
+ {
+ pCallback->SetTotal(pHeader->m_uUncomprSize);
+ if (!pCallback->RequestCallback(pHeader->m_uUncomprSize) || !pCallback->RequestLastCallback())
+ {
+ iAborted = CZipException::abortedSafely;
+ }
+ pCallback->CallbackEnd();
+ if (iAborted)
+ CZipException::Throw(iAborted, szFile);
+ }
+ return true;
+ }
+ }
+ }
+ ZipPlatform::RemoveFile(szFile, true, iOverwriteMode);
+ }
+
if (!OpenFile(uIndex))
return false;
+ CZipPathComponent zpc(szFile);
+ ZipPlatform::ForceDirectory(zpc.GetFilePath());
if (pCallback)
pCallback->SetTotal(pHeader->m_uUncomprSize);
- CZipPathComponent zpc(szFile);
- ZipPlatform::ForceDirectory(zpc.GetFilePath());
+
CZipFile f(szFile, CZipFile::modeWrite |
- CZipFile::modeCreate | CZipFile::shareDenyWrite);
+ CZipFile::modeCreate | CZipFile::shareDenyWrite);
DWORD iRead;
CZipAutoBuffer buf(nBufSize);
- int iAborted = 0;
+
for(;;)
{
iRead = ReadFile(buf, buf.GetSize());
@@ -597,13 +757,13 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, }
}
+ int iResult;
if (pCallback)
{
if (!iAborted)
{
- bool bRet = CloseFile(f) == 1;
- pCallback->CallbackEnd();
- return bRet;
+ iResult = CloseFile(f);
+ pCallback->CallbackEnd();
}
else
{
@@ -618,7 +778,7 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, }
// if any exception was thrown, then we are not successful
// catch all exceptions to throw aborted exception only
-#ifdef ZIP_ARCHIVE_MFC
+#ifdef _ZIP_IMPL_MFC
catch(CException* e)
{
e->Delete();
@@ -642,12 +802,17 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, }
}
else
- return CloseFile(f) == 1;
+ {
+ iResult = CloseFile(f);
+ }
+ if (iResult == -1)
+ ThrowError(CZipException::badZipFile, szFile);
+ return iResult == 1;
}
}
-bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex,
- CZipMemFile& mf,
+bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex,
+ CZipAbstractFile& af,
bool bRewind,
DWORD nBufSize)
{
@@ -655,11 +820,14 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, return false;
CZipFileHeader* pHeader = (*this)[uIndex];
+ if (!pHeader || pHeader->IsDirectory())
+ return false;
+
CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbExtract);
if (pCallback)
pCallback->Init(pHeader->GetFileName());
- if (pHeader->IsDirectory() || !OpenFile(uIndex))
+ if (!OpenFile(uIndex))
return false;
if (pCallback)
@@ -667,11 +835,11 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, CZipAutoBuffer buf(nBufSize);
- //mf.SeekToEnd();
+ //af.SeekToEnd();
ZIP_FILE_USIZE oldPos = 0;
if (bRewind)
- oldPos = mf.GetPosition();
+ oldPos = af.GetPosition();
DWORD iRead;
int iAborted = 0;
@@ -684,7 +852,7 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, iAborted = CZipException::abortedSafely;
break;
}
- mf.Write(buf, iRead);
+ af.Write(buf, iRead);
if (pCallback && !pCallback->RequestCallback(iRead))
{
if (iRead == buf.GetSize() && ReadFile(buf, 1) != 0) // test one byte if there is something left
@@ -700,8 +868,12 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, {
if (!iAborted)
{
- bRet = CloseFile() == 1;
- pCallback->CallbackEnd();
+ int iResult = CloseFile();
+ pCallback->CallbackEnd();
+
+ if (iResult == -1)
+ ThrowError(CZipException::badZipFile);
+ bRet = iResult == 1;
}
else
{
@@ -716,7 +888,7 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, }
// if any exception was thrown, then we are not successful
// catch all exceptions to thrown aborted exception only
- #ifdef ZIP_ARCHIVE_MFC
+ #ifdef _ZIP_IMPL_MFC
catch(CException* e)
{
e->Delete();
@@ -736,21 +908,28 @@ bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, pCallback->CallbackEnd();
if (bRewind)
- mf.Seek(oldPos, CZipMemFile::begin);
+ af.SafeSeek(oldPos, true);
CZipException::Throw(iAborted);
return false; // for the compiler
}
}
else
- bRet = CloseFile() == 1;
+ {
+ int iResult = CloseFile();
+ // when using seeking, it's expected to return -1
+
+ if (iResult == -1)
+ ThrowError(CZipException::badZipFile);
+ bRet = iResult == 1;
+ }
if (bRewind)
- mf.Seek(oldPos, CZipMemFile::begin);
+ af.SafeSeek(oldPos, true);
return bRet;
}
-bool CZipArchive::WriteNewFile(const void *pBuf, DWORD uSize)
+bool CZipArchive::WriteNewFile(const void *pBuf, DWORD uSize)
{
if (m_iFileOpened != compress)
{
@@ -762,7 +941,7 @@ bool CZipArchive::WriteNewFile(const void *pBuf, DWORD uSize) return true;
}
-bool CZipArchive::CloseNewFile(bool bAfterException)
+bool CZipArchive::CloseNewFile(bool bAfterException)
{
if (m_iFileOpened != compress)
{
@@ -782,20 +961,45 @@ bool CZipArchive::CloseNewFile(bool bAfterException) }
m_iFileOpened = nothing;
ClearCryptograph();
- if (m_bAutoFlush && !bAfterException)
- Flush();
+ if (!bAfterException)
+ Finalize(true);
return true;
}
-bool CZipArchive::RemoveFile(ZIP_INDEX_TYPE uIndex)
+bool CZipArchive::RemoveFile(ZIP_INDEX_TYPE uIndex, bool bRemoveData)
{
- CZipIndexesArray indexes;
- indexes.Add(uIndex);
- return RemoveFiles(indexes);
+ if (bRemoveData)
+ {
+ CZipIndexesArray indexes;
+ indexes.Add(uIndex);
+ return RemoveFiles(indexes);
+ }
+ else
+ {
+ if (!CanModify())
+ return false;
+
+ if (GetCount() == 0)
+ {
+ ZIPTRACE("%s(%i) : There is nothing to delete: the archive is empty.\n");
+ return false;
+ }
+
+ m_centralDir.RemoveFromDisk();
+ if (m_centralDir.IsValidIndex(uIndex))
+ {
+ m_centralDir.RemoveFile(NULL, uIndex, false);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
}
-void CZipArchive::GetIndexes(const CZipStringArray &aNames, CZipIndexesArray& aIndexes)
+void CZipArchive::GetIndexes(const CZipStringArray &aNames, CZipIndexesArray& aIndexes)
{
if (IsClosed())
{
@@ -807,7 +1011,7 @@ void CZipArchive::GetIndexes(const CZipStringArray &aNames, CZipIndexesArray& a aIndexes.Add(FindFile(aNames[(ZIP_ARRAY_SIZE_TYPE)i], ffDefault, false));
}
-bool CZipArchive::RemoveFiles(const CZipStringArray &aNames)
+bool CZipArchive::RemoveFiles(const CZipStringArray &aNames)
{
CZipIndexesArray indexes;
GetIndexes(aNames, indexes);
@@ -823,23 +1027,10 @@ struct CZipDeleteInfo bool m_bDelete;
};
-bool CZipArchive::RemoveFiles(CZipIndexesArray &aIndexes)
+bool CZipArchive::RemoveFiles(CZipIndexesArray &aIndexes)
{
- if (IsClosed())
+ if (!CanModify())
{
- ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
- return false;
- }
-
- if (m_storage.IsSegmented())
- {
- ZIPTRACE("%s(%i) : ZipArchive Library cannot delete files from a segmented archive.\n");
- return false;
- }
-
- if (m_iFileOpened)
- {
- ZIPTRACE("%s(%i) : ZipArchive Library cannot delete files if there is a file opened.\n");
return false;
}
@@ -881,10 +1072,10 @@ bool CZipArchive::RemoveFiles(CZipIndexesArray &aIndexes) }
m_centralDir.RemoveFromDisk();
- m_storage.m_pFile->SetLength((ZIP_FILE_USIZE) m_storage.m_uBytesBeforeZip);
+ // we take into account the bytes present in an archive that was created with CZipArchive::zipCreateAppend
+ m_storage.m_pFile->SetLength(GetFileInfo(0)->m_uOffset + (ZIP_FILE_USIZE) m_storage.m_uBytesBeforeZip);
m_centralDir.RemoveAll();
- if (m_bAutoFlush)
- Flush();
+ Finalize(true);
if (pCallback)
pCallback->CallbackEnd();
return true;
@@ -973,7 +1164,7 @@ bool CZipArchive::RemoveFiles(CZipIndexesArray &aIndexes) while(i > 0)
{
i--;
- // cannot use a decreasing loop because i is unsigned and instead negative at the end of the loop it will be maximum positive
+ // cannot use a decreasing loop because it is unsigned and instead negative at the end of the loop it will be maximum positive
const CZipDeleteInfo& di = aInfo[(ZIP_ARRAY_SIZE_TYPE)i];
if (!di.m_bDelete)
uTotalToMoveBytes += uLastOffset - di.m_pHeader->m_uOffset;
@@ -1040,30 +1231,16 @@ bool CZipArchive::RemoveFiles(CZipIndexesArray &aIndexes) if (pCallback)
pCallback->CallbackEnd();
- if (m_bAutoFlush)
- Flush();
+ Finalize(true);
return true;
}
-bool CZipArchive::ShiftData(ZIP_SIZE_TYPE uOffset)
+bool CZipArchive::ShiftData(ZIP_SIZE_TYPE uOffset)
{
- if (IsClosed())
+ if (!CanModify())
{
- ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n");
- return false;
- }
-
- if (m_storage.IsSegmented() != 0)
- {
- ZIPTRACE("%s(%i) : Cannot shift data for a segmented archive.\n");
- return false;
- }
-
- if (m_iFileOpened)
- {
- ZIPTRACE("%s(%i) : A file should not be opened.\n");
return false;
}
@@ -1101,13 +1278,13 @@ bool CZipArchive::ShiftData(ZIP_SIZE_TYPE uOffset) return true;
}
-bool CZipArchive::PrependData(LPCTSTR lpszFilePath, LPCTSTR lpszNewExt)
+bool CZipArchive::PrependData(LPCTSTR lpszFilePath, LPCTSTR lpszNewExt)
{
CZipFile file(lpszFilePath, CZipFile::modeRead | CZipFile::shareDenyNone);
return PrependData(file, lpszNewExt);
}
-bool CZipArchive::PrependData(CZipAbstractFile& file, LPCTSTR lpszNewExt)
+bool CZipArchive::PrependData(CZipAbstractFile& file, LPCTSTR lpszNewExt)
{
if (file.IsClosed())
{
@@ -1145,25 +1322,28 @@ bool CZipArchive::PrependData(CZipAbstractFile& file, LPCTSTR lpszNewExt) }
while (!bBreak);
- if (m_storage.m_bInMemory || lpszNewExt == NULL)
+ if (lpszNewExt == NULL)
return true;
CZipString szInitialPath = m_storage.m_pFile->GetFilePath();
+ if (szInitialPath.IsEmpty()) // is the case for in-memory archives
+ return true;
// must close to rename
+#pragma warning(suppress: 26444)
Close();
CZipPathComponent zpc(szInitialPath);
zpc.SetExtension(lpszNewExt);
CZipString szNewPath = zpc.GetFullPath();
if (!ZipPlatform::RenameFile(szInitialPath, szNewPath, false))
return false;
-#ifdef ZIP_ARCHIVE_LNX
+#ifdef _ZIP_SYSTEM_LINUX
return ZipPlatform::SetExeAttr(szNewPath);
#else
return true;
#endif
}
-bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath,
+bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath,
int iComprLevel,
bool bFullPath,
int iSmartLevel,
@@ -1177,7 +1357,7 @@ bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath, return AddNewFile(zanfi);
}
-bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath,
+bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath,
LPCTSTR lpszFileNameInZip,
int iComprLevel,
int iSmartLevel,
@@ -1190,13 +1370,13 @@ bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath, return AddNewFile(zanfi);
}
-bool CZipArchive::AddNewFile(CZipMemFile& mf,
+bool CZipArchive::AddNewFile(CZipAbstractFile& af,
LPCTSTR lpszFileNameInZip,
int iComprLevel,
int iSmartLevel,
unsigned long nBufSize)
{
- CZipAddNewFileInfo zanfi(&mf, lpszFileNameInZip);
+ CZipAddNewFileInfo zanfi(&af, lpszFileNameInZip);
zanfi.m_iComprLevel = iComprLevel;
zanfi.m_iSmartLevel = iSmartLevel;
zanfi.m_nBufSize = nBufSize;
@@ -1232,7 +1412,7 @@ private: CZipArchive* m_pZip;
};
-bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info)
+bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info)
{
// no need for ASSERT and TRACE here - it will be done by OpenNewFile
@@ -1248,7 +1428,7 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) return false;
}
- bool bSegm = GetSegmMode() != 0;
+ bool bSegm = m_storage.IsSegmented();
// checking the replace index
if (!UpdateReplaceIndex(info.m_uReplaceIndex))
@@ -1257,25 +1437,38 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) bool bReplace = info.m_uReplaceIndex != ZIP_FILE_INDEX_UNSPECIFIED;
DWORD uAttr;
- time_t ttime;
+ time_t tModificationTime = (time_t) 0, tCreationTime = time_t(0), tLastAccessTime = (time_t)0;
if (info.m_pFile)
{
uAttr = ZipPlatform::GetDefaultAttributes();
- ttime = time(NULL);
+ tModificationTime = time(NULL);
+ if (m_bStoreFullFileTimes)
+ {
+ tCreationTime = tLastAccessTime = tModificationTime;
+ }
}
else
{
if (!ZipPlatform::GetFileAttr(info.m_szFilePath, uAttr))
- return false; // we don't know whether it is a file or a directory
- ZipPlatform::GetFileModTime(info.m_szFilePath, ttime);
+ ThrowError(CZipException::fileError, info.m_szFilePath); // we don't know whether it is a file or a directory
+ if (m_bStoreFullFileTimes)
+ ZipPlatform::GetFileTimes(info.m_szFilePath, &tModificationTime, &tCreationTime, &tLastAccessTime);
+ else
+ ZipPlatform::GetFileTimes(info.m_szFilePath, &tModificationTime);
}
- CZipFileHeader header;
- SetFileHeaderAttr(header, uAttr);
+ CZipFileHeader header;
+ header.SetSystemCompatibility(m_iArchiveSystCompatib);
+ header.SetSystemAttr(uAttr);
if (info.m_szFileNameInZip.IsEmpty())
info.m_szFileNameInZip = PredictFileNameInZip(info.m_szFilePath, info.m_bFullPath, header.IsDirectory() ? prDir : prFile);
header.SetFileName(info.m_szFileNameInZip);
- header.SetTime(ttime);
- bool bInternal = (info.m_iSmartLevel & zipsmInternal01) != 0;
+ header.SetModificationTime(tModificationTime, m_bStoreFullFileTimes, m_bUseUtcFileTimes);
+ if (m_bStoreFullFileTimes)
+ {
+ header.SetCreationTime(tCreationTime);
+ header.SetLastAccessTime(tLastAccessTime);
+ }
+ bool bInternal = info.m_iSmartLevel.IsSetAny(zipsmInternal01);
if (header.IsDirectory()) // will never be when m_pFile is not NULL, so we don't check it
{
@@ -1292,7 +1485,7 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) // clear password for a directory
CZipSmClrPass smcp;
- if (info.m_iSmartLevel & zipsmCPassDir)
+ if (info.m_iSmartLevel.IsSetAny(zipsmCPassDir))
smcp.ClearPasswordSmartly(this);
bool bRet = OpenNewFile(header, CZipCompressor::levelStore, NULL, info.m_uReplaceIndex);
@@ -1305,10 +1498,15 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) }
CZipSmClrPass smcp;
+ if (m_uCompressionMethod == CZipCompressor::methodStore)
+ {
+ info.m_iComprLevel = 0;
+ }
+
bool bIsCompression = info.m_iComprLevel != 0;
- bool bEff = (info.m_iSmartLevel & zipsmCheckForEff)&& bIsCompression;
- bool bCheckForZeroSized = (info.m_iSmartLevel & zipsmCPFile0) && WillEncryptNextFile();
- bool bCheckForSmallFiles = (info.m_iSmartLevel & zipsmNotCompSmall) && bIsCompression;
+ bool bEff = info.m_iSmartLevel.IsSetAny(zipsmCheckForEff)&& bIsCompression;
+ bool bCheckForZeroSized = info.m_iSmartLevel.IsSetAny(zipsmCPFile0) && WillEncryptNextFile();
+ bool bCheckForSmallFiles = info.m_iSmartLevel.IsSetAny(zipsmNotCompSmall) && bIsCompression;
ZIP_SIZE_TYPE uFileSize = ZIP_SIZE_TYPE(-1);
bool bNeedTempArchive = (bEff && bSegm) || (bReplace && bIsCompression);
if (bCheckForSmallFiles || bCheckForZeroSized || bNeedTempArchive)
@@ -1319,7 +1517,7 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) else
{
if (!ZipPlatform::GetFileSize(info.m_szFilePath, uFileSize) && bEff)
- bEff = false; // the file size is needed only when efficient in a segmented archive
+ uFileSize = ZIP_SIZE_TYPE(-1);
}
if (uFileSize != ZIP_SIZE_TYPE(-1))
@@ -1329,27 +1527,36 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) if (bCheckForSmallFiles && uFileSize < 5)
info.m_iComprLevel = 0;
}
+ else
+ {
+ bEff = false;
+ bNeedTempArchive = false;
+ if (bReplace && bIsCompression)
+ {
+ info.m_iComprLevel = 0;
+ bIsCompression = false;
+ }
+ }
}
- bool bEffInMem = bEff && (info.m_iSmartLevel & zipsmMemoryFlag);
+ bool bEffInMem = bEff && info.m_iSmartLevel.IsSetAny(zipsmMemoryFlag);
CZipString szTempFileName;
if (bNeedTempArchive && (bEffInMem ||
- !(szTempFileName = ZipPlatform::GetTmpFileName(
- m_szTempPath.IsEmpty() ? NULL : (LPCTSTR)m_szTempPath, uFileSize)
- ).IsEmpty()))
+ !(szTempFileName = ZipPlatform::GetTmpFileName(m_szTempPath.IsEmpty() ? NULL : (LPCTSTR)m_szTempPath, uFileSize)).IsEmpty()))
{
CZipMemFile* pmf = NULL;
- CZipArchive zip;
+ CZipArchive zip;
try
{
- // compress first to a temporary file, if ok - copy the data, if not - add storing
-
+ // compress first to a temporary file, if ok - copy the data, if not - add storing
if (bEffInMem)
{
pmf = new CZipMemFile;
- zip.Open(*pmf, zipCreate);
+ if (!zip.Open(*pmf, zipCreate))
+ return false;
}
- else
- zip.Open(szTempFileName, zipCreate);
+ else if (!zip.Open(szTempFileName, zipCreate))
+ return false;
+
zip.SetRootPath(m_szRootPath);
zip.SetPassword(GetPassword());
zip.SetEncryptionMethod(m_iEncryptionMethod);
@@ -1380,7 +1587,8 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) }
catch (bool bRet)
{
- zip.Close(!bRet); // that doesn't really matter how it will be closed
+#pragma warning(suppress: 26444)
+ zip.Close(bRet ? CZipArchive::afNoException : CZipArchive::afAfterException); // that doesn't really matter how it will be closed
if (pmf)
delete pmf;
if (!bEffInMem)
@@ -1390,7 +1598,8 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) }
catch (...)
{
- zip.Close(true);
+#pragma warning(suppress: 26444)
+ zip.Close(CZipArchive::afAfterException);
if (pmf)
delete pmf;
if (!bEffInMem)
@@ -1413,15 +1622,21 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) // cannot be shareDenyWrite
// If you specify the GENERIC_READ and GENERIC_WRITE access modes along with the FILE_SHARE_READ and FILE_SHARE_WRITE sharing modes in your first call to CreateFile. If you specify the GENERIC_READ and GENERIC_WRITE access modes and the FILE_SHARE_READ sharing mode only in your second call to CreateFile, the function will fail with a sharing violation because the read-only sharing mode specified in the second call conflicts with the read/write access that has been granted in the first call.
// Original information was here (but not any longer): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/creating_and_opening_files.asp
- if (!f.Open(info.m_szFilePath, CZipFile::modeRead | CZipFile::shareDenyNone, false))
+ if (!f.Open(info.m_szFilePath, CZipFile::modeRead | CZipFile::shareDenyNone, true))
return false;
pf = &f;
}
ASSERT(pf);
- // call init before opening (in case of exception we have the names)
- uFileSize = (ZIP_SIZE_TYPE)pf->GetLength();
+ if (uFileSize == ZIP_SIZE_TYPE(-1))
+ {
+ uFileSize = (ZIP_SIZE_TYPE)pf->GetLength();
+ if (uFileSize == ZIP_SIZE_TYPE(-1))
+ {
+ return false;
+ }
+ }
// predict sizes in local header, so that zip64 can write extra header if needed
header.m_uLocalUncomprSize = uFileSize;
if (!bIsCompression)
@@ -1451,12 +1666,12 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) pCallback->SetTotal(uFileSize);
}
- CZipAutoBuffer buf(info.m_nBufSize);
+ CZipAutoBuffer buf((DWORD)info.m_nBufSize);
DWORD iRead;
int iAborted = 0;
do
{
- iRead = pf->Read(buf, info.m_nBufSize);
+ iRead = (DWORD)pf->Read(buf, (UINT)info.m_nBufSize);
if (iRead)
{
WriteNewFile(buf, iRead);
@@ -1487,7 +1702,7 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) if (pCallback)
{
if (!iAborted && !pCallback->RequestLastCallback())
- // temporaty value - safe abort
+ // temporary value - safe abort
iAborted = CZipException::aborted;
if (!iAborted)
@@ -1500,12 +1715,11 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) // possible safe abort
if (iAborted == CZipException::aborted)
{
- bool bRet;
try
{
bRet = CloseNewFile();
}
-#ifdef ZIP_ARCHIVE_MFC
+#ifdef _ZIP_IMPL_MFC
catch(CException* e)
{
e->Delete();
@@ -1548,7 +1762,7 @@ bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) return true;
}
-bool CZipArchive::RemoveLast(bool bRemoveAnyway)
+bool CZipArchive::RemoveLast(bool bRemoveAnyway)
{
if (GetCount() == 0)
return false;
@@ -1587,13 +1801,15 @@ public: class CCalculateAddFilesEnumerator : public ZipArchiveLib::CDirEnumerator
{
CZipActionCallback* m_pCallback;
+ bool m_countDirectories;
public:
ZIP_FILE_USIZE m_uTotalBytes;
ZIP_FILE_USIZE m_uTotalFiles;
- CCalculateAddFilesEnumerator(LPCTSTR lpszDirectory, bool bRecursive, CZipActionCallback* pCallback)
+ CCalculateAddFilesEnumerator(LPCTSTR lpszDirectory, bool bRecursive, CZipActionCallback* pCallback, bool countDirectories)
:ZipArchiveLib::CDirEnumerator(lpszDirectory, bRecursive)
{
m_pCallback = pCallback;
+ m_countDirectories = countDirectories;
m_uTotalFiles = m_uTotalBytes = 0;
}
protected:
@@ -1605,6 +1821,10 @@ protected: bool Process(LPCTSTR, const ZipArchiveLib::CFileInfo& info)
{
+ // do not count directories
+ if (info.IsDirectory() && !m_countDirectories)
+ return true;
+
m_uTotalFiles++;
m_uTotalBytes += info.m_uSize;
if (m_pCallback && !m_pCallback->RequestCallback())
@@ -1627,40 +1847,7 @@ protected: }
};
-class CAddFilesEnumerator : public ZipArchiveLib::CDirEnumerator
-{
- CZipArchive* m_pZip;
- CZipActionCallback* m_pMultiCallback;
- int m_iComprLevel;
- int m_iSmartLevel;
- unsigned long m_nBufSize;
-public:
- CAddFilesEnumerator(LPCTSTR lpszDirectory,
- bool bRecursive,
- CZipArchive* pZip,
- int iComprLevel,
- int iSmartLevel,
- unsigned long nBufSize,
- CZipActionCallback* pMultiCallback)
- :ZipArchiveLib::CDirEnumerator(lpszDirectory, bRecursive), m_pZip(pZip)
- {
- m_iComprLevel = iComprLevel;
- m_nBufSize = nBufSize;
- m_iSmartLevel = iSmartLevel;
- m_pMultiCallback = pMultiCallback;
- }
-protected:
- bool Process(LPCTSTR lpszPath, const ZipArchiveLib::CFileInfo&)
- {
- bool ret = m_pZip->AddNewFile(lpszPath, m_iComprLevel, m_pZip->GetRootPath().IsEmpty() != 0, m_iSmartLevel, m_nBufSize);
- if (ret && m_pMultiCallback)
- if (!m_pMultiCallback->MultiActionsNext())
- CZipException::Throw(CZipException::abortedSafely);
- return ret;
- }
-};
-
-bool CZipArchive::AddNewFiles(LPCTSTR lpszPath,
+bool CZipArchive::AddNewFiles(LPCTSTR lpszPath,
CFileFilter& filter,
bool bRecursive,
int iComprLevel,
@@ -1668,16 +1855,35 @@ bool CZipArchive::AddNewFiles(LPCTSTR lpszPath, int iSmartLevel,
unsigned long nBufSize)
{
+ CZipAddFilesEnumerator addFilesEnumerator(lpszPath, bRecursive, iComprLevel, iSmartLevel, nBufSize);
+ return AddNewFiles(addFilesEnumerator, filter, bSkipInitialPath);
+}
+
+bool CZipArchive::AddNewFiles(CZipAddFilesEnumerator& addFilesEnumerator, CFileFilter& filter, bool bSkipInitialPath)
+{
+ if (IsClosed())
+ {
+ ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
+ return false;
+ }
+ addFilesEnumerator.Initialize(this);
CZipRootPathRestorer restorer;
if (bSkipInitialPath)
- restorer.SetNewRootPath(this, lpszPath);
+ {
+ CZipString directory = addFilesEnumerator.GetDirectory();
+ if (directory.IsEmpty() || directory == _T(".")) // an empty directory is set to "." in the constructor of CDirEnumerator
+ restorer.SetNewRootPath(this, NULL);
+ else
+ restorer.SetNewRootPath(this, directory);
+ }
CZipActionCallback* pMultiCallback = GetCallback(CZipActionCallback::cbMultiAdd);
if (pMultiCallback)
{
// if multi callback is set, calculate total data to process
// call cbCalculateForMulti in the meantime
- CCalculateAddFilesEnumerator calculateEnumerator(lpszPath, bRecursive, GetCallback(CZipActionCallback::cbCalculateForMulti));
+ CCalculateAddFilesEnumerator calculateEnumerator(addFilesEnumerator.GetDirectory(), addFilesEnumerator.IsRecursive(),
+ GetCallback(CZipActionCallback::cbCalculateForMulti), (addFilesEnumerator.m_iSmartLevel & CZipArchive::zipsmIgnoreDirectories) == 0);
if (!calculateEnumerator.Start(filter))
return false;
if (pMultiCallback->m_iType != CZipActionCallback::cbMultiAdd)
@@ -1688,7 +1894,6 @@ bool CZipArchive::AddNewFiles(LPCTSTR lpszPath, try
{
- CAddFilesEnumerator addFilesEnumerator(lpszPath, bRecursive, this, iComprLevel, iSmartLevel, nBufSize, pMultiCallback);
bool ret = addFilesEnumerator.Start(filter);
if (pMultiCallback)
pMultiCallback->MultiActionsEnd();
@@ -1703,17 +1908,17 @@ bool CZipArchive::AddNewFiles(LPCTSTR lpszPath, }
-CZipString CZipArchive::GetArchivePath() const
+CZipString CZipArchive::GetArchivePath() const
{
if (IsClosed(false))
{
- ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
+ ZIPTRACE("%s(%i) : ZipArchive file is closed.\n");
return _T("");
}
return m_storage.m_pFile->GetFilePath();
}
-CZipString CZipArchive::GetGlobalComment() const
+CZipString CZipArchive::GetGlobalComment() const
{
if (IsClosed())
{
@@ -1725,53 +1930,27 @@ CZipString CZipArchive::GetGlobalComment() const return temp;
}
-bool CZipArchive::SetGlobalComment(LPCTSTR lpszComment)
+bool CZipArchive::SetGlobalComment(LPCTSTR lpszComment, UINT codePage)
{
- if (IsClosed())
+ if (!CanModify(true))
{
- ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
return false;
}
- if (m_storage.IsSegmented() == -1)
+ if (codePage == ZIP_DEFAULT_CODE_PAGE)
{
- ZIPTRACE("%s(%i) : ZipArchive Library cannot modify the global comment of an existing segmented archive.\n");
- return false;
+ codePage = ZipCompatibility::GetDefaultCommentCodePage(m_iArchiveSystCompatib);
}
-
- m_centralDir.SetComment(lpszComment);
- if (m_bAutoFlush)
- Flush();
-
+ m_centralDir.SetComment(lpszComment, codePage);
+ Finalize(true);
return true;
}
-
-
-ZIP_VOLUME_TYPE CZipArchive::GetCurrentVolume() const
+ZIP_VOLUME_TYPE CZipArchive::GetCurrentVolume() const
{
return (ZIP_VOLUME_TYPE)(m_storage.GetCurrentVolume() + 1);
}
-bool CZipArchive::SetFileComment(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszComment)
-{
- if (IsClosed())
- {
- ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
- return false;
- }
- if (m_storage.IsSegmented() == -1)
- {
- ZIPTRACE("%s(%i) : ZipArchive Library cannot modify the file comment in an existing segmented archive.\n");
- return false;
- }
-
- m_centralDir.SetFileComment(uIndex, lpszComment);
- if (m_bAutoFlush)
- Flush();
- return true;
-}
-
-bool CZipArchive::SetPassword(LPCTSTR lpszPassword)
+bool CZipArchive::SetPassword(LPCTSTR lpszPassword, UINT codePage)
{
if (m_iFileOpened != nothing)
{
@@ -1782,14 +1961,23 @@ bool CZipArchive::SetPassword(LPCTSTR lpszPassword) {
ZIPTRACE("%s(%i) : Setting the password for a closed archive has no effect.\n");
}
+
if (lpszPassword)
- ZipCompatibility::ConvertStringToBuffer(lpszPassword, m_pszPassword, CP_ACP);
+ {
+ if (codePage == ZIP_DEFAULT_CODE_PAGE)
+ {
+ codePage = ZipCompatibility::GetDefaultPasswordCodePage(m_iArchiveSystCompatib);
+ }
+ ZipCompatibility::ConvertStringToBuffer(lpszPassword, m_pszPassword, codePage);
+ }
else
+ {
m_pszPassword.Release();
+ }
return true;
}
-bool CZipArchive::SetEncryptionMethod(int iEncryptionMethod)
+bool CZipArchive::SetEncryptionMethod(int iEncryptionMethod)
{
if (m_iFileOpened == compress)
{
@@ -1811,6 +1999,7 @@ struct CZipEncryptFileInfo m_uLocalSizeDiff = 0;
m_uDescriptorSizeDiff = 0;
m_uIndex = 0;
+ m_uUncompressedOffset = 0;
}
CZipEncryptFileInfo(CZipFileHeader* pHeader, DWORD uLocalSizeDiff,
DWORD uDescriptorSizeDiff, ZIP_INDEX_TYPE uIndex, ZIP_SIZE_TYPE uDataOffset)
@@ -1830,29 +2019,10 @@ struct CZipEncryptFileInfo }
};
-bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes)
+bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes)
{
- if (IsClosed())
- {
- ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
- return false;
- }
-
- if (m_storage.IsSegmented())
+ if (!CanModify())
{
- ZIPTRACE("%s(%i) : ZipArchive Library cannot encrypt existing files in a segmented archive.\n");
- return false;
- }
-
- if (m_storage.m_bReadOnly)
- {
- ZIPTRACE("%s(%i) : ZipArchive Library cannot encrypt files in a read-only archive.\n");
- return false;
- }
-
- if (m_iFileOpened)
- {
- ZIPTRACE("%s(%i) : ZipArchive Library cannot encrypt files if there is a file opened.\n");
return false;
}
@@ -1928,13 +2098,13 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) DWORD uOrigDescriptorSize = pHeader->GetDataDescriptorSize(&m_storage);
pHeader->m_uEncryptionMethod = (BYTE)m_iEncryptionMethod;
- pHeader->UpdateFlag(m_storage.IsSegmented() != 0);
+ pHeader->UpdateFlag(m_storage.IsSegmented());
// needed for GetLocalSize
- pHeader->PrepareFileName();
+ pHeader->PrepareStringBuffers();
DWORD uLocalDiff = pHeader->GetLocalSize(false) - uOrigSize;
DWORD uDescriptorDiff = pHeader->GetDataDescriptorSize(&m_storage) - uOrigDescriptorSize;
- uExtraData += uLocalDiff + uDescriptorDiff;
+ uExtraData += (ZIP_SIZE_TYPE)uLocalDiff + uDescriptorDiff;
infos.Add(CZipEncryptFileInfo(pHeader, uLocalDiff, uDescriptorDiff, idx, pHeader->m_uOffset + uOrigSize));
if (pCallback && !pCallback->RequestCallback())
{
@@ -2017,7 +2187,7 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) DWORD uExtraBefore = CZipCryptograph::GetEncryptedInfoSizeBeforeData(m_iEncryptionMethod);
DWORD uExtraAfter = CZipCryptograph::GetEncryptedInfoSizeAfterData(m_iEncryptionMethod);
// the total amount of extra data
- uExtraData += ((uExtraBefore + uExtraAfter) * infos.GetSize());
+ uExtraData += ((ZIP_SIZE_TYPE)uExtraBefore + uExtraAfter) * (DWORD)infos.GetSize();
ZIP_SIZE_TYPE uLastOffset = m_storage.GetLastDataOffset();
ZIP_INDEX_TYPE lastNormalIdx = ZIP_FILE_INDEX_UNSPECIFIED;
@@ -2042,7 +2212,7 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) pCallback->CallbackEnd();
lastNormalIdx = ZIP_FILE_INDEX_UNSPECIFIED;
}
- uExtraData -= (uExtraAfter + info.m_uDescriptorSizeDiff);
+ uExtraData -= ((ZIP_SIZE_TYPE)uExtraAfter + info.m_uDescriptorSizeDiff);
if (pCallback)
{
pCallback->Init();
@@ -2056,8 +2226,8 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) if (++idxIdx == uSize)
break;
- uExtraData -= (uExtraBefore + info.m_uLocalSizeDiff);
- // use original offsett
+ uExtraData -= ((ZIP_SIZE_TYPE)uExtraBefore + info.m_uLocalSizeDiff);
+ // use original offset
uLastOffset = info.m_pHeader->m_uOffset;
// now change the offset (not counting expanded local header - it changed the offset of data, not the offset of local header)
info.m_pHeader->m_uOffset += uExtraData;
@@ -2071,7 +2241,7 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) }
}
bAborted = false;
- ZIP_SIZE_TYPE uToEncrypt = 0;
+ ZIP_SIZE_TYPE uToEncrypt;
i = uSize;
// now encrypt the files (starting from the first one in the archive - this way the general direction of data copying is kept
CreateCryptograph(m_iEncryptionMethod);
@@ -2084,13 +2254,15 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) CZipEncryptFileInfo inf = infos[i];
CZipFileHeader* pHeader = inf.m_pHeader;
uToEncrypt = pHeader->m_uComprSize;
+ const CZipString& szFileName = pHeader->GetFileName();
if (pCallback)
{
- pCallback->Init(pHeader->GetFileName());
+ pCallback->Init(szFileName);
pCallback->SetTotal(uToEncrypt);
}
m_storage.Seek(pHeader->m_uOffset);
+ pHeader->AdjustLocalComprSize();
pHeader->WriteLocal(&m_storage);
// take the number of bytes to encode, before m_uComprSize is modified
m_pCryptograph->InitEncode(m_pszPassword, *pHeader, m_storage);
@@ -2117,7 +2289,7 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) bBreak = true;
m_pCryptograph->Encode(buf, uSizeRead);
- pFile->Seek(uPosition);
+ pFile->SafeSeek(uPosition);
pFile->Write(buf, uSizeRead);
uPosition += uSizeRead;
@@ -2127,7 +2299,7 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) break;
}
if (pMultiCallback)
- pMultiCallback->MultiActionsNext();
+ pMultiCallback->MultiActionsNext(szFileName);
}
while (!bBreak);
}
@@ -2180,19 +2352,13 @@ bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) }
-
-bool CZipArchive::SetCompressionMethod(WORD uCompressionMethod)
+bool CZipArchive::SetCompressionMethod(WORD uCompressionMethod)
{
if (m_iFileOpened == compress)
{
ZIPTRACE("%s(%i) : ZipArchive Library cannot change the compression method when there is a file opened for compression.\n");
return false;
}
- if (uCompressionMethod == CZipCompressor::methodStore)
- {
- ZIPTRACE("%s(%i) : Use the compression level CZipCompressor::levelStore when compressing files instead.\n");
- return false;
- }
if (!CZipCompressor::IsCompressionSupported(uCompressionMethod))
{
@@ -2204,14 +2370,14 @@ bool CZipArchive::SetCompressionMethod(WORD uCompressionMethod) return true;
}
-CZipString CZipArchive::GetPassword()const
+CZipString CZipArchive::GetPassword()const
{
CZipString temp;
ZipCompatibility::ConvertBufferToString(temp, m_pszPassword, CP_ACP);
return temp;
}
-bool CZipArchive::TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize)
+bool CZipArchive::TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize)
{
if (IsClosed())
{
@@ -2219,7 +2385,7 @@ bool CZipArchive::TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize) return false;
}
- if (m_storage.IsSegmented() == 1)
+ if (m_storage.IsNewSegmented())
{
ZIPTRACE("%s(%i) : ZipArchive Library cannot test a segmented archive in creation.\n");
return false;
@@ -2261,7 +2427,7 @@ bool CZipArchive::TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize) pCallback->SetTotal(pHeader->m_uUncomprSize);
if (!OpenFile(uIndex))
- return false;
+ return false;
CZipAutoBuffer buf(uBufSize);
DWORD iRead;
int iAborted = 0;
@@ -2308,7 +2474,7 @@ bool CZipArchive::TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize) }
// if any exception was thrown, then we are not successful
// catch all exceptions to thrown aborted exception only
-#ifdef ZIP_ARCHIVE_MFC
+#ifdef _ZIP_IMPL_MFC
catch(CException* e)
{
e->Delete();
@@ -2339,13 +2505,7 @@ bool CZipArchive::TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize) }
}
-void CZipArchive::SetFileHeaderAttr(CZipFileHeader& header, DWORD uAttr)const
-{
- header.SetSystemCompatibility(m_iArchiveSystCompatib);
- header.SetSystemAttr(uAttr);
-}
-
-void CZipArchive::EnableFindFast(bool bEnable)
+void CZipArchive::EnableFindFast(bool bEnable)
{
if (IsClosed())
{
@@ -2355,7 +2515,7 @@ void CZipArchive::EnableFindFast(bool bEnable) m_centralDir.EnableFindFast(bEnable, m_bCaseSensitive);
}
-bool CZipArchive::SetSystemCompatibility(int iSystemComp)
+bool CZipArchive::SetSystemCompatibility(int iSystemComp)
{
if (IsClosed())
{
@@ -2371,15 +2531,17 @@ bool CZipArchive::SetSystemCompatibility(int iSystemComp) if (!ZipCompatibility::IsPlatformSupported(iSystemComp))
return false;
+#ifdef _ZIP_UNICODE_CUSTOM
// change the name coding page, if it was not changed before
if (m_stringSettings.IsStandardNameCodePage(m_iArchiveSystCompatib))
m_stringSettings.SetDefaultNameCodePage(iSystemComp);
+#endif
m_iArchiveSystCompatib = iSystemComp;
return true;
}
-void CZipArchive::SetRootPath(LPCTSTR szPath)
+void CZipArchive::SetRootPath(LPCTSTR szPath)
{
if (IsClosed())
{
@@ -2402,7 +2564,7 @@ void CZipArchive::SetRootPath(LPCTSTR szPath) m_szRootPath.Empty();
}
-CZipString CZipArchive::TrimRootPath(CZipPathComponent &zpc)const
+CZipString CZipArchive::TrimRootPath(CZipPathComponent &zpc)const
{
if (m_szRootPath.IsEmpty())
return zpc.GetFileName();
@@ -2410,13 +2572,23 @@ CZipString CZipArchive::TrimRootPath(CZipPathComponent &zpc)const return RemovePathBeginning(m_szRootPath, szPath, m_pZipCompare) ? szPath : zpc.GetFileName();
}
-bool CZipArchive::RemovePathBeginning(LPCTSTR lpszBeginning, CZipString& szPath, ZIPSTRINGCOMPARE pCompareFunction)
+bool CZipArchive::RemovePathBeginning(LPCTSTR lpszBeginning, CZipString& szPath, ZIPSTRINGCOMPARE pCompareFunction)
{
CZipString szBeginning(lpszBeginning);
CZipPathComponent::RemoveSeparators(szBeginning);
+ CZipString szNormalizedPath(szPath);
+
+ // normalize paths to allow using slashes in paths under Windows
+#ifdef _ZIP_SYSTEM_WIN
+ // this is just for completness as it will always be a slash character under Windows
+ TCHAR cReversedSeparator = CZipPathComponent::m_cSeparator == _T('\\') ? _T('/') : _T('\\');
+ szBeginning.Replace(cReversedSeparator, CZipPathComponent::m_cSeparator);
+ szNormalizedPath.Replace(cReversedSeparator, CZipPathComponent::m_cSeparator);
+#endif
+
int iRootPathLength = szBeginning.GetLength();
- if (iRootPathLength && szPath.GetLength() >= iRootPathLength &&
- (szPath.Left(iRootPathLength).*pCompareFunction)(szBeginning) == 0)
+ if (iRootPathLength && szNormalizedPath.GetLength() >= iRootPathLength &&
+ (szNormalizedPath.Left(iRootPathLength).*pCompareFunction)(szBeginning) == 0)
{
// the beginning is the same
if (szPath.GetLength() == iRootPathLength)
@@ -2437,7 +2609,7 @@ bool CZipArchive::RemovePathBeginning(LPCTSTR lpszBeginning, CZipString& szPath return false;
}
-void CZipArchive::SetTempPath(LPCTSTR lpszPath, bool bForce)
+void CZipArchive::SetTempPath(LPCTSTR lpszPath, bool bForce)
{
m_szTempPath = lpszPath;
if (lpszPath && bForce)
@@ -2445,7 +2617,7 @@ void CZipArchive::SetTempPath(LPCTSTR lpszPath, bool bForce) CZipPathComponent::RemoveSeparators(m_szTempPath);
}
-CZipString CZipArchive::PredictFileNameInZip(LPCTSTR lpszFilePath,
+CZipString CZipArchive::PredictFileNameInZip(LPCTSTR lpszFilePath,
bool bFullPath, int iWhat)const
{
CZipString sz = lpszFilePath;
@@ -2473,7 +2645,7 @@ CZipString CZipArchive::PredictFileNameInZip(LPCTSTR lpszFilePath, if (bFullPath)
{
- if (m_bRemoveDriveLetter)
+ if (m_bSafePaths)
sz = zpc.GetNoDrive();
}
else
@@ -2484,97 +2656,142 @@ CZipString CZipArchive::PredictFileNameInZip(LPCTSTR lpszFilePath, return sz;
}
-CZipString CZipArchive::PredictExtractedFileName(LPCTSTR lpszFileNameInZip, LPCTSTR lpszPath, bool bFullPath, LPCTSTR lpszNewName)const
+CZipString CZipArchive::PredictExtractedFileName(LPCTSTR lpszFileNameInZip, LPCTSTR lpszPath, bool bFullPath, LPCTSTR lpszNewName)const
{
CZipString szFile = lpszPath;
- CZipString sz = lpszNewName ? lpszNewName : lpszFileNameInZip;
+
+ CZipString sz;
+ if (lpszNewName)
+ sz = lpszNewName;
+ else
+ {
+ sz = lpszFileNameInZip;
+ if (m_bSafePaths)
+ {
+ CZipString szDirTraversal = _T("..");
+ szDirTraversal += CZipPathComponent::m_cSeparator;
+ int current = 0;
+ while(true)
+ {
+ int start = sz.Find(szDirTraversal, current);
+ if (start > -1)
+ {
+ if (start == 0)
+ {
+ sz = sz.Mid(3);
+ }
+ else
+ {
+ sz = sz.Mid(0, start) + sz.Mid(start + 3);
+ }
+ }
+ else
+ break;
+ current = start;
+ }
+ CZipPathComponent::RemoveSeparatorsLeft(sz);
+ }
+ }
if (sz.IsEmpty())
return szFile;
if (!szFile.IsEmpty())
CZipPathComponent::AppendSeparator(szFile);
-
// remove for CZipPathComponent treating last name as a file even if dir
CZipPathComponent::RemoveSeparators(sz);
CZipPathComponent zpc(sz);
- szFile += bFullPath ? (m_bRemoveDriveLetter ? zpc.GetNoDrive() : sz)
+ szFile += bFullPath ? (m_bSafePaths ? zpc.GetNoDrive() : sz)
: TrimRootPath(zpc);
return szFile;
}
-ZIP_SIZE_TYPE CZipArchive::PredictMaximumFileSizeInArchive(LPCTSTR lpszFilePath, bool bFullPath) const
+ZIP_SIZE_TYPE CZipArchive::PredictMaximumFileSizeInArchive(LPCTSTR lpszFilePath, bool bFullPath)
{
DWORD attr;
if (!ZipPlatform::GetFileAttr(lpszFilePath, attr))
- return 0;
+ ThrowError(CZipException::fileError, lpszFilePath);
CZipFileHeader fh;
- SetFileHeaderAttr(fh, attr);
+
+ fh.SetSystemAttr(attr);
if (!fh.IsDirectory())
- if (!ZipPlatform::GetFileSize(lpszFilePath, fh.m_uUncomprSize))
- return 0;
- fh.SetFileName(PredictFileNameInZip(lpszFilePath, bFullPath, fh.IsDirectory() ? prDir : prFile));
+ if (!ZipPlatform::GetFileSize(lpszFilePath, fh.m_uComprSize))
+ return 0;
+ fh.SetFileName(PredictFileNameInZip(lpszFilePath, bFullPath, fh.IsDirectory() ? prDir : prFile));
return PredictMaximumFileSizeInArchive(fh);
}
-ZIP_SIZE_TYPE CZipArchive::PredictMaximumFileSizeInArchive(CZipFileHeader& fh) const
-{
- fh.m_stringSettings = m_stringSettings;
+ZIP_SIZE_TYPE CZipArchive::PredictMaximumFileSizeInArchive(CZipFileHeader& fh)
+{
+ fh.m_pCentralDir = &m_centralDir;
+ fh.SetSystemCompatibility(GetSystemCompatibility());
+ fh.UpdateStringsFlags(false);
fh.m_uEncryptionMethod = WillEncryptNextFile() ? (BYTE)m_iEncryptionMethod : (BYTE)CZipCryptograph::encNone;
fh.m_uMethod = CZipCompressor::methodStore;
- fh.PrepareData(CZipCompressor::levelStore, m_storage.IsSegmented() != 0);
+ fh.PrepareData(CZipCompressor::levelStore, m_storage.IsSegmented());
DWORD uLocalSize = fh.GetLocalSize(true);
- return fh.GetSize() + uLocalSize + fh.GetDataSize(true, false) + fh.GetDataDescriptorSize(&m_storage);
+ ZIP_SIZE_TYPE ret = (ZIP_SIZE_TYPE)fh.GetSize() + uLocalSize + fh.GetDataSize(false) + fh.GetDataDescriptorSize(&m_storage);
+ fh.m_pCentralDir = NULL;
+ return ret;
}
-void CZipArchive::SetAutoFlush(bool bAutoFlush)
+bool CZipArchive::SetAutoFinalize(bool bAutoFinalize)
{
- if (IsClosed())
+ if (!CanModify(false, false))
{
- ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n");
- return;
+ return false;
}
- if (m_storage.IsSegmented() != 0)
+ if (m_bAutoFinalize != bAutoFinalize)
{
- ZIPTRACE("%s(%i) : Cannot set auto-flush for a segmented archive.\n");
- return;
+ if (bAutoFinalize)
+ {
+ if (IsModified())
+ {
+ ZIPTRACE("%s(%i) : Cannot enable auto finalize when there are pending changes to commit.\n");
+ return false;
+ }
+ }
+ m_bAutoFinalize = bAutoFinalize;
}
- m_bAutoFlush = bAutoFlush;
+ return true;
}
-void CZipArchive::Flush()
+bool CZipArchive::Finalize(bool bOnlyIfAuto)
{
- if (IsClosed())
+ if (bOnlyIfAuto && !m_bAutoFinalize)
{
- ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n");
- return;
+ return false;
}
- if (m_storage.IsSegmented() < 0)
+ if (!CanModify(true, false))
{
- ZIPTRACE("%s(%i) : Cannot flush an existing segmented archive.\n");
- return;
+ return false;
+ }
+
+ if (IsModified())
+ {
+ ZIPTRACE("%s(%i) : Cannot finalize when there are pending changes to commit.\n");
+ return false;
}
WriteCentralDirectory();
m_storage.FlushFile();
- if (m_storage.IsSegmented() > 0) // try to finalize a segmented archive without closing it
+ if (m_storage.IsNewSegmented()) // try to finalize a segmented archive without closing it
m_storage.FinalizeSegm();
+ return true;
}
-
-void CZipArchive::GetCentralDirInfo(CZipCentralDir::CInfo& info)const
+void CZipArchive::GetCentralDirInfo(CZipCentralDir::CInfo& info)const
{
if (IsClosed())
{
ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n");
- return;
-
+ return;
}
m_centralDir.GetInfo(info);
- if (GetSegmMode() > 0)
+ if (m_storage.IsNewSegmented() && !m_storage.IsBinarySplit())
info.m_uLastVolume = m_storage.GetCurrentVolume();
}
-void CZipArchive::FindMatches(LPCTSTR lpszPattern, CZipIndexesArray &ar, bool bFullPath)
+void CZipArchive::FindMatches(LPCTSTR lpszPattern, CZipIndexesArray &ar, bool bFullPath)
{
if (IsClosed())
{
@@ -2582,7 +2799,7 @@ void CZipArchive::FindMatches(LPCTSTR lpszPattern, CZipIndexesArray &ar, bool b return;
}
- // ar.RemoveAll(); don't do this
+ // ar.RemoveAll(); don't remove
ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)GetCount();
CWildcard wc(lpszPattern, m_bCaseSensitive);
for (ZIP_INDEX_TYPE i = 0; i < uCount; i++)
@@ -2599,7 +2816,7 @@ void CZipArchive::FindMatches(LPCTSTR lpszPattern, CZipIndexesArray &ar, bool b }
}
-ZIP_INDEX_TYPE CZipArchive::WillBeDuplicated(LPCTSTR lpszFilePath, bool bFullPath, bool bFileNameOnly , int iWhat)
+ZIP_INDEX_TYPE CZipArchive::WillBeDuplicated(LPCTSTR lpszFilePath, bool bFullPath, bool bFileNameOnly , int iWhat)
{
CZipString szFile;
if (bFileNameOnly)
@@ -2612,8 +2829,7 @@ ZIP_INDEX_TYPE CZipArchive::WillBeDuplicated(LPCTSTR lpszFilePath, bool bFullPa return FindFile(szFile, ffDefault, bFileNameOnly);
}
-
-bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewFileName, ZIP_INDEX_TYPE uReplaceIndex, bool bKeepSystComp, CZipActionCallback* pCallback)
+bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewFileName, ZIP_INDEX_TYPE uReplaceIndex, bool bKeepSystComp, CZipActionCallback* pCallback)
{
if (this == &zip)
{
@@ -2633,7 +2849,7 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT return false;
}
- if (m_storage.IsSegmented() == -1)
+ if (m_storage.IsExistingSegmented())
{
ZIPTRACE("%s(%i) : ZipArchive Library cannot add files to an existing segmented archive.\n");
return false;
@@ -2641,7 +2857,7 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT ASSERT(m_pBuffer.GetSize() > 0);
- bool bSegm = m_storage.IsSegmented() == 1;
+ bool bSegm = m_storage.IsSegmented();
if (!zip.m_centralDir.IsValidIndex(uIndex))
return false;
@@ -2652,24 +2868,42 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT // we need a copy - we are going to modify this
if (!zip.GetFileInfo(originalHeader, uIndex))
return false;
- if (zip.m_storage.IsSegmented() != 0 && originalHeader.m_uLocalComprSize == 0)
- // we must compensate for adding the encrypted info size to m_uLocalComprSize at the beginning of CZipFileHeader::WriteLocal()
- originalHeader.m_uLocalComprSize = originalHeader.m_uComprSize - originalHeader.GetEncryptedInfoSize();
- bool bConvertSystem = !bKeepSystComp && originalHeader.GetSystemCompatibility() != m_iArchiveSystCompatib;
+
+ if (originalHeader.IsDataDescriptor())
+ {
+ if (originalHeader.m_uLocalComprSize == 0)
+ {
+ originalHeader.m_uLocalComprSize = originalHeader.m_uComprSize;
+ }
+
+ if (originalHeader.m_uLocalUncomprSize == 0)
+ {
+ originalHeader.m_uLocalUncomprSize = originalHeader.m_uUncomprSize;
+ }
+ }
+
+ DWORD uSize = originalHeader.GetEncryptedInfoSize();
+ // just in case checking
+ if (uSize > 0 && originalHeader.m_uLocalComprSize >= uSize)
+ {
+ // to compensate increasing in PrepareData
+ originalHeader.m_uLocalComprSize -= uSize;
+ }
+
CZipString szFileName;
if (lpszNewFileName != NULL)
{
szFileName = lpszNewFileName;
+ // to avoid calling on name change event
+ originalHeader.m_pCentralDir = NULL;
originalHeader.SetFileName(lpszNewFileName);
}
else
szFileName = originalHeader.GetFileName(); // empty
- if (bConvertSystem)
+ if (bKeepSystComp)
{
- DWORD uAttr = originalHeader.GetSystemAttr();
- originalHeader.SetSystemCompatibility(m_iArchiveSystCompatib);
- originalHeader.SetSystemAttr(uAttr);
+ originalHeader.SetSystemCompatibility(m_iArchiveSystCompatib, true);
}
if (!UpdateReplaceIndex(uReplaceIndex))
@@ -2679,10 +2913,15 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT if (bReplace && bSegm)
return false;
- int iCallbackType = 0;
+ int iCallbackType = CZipActionCallback::cbNothing;
if (pCallback)
iCallbackType = pCallback->m_iType;
+ // if the original header had no data descriptor it used an original CRC32 during writing CRC encryption header
+ // we need to skip the data descriptor as well, otherwise during decrypting, the decryptor will verify against
+ // a pseudo-crc (see InitDecode in CZipCrc32Cryptograph);
+ bool clearDataDescriptor = !originalHeader.IsDataDescriptor() && originalHeader.GetEncryptionMethod() == CZipCryptograph::encStandard;
+
if (!originalHeader.IsEncrypted() && WillEncryptNextFile())
{
originalHeader.m_uEncryptionMethod = (BYTE)m_iEncryptionMethod;
@@ -2694,10 +2933,12 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT // if the same callback is applied to cbMoveData, then the previous information about the type will be lost
// we restore it later
CZipFileHeader* pHeader = m_centralDir.AddNewFile(originalHeader, uReplaceIndex, originalHeader.GetCompressionLevel(), true);
- pHeader->m_stringSettings.m_uCommentCodePage = originalHeader.m_stringSettings.m_uCommentCodePage;
-
+ if (clearDataDescriptor && pHeader->IsDataDescriptor()) // the second condition is just in case
+ {
+ pHeader->m_uFlag &= ~8;
+ }
// prepare this here: it will be used for GetLocalSize and WriteLocal
- pHeader->PrepareFileName();
+ pHeader->PrepareStringBuffers();
ZIP_SIZE_TYPE uTotalToMove = pHeader->m_uComprSize;
@@ -2706,7 +2947,7 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT ZIP_SIZE_TYPE uDataSize;
if (m_pCryptograph)
// the file will be encrypted and have not yet increased pHeader->m_uComprSize (in m_pCryptograph->InitEncode)
- uDataSize = pHeader->GetDataSize(false, false);
+ uDataSize = pHeader->GetDataSize(false);
else
uDataSize = uTotalToMove;
MakeSpaceForReplace(uReplaceIndex, uDataSize + pHeader->GetLocalSize(false) + pHeader->GetDataDescriptorSize(&m_storage), szFileName);
@@ -2762,7 +3003,13 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT iAborted = CZipException::abortedAction;
}
else
+ {
+ if (m_pCryptograph)
+ m_pCryptograph->FinishEncode(*pHeader, m_storage);
+ // it will be written only if needed
+ pHeader->WriteDataDescriptor(&m_storage);
iAborted = CZipException::abortedSafely;
+ }
break;
}
@@ -2772,8 +3019,18 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT if (pCallback)
{
if (!iAborted && !pCallback->RequestLastCallback())
- iAborted = CZipException::abortedSafely;
-
+ {
+ if (uTotalToMove > 0)
+ iAborted = CZipException::abortedAction;
+ else
+ {
+ if (m_pCryptograph)
+ m_pCryptograph->FinishEncode(*pHeader, m_storage);
+ // it will be written only if needed
+ pHeader->WriteDataDescriptor(&m_storage);
+ iAborted = CZipException::abortedSafely;
+ }
+ }
if (iAborted)
{
// when no exception, CallbackEnd() called later
@@ -2784,7 +3041,6 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT }
m_centralDir.m_pOpenedFile = NULL;
- // copying from a not segmented to a segmented archive so add the data descriptor
// we want write the additional data only if everything is all right, but we don't want to flush the storage before
// (and we want to flush the storage before throwing an exception, if something is wrong)
@@ -2807,7 +3063,7 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCT return true;
}
-bool CZipArchive::GetFromArchive( CZipArchive& zip, CZipIndexesArray &aIndexes, bool bKeepSystComp)
+bool CZipArchive::GetFromArchive( CZipArchive& zip, CZipIndexesArray &aIndexes, bool bKeepSystComp, bool bReplaceMode)
{
aIndexes.Sort(true);
ZIP_INDEX_TYPE uFiles = (ZIP_INDEX_TYPE)aIndexes.GetSize();
@@ -2817,7 +3073,14 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, CZipIndexesArray &aIndexes, for (ZIP_INDEX_TYPE i = 0; i < uFiles; i++)
{
ZIP_INDEX_TYPE uFileIndex = aIndexes[(ZIP_ARRAY_SIZE_TYPE)i];
- if (!GetFromArchive(zip, uFileIndex, NULL, ZIP_FILE_INDEX_UNSPECIFIED, bKeepSystComp, GetCallback(CZipActionCallback::cbGet)))
+ ZIP_INDEX_TYPE uReplaceIndex = ZIP_FILE_INDEX_UNSPECIFIED;
+ if (bReplaceMode)
+ {
+ if (!zip.m_centralDir.IsValidIndex(uFileIndex))
+ return false;
+ uReplaceIndex = FindFile(zip[uFileIndex]->GetFileName());
+ }
+ if (!GetFromArchive(zip, uFileIndex, NULL, uReplaceIndex, bKeepSystComp, GetCallback(CZipActionCallback::cbGet)))
{
ReleaseBuffer();
return false;
@@ -2830,122 +3093,195 @@ bool CZipArchive::GetFromArchive( CZipArchive& zip, CZipIndexesArray &aIndexes, throw;
}
ReleaseBuffer();
- if (m_bAutoFlush)
- Flush();
+ Finalize(true);
return true;
}
-bool CZipArchive::RenameFile(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewName)
-{
- if (IsClosed())
- {
- ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
- return false;
- }
-
- if (m_storage.IsSegmented())
+
+struct CZipChangeInfo
+{
+ CZipChangeInfo()
{
- ZIPTRACE("%s(%i) : ZipArchive Library cannot rename files in a segmented archive.\n");
- return false;
+ m_index = 0;
+ m_startOffset = 0;
+ m_endOffset = 0;
+ m_relativeOffset = 0;
}
-
- if (m_iFileOpened)
+
+ CZipChangeInfo(ZIP_INDEX_TYPE index,
+ ZIP_SIZE_TYPE startOffset,
+ ZIP_FILE_SIZE relativeOffset)
{
- ZIPTRACE("%s(%i) : ZipArchive Library cannot rename a file if there is a file opened.\n");
- return false;
+ m_index = index;
+ m_startOffset = startOffset;
+ m_endOffset = 0;
+ m_relativeOffset = relativeOffset;
}
- CZipFileHeader* pHeader = (*this)[uIndex];
- if (pHeader == NULL)
+
+ ZIP_INDEX_TYPE m_index;
+ ZIP_SIZE_TYPE m_startOffset;
+ ZIP_SIZE_TYPE m_endOffset;
+ ZIP_FILE_SIZE m_relativeOffset;
+};
+
+bool CZipArchive::CommitChanges()
+{
+ if (!CanModify())
return false;
- CZipString szNewName(lpszNewName);
- if (pHeader->IsDirectory())
- CZipPathComponent::AppendSeparator(szNewName);
- else
- CZipPathComponent::RemoveSeparators(szNewName);
- CZipString szPreviousFileName = pHeader->GetFileName();
- if (szPreviousFileName.Collate(szNewName) == 0)
+ ZIP_INDEX_TYPE uCount = GetCount();
+ if (uCount == 0)
return true;
+
+ CZipArray<CZipChangeInfo> aInfo;
+ ZIP_FILE_SIZE relativeOffset = 0;
+ for (ZIP_INDEX_TYPE i = 0; i < uCount; i++)
+ {
+ CZipFileHeader* pHeader = GetFileInfo(i);
+ if (!pHeader->IsModified())
+ continue;
+
+ ReadLocalHeaderInternal(i);
+ // used in GetLocalSize and WriteLocal
+ pHeader->PrepareStringBuffers();
+ DWORD localSize = pHeader->GetLocalSize(true);
+
+ ASSERT(pHeader->m_fileName.m_buffer.IsAllocated());
+ DWORD newLocalSize = pHeader->GetLocalSize(false);
+ int offset = newLocalSize - localSize;
+ relativeOffset += offset;
+
+ aInfo.Add(CZipChangeInfo(i, pHeader->m_uOffset + localSize, relativeOffset));
+ }
- // don't copy the comment code page, it already could have been set using it's own code page (set CD CP, change comment, change CD CP)
- pHeader->m_stringSettings.m_bStoreNameInExtraData = m_stringSettings.m_bStoreNameInExtraData;
- pHeader->m_stringSettings.m_uNameCodePage = m_stringSettings.m_uNameCodePage;
- pHeader->SetFileName(szNewName);
+
+ ZIP_ARRAY_SIZE_TYPE totalInfos = aInfo.GetSize();
+ if (totalInfos == 0)
+ return true;
m_centralDir.RemoveFromDisk(); // does m_storage.Flush();
- // read local data - it may differ from central data
- char localInfo[4];
- m_storage.Seek(pHeader->m_uOffset + 26);
- m_storage.m_pFile->Read(localInfo, 4); // read at once
- WORD uFileNameLen, uExtraFieldSize;
- CBytesWriter::ReadBytes(uFileNameLen, localInfo);
- // skip endian issues - the variable will not be used, but written back as it is
- memcpy(&uExtraFieldSize, localInfo + 2, 2);
-
- // filename buffer already cleared (GetFileName), the conversion will take place
- pHeader->PrepareFileName();
- ASSERT(pHeader->m_pszFileNameBuffer.IsAllocated());
- WORD uNewFileNameLen = (WORD)pHeader->m_pszFileNameBuffer.GetSize();
- int iDelta = uNewFileNameLen - uFileNameLen;
- int iOffset = 0;
- CZipAutoBuffer buf, *pBuf;
-
- if (iDelta != 0)
- {
- // we need to make more or less space
- InitBuffer();
- ZIP_SIZE_TYPE uStartOffset = pHeader->m_uOffset + 30 + uFileNameLen;
- ZIP_SIZE_TYPE uFileLen = (ZIP_SIZE_TYPE)m_storage.m_pFile->GetLength();
- ZIP_SIZE_TYPE uEndOffset = uFileLen - m_storage.m_uBytesBeforeZip;
- CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbRename);
- if (pCallback)
+
+ ZIP_SIZE_TYPE uFileLen = (ZIP_SIZE_TYPE)m_storage.m_pFile->GetLength();
+ ZIP_ARRAY_SIZE_TYPE lastInfoIndex = totalInfos - 1;
+ ZIP_SIZE_TYPE uTotal = 0;
+ ZIP_ARRAY_SIZE_TYPE idx = 0;
+ // calculate end offsets and total data to process
+ for(;;)
+ {
+ bool last;
+ ZIP_SIZE_TYPE uEndOffset;
+ if (idx == lastInfoIndex)
+ {
+ uEndOffset = uFileLen - m_storage.m_uBytesBeforeZip;
+ last = true;
+ }
+ else
{
- // do it right and sent the notification
- pCallback->Init(szPreviousFileName, GetArchivePath());
- pCallback->SetTotal(uEndOffset - uStartOffset);
+ uEndOffset = GetFileInfo(aInfo.GetAt(idx + 1).m_index)->m_uOffset;
+ last = false;
}
- bool bForward = iDelta > 0;
- if (bForward)
- m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + iDelta)); // ensure the seek is correct
+ CZipChangeInfo& info = aInfo[idx];
+ info.m_endOffset = uEndOffset;
+ uTotal += uEndOffset - info.m_startOffset;
+ if (last)
+ break;
+ idx++;
+ }
+
+ ZIP_ARRAY_SIZE_TYPE currentIndex = lastInfoIndex;
+ // the total offset is the last offset in the array (offsets are accumulated)
+ ZIP_FILE_SIZE totalOffset = aInfo.GetAt(currentIndex).m_relativeOffset;
+ if (totalOffset > 0)
+ {
+ m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + totalOffset)); // ensure the seek is correct
+ }
+
+ InitBuffer();
+ CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbModify);
+ if (pCallback)
+ {
+ // do it right and sent the notification
+ pCallback->Init(NULL, GetArchivePath());
+ pCallback->SetTotal(uTotal);
+ }
+ for(;;)
+ {
+ CZipChangeInfo& info = aInfo[currentIndex];
+ bool last;
+
+ if (info.m_relativeOffset > 0)
+ {
+ last = currentIndex == 0;
+ MovePackedFiles(info.m_startOffset, info.m_endOffset, (ZIP_SIZE_TYPE)info.m_relativeOffset, pCallback, true, last);
+ }
+ else
+ {
+ ZIP_ARRAY_SIZE_TYPE limitIndex = currentIndex;
+ while (currentIndex > 0 && aInfo.GetAt(currentIndex - 1).m_relativeOffset <= 0)
+ {
+ currentIndex--;
+ }
- MovePackedFiles(uStartOffset, uEndOffset, abs(iDelta), pCallback, bForward);
- if (pCallback)
- pCallback->CallbackEnd();
+ last = currentIndex == 0;
+
+ for(ZIP_ARRAY_SIZE_TYPE uSubIndex = currentIndex; ; uSubIndex++)
+ {
+ CZipChangeInfo& newInfo = aInfo[uSubIndex];
+ bool subLast = uSubIndex == limitIndex;
+ MovePackedFiles(newInfo.m_startOffset, newInfo.m_endOffset, (ZIP_SIZE_TYPE)(-newInfo.m_relativeOffset), pCallback, false, last && subLast);
+ if (subLast)
+ break;
+ }
+ }
- if (!bForward)
- m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + iDelta)); // delta < 0; shrink the file
+ if (last)
+ break;
- ReleaseBuffer();
+ currentIndex--;
+ }
+ ReleaseBuffer();
- ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)GetCount();
- for (ZIP_INDEX_TYPE i = (ZIP_INDEX_TYPE)(uIndex + 1); i < uSize; i++)
- m_centralDir[i]->m_uOffset += iDelta;
- buf.Allocate(4 + uNewFileNameLen);
- CBytesWriter::WriteBytes(buf, uNewFileNameLen);
- // the variable was not used - we write it back as it was (no endian issues)
- // to write everything at once
- memcpy((char*)buf + 2, &uExtraFieldSize, 2);
- memcpy((char*)buf + 4, pHeader->m_pszFileNameBuffer, uNewFileNameLen);
- pBuf = &buf;
- iOffset = -4;
+ if (totalOffset < 0)
+ {
+ m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + totalOffset)); // totalOffset < 0; shrink the file
+ }
+
+ for (idx = 0; ; idx++)
+ {
+ bool last = idx == lastInfoIndex;
+ // update offsets of the files that lie in between (will be written to central headers only)
+ CZipChangeInfo& info = aInfo[idx];
+ CZipFileHeader* pHeader = GetFileInfo(info.m_index);
+ ZIP_INDEX_TYPE endIndex = last ? GetCount() : aInfo.GetAt(idx + 1).m_index;
+#ifdef _ZIP_STRICT_U16
+ if (info.m_index < endIndex) // the index type is unsigned
+#endif
+ for (ZIP_INDEX_TYPE uSubIndex = (ZIP_INDEX_TYPE)(info.m_index + 1); uSubIndex < endIndex; uSubIndex ++)
+ {
+ GetFileInfo(uSubIndex)->m_uOffset += (ZIP_SIZE_TYPE)info.m_relativeOffset;
+ }
+ relativeOffset = idx == 0 ? 0 : aInfo.GetAt(idx - 1).m_relativeOffset;
+ m_storage.Seek(pHeader->m_uOffset + relativeOffset);
+ pHeader->WriteLocal(&m_storage); // will update offset and local filename size
+ pHeader->SetModified(false);
+ m_storage.Flush();
+ if (last)
+ break;
}
- else
- pBuf = &pHeader->m_pszFileNameBuffer;
-
- m_storage.Seek(pHeader->m_uOffset + 30 + iOffset);
- m_storage.m_pFile->Write(*pBuf, pBuf->GetSize());
- m_centralDir.RebuildFindFastArray();
- if (m_bAutoFlush)
- Flush();
+ Finalize(true);
+
+ if (pCallback)
+ pCallback->CallbackEnd();
+
return true;
}
-bool CZipArchive::UpdateReplaceIndex(ZIP_INDEX_TYPE& uReplaceIndex)
+bool CZipArchive::UpdateReplaceIndex(ZIP_INDEX_TYPE& uReplaceIndex)
{
if (uReplaceIndex == ZIP_FILE_INDEX_UNSPECIFIED)
return true;
- if (GetSegmMode() != 0)
+ if (m_storage.IsSegmented())
{
ZIPTRACE("%s(%i) : ZipArchive Library cannot replace files in a segmented archive.\n");
return false;
@@ -2964,7 +3300,7 @@ bool CZipArchive::UpdateReplaceIndex(ZIP_INDEX_TYPE& uReplaceIndex) return true;
}
-void CZipArchive::MakeSpaceForReplace(ZIP_INDEX_TYPE uReplaceIndex, ZIP_SIZE_TYPE uTotal, LPCTSTR lpszFileName)
+void CZipArchive::MakeSpaceForReplace(ZIP_INDEX_TYPE uReplaceIndex, ZIP_SIZE_TYPE uTotal, LPCTSTR lpszFileName)
{
ASSERT(uReplaceIndex < GetCount() - 1);
// we can't use the offset from the central directory here, because the header is already replaced
@@ -3022,53 +3358,55 @@ void CZipArchive::MakeSpaceForReplace(ZIP_INDEX_TYPE uReplaceIndex, ZIP_SIZE_TY pCallback->CallbackEnd();
}
-void CZipArchive::MovePackedFiles(ZIP_SIZE_TYPE uStartOffset, ZIP_SIZE_TYPE uEndOffset, ZIP_SIZE_TYPE uMoveBy,
+void CZipArchive::MovePackedFiles(ZIP_SIZE_TYPE uStartOffset, ZIP_SIZE_TYPE uEndOffset, ZIP_SIZE_TYPE uMoveBy,
CZipActionCallback* pCallback, bool bForward, bool bLastCall)
{
ASSERT(m_pBuffer.GetSize() > 0);
- ZIP_SIZE_TYPE uTotalToMove = uEndOffset - uStartOffset;
- ZIP_SIZE_TYPE uPack = uTotalToMove > m_pBuffer.GetSize() ? m_pBuffer.GetSize() : uTotalToMove;
- char* buf = (char*)m_pBuffer;
-
-
- UINT uSizeRead;
- bool bBreak = false;
bool bAborted = false;
- do
+ if (uMoveBy > 0)
{
- if (uEndOffset - uStartOffset < uPack)
+ ZIP_SIZE_TYPE uTotalToMove = uEndOffset - uStartOffset;
+ ZIP_SIZE_TYPE uPack = uTotalToMove > m_pBuffer.GetSize() ? m_pBuffer.GetSize() : uTotalToMove;
+ char* buf = (char*)m_pBuffer;
+
+ UINT uSizeRead;
+ bool bBreak = false;
+ do
{
- uPack = uEndOffset - uStartOffset;
- if (!uPack)
+ if (uEndOffset - uStartOffset < uPack)
+ {
+ uPack = uEndOffset - uStartOffset;
+ if (!uPack)
+ break;
+ bBreak = true;
+
+ }
+ ZIP_SIZE_TYPE uPosition = bForward ? uEndOffset - uPack : uStartOffset;
+
+ m_storage.Seek(uPosition);
+ uSizeRead = (UINT)m_storage.m_pFile->Read(buf, (UINT)uPack);
+ if (!uSizeRead)
break;
- bBreak = true;
+ if (bForward)
+ uPosition += uMoveBy;
+ else
+ uPosition -= uMoveBy;
+ m_storage.Seek(uPosition);
+ m_storage.m_pFile->Write(buf, uSizeRead);
+ if (bForward)
+ uEndOffset -= uSizeRead;
+ else
+ uStartOffset += uSizeRead;
+ if (pCallback && !pCallback->RequestCallback(uSizeRead))
+ {
+ bAborted = true;
+ break;
+ }
}
- ZIP_SIZE_TYPE uPosition = bForward ? uEndOffset - uPack : uStartOffset;
-
- m_storage.Seek(uPosition);
- uSizeRead = m_storage.m_pFile->Read(buf, (UINT)uPack);
- if (!uSizeRead)
- break;
-
- if (bForward)
- uPosition += uMoveBy;
- else
- uPosition -= uMoveBy;
- m_storage.Seek(uPosition);
- m_storage.m_pFile->Write(buf, uSizeRead);
- if (bForward)
- uEndOffset -= uSizeRead;
- else
- uStartOffset += uSizeRead;
- if (pCallback && !pCallback->RequestCallback(uSizeRead))
- {
- bAborted = true;
- break;
- }
+ while (!bBreak);
}
- while (!bBreak);
if (pCallback)
{
@@ -3078,19 +3416,18 @@ void CZipArchive::MovePackedFiles(ZIP_SIZE_TYPE uStartOffset, ZIP_SIZE_TYPE uEn //pCallback->CallbackEnd();
if (bAborted)
{
- // call here before throwing the the aborted exception
+ // call here before throwing the aborted exception
pCallback->CallbackEnd();
ThrowError(CZipException::abortedAction);
}
}
- if (uEndOffset != uStartOffset)
+ if (uMoveBy > 0 && uEndOffset != uStartOffset)
ThrowError(CZipException::internalError);
}
-
-bool CZipArchive::RemoveCentralDirectoryFromArchive()
+bool CZipArchive::RemoveCentralDirectoryFromArchive()
{
if (IsClosed())
{
@@ -3107,7 +3444,7 @@ bool CZipArchive::RemoveCentralDirectoryFromArchive() return true;
}
-bool CZipArchive::OverwriteLocalHeader(ZIP_INDEX_TYPE uIndex)
+bool CZipArchive::OverwriteLocalHeader(ZIP_INDEX_TYPE uIndex)
{
if (IsClosed())
{
@@ -3122,12 +3459,14 @@ bool CZipArchive::OverwriteLocalHeader(ZIP_INDEX_TYPE uIndex) }
CZipFileHeader* pHeader = GetFileInfo(uIndex);
- m_storage.Seek(pHeader->m_uOffset);
+ if (!pHeader)
+ return false;
+ m_storage.Seek(pHeader->m_uOffset);
pHeader->WriteLocal(&m_storage);
return true;
}
-bool CZipArchive::ReadLocalHeader(ZIP_INDEX_TYPE uIndex)
+bool CZipArchive::ReadLocalHeader(ZIP_INDEX_TYPE uIndex)
{
if (IsClosed())
{
@@ -3143,10 +3482,35 @@ bool CZipArchive::ReadLocalHeader(ZIP_INDEX_TYPE uIndex) return true;
}
-void CZipArchive::SetSegmCallback(CZipSegmCallback* pCallback, int callbackType)
+void CZipArchive::SetSegmCallback(CZipSegmCallback* pCallback, int callbackType)
{
- if ((callbackType & scSpan) != 0)
+ CBitFlag flag = callbackType;
+ if (flag.IsSetAny(scSpan))
m_storage.m_pSpanChangeVolumeFunc = pCallback;
- if ((callbackType & scSplit) != 0)
+ if (flag.IsSetAny(scSplit))
m_storage.m_pSplitChangeVolumeFunc = pCallback;
}
+
+
+bool CZipArchive::ResetCurrentVolume()
+{
+ if (IsClosed())
+ {
+ ZIPTRACE("%s(%i) : ZipArchive is closed.\n");
+ return false;
+ }
+
+ // the second condition is just in case
+ if (!m_storage.IsExistingSegmented() || m_iFileOpened == compress)
+ {
+ ZIPTRACE("%s(%i) : ZipArchive is not an existing segmented archive.\n");
+ return false;
+ }
+
+ if (m_iFileOpened)
+ {
+ CloseFile(NULL, true);
+ }
+ m_storage.m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
+ return true;
+}
|
