summaryrefslogtreecommitdiff
path: root/zip/ZipArchive/ZipCentralDir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zip/ZipArchive/ZipCentralDir.cpp')
-rw-r--r--zip/ZipArchive/ZipCentralDir.cpp411
1 files changed, 283 insertions, 128 deletions
diff --git a/zip/ZipArchive/ZipCentralDir.cpp b/zip/ZipArchive/ZipCentralDir.cpp
index 42ad63a..93969bf 100644
--- a/zip/ZipArchive/ZipCentralDir.cpp
+++ b/zip/ZipArchive/ZipCentralDir.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,7 +9,7 @@
//
// For the licensing details refer to the License.txt file.
//
-// Web Site: http://www.artpol-software.com
+// Web Site: https://www.artpol-software.com
////////////////////////////////////////////////////////////////////////////////
@@ -24,6 +24,8 @@
#define CENTRAL_DIR_END_SIZE 22
+// needed also for checking when Zip64 is disabled
+#define CENTRAL_DIR_END64_LOCATOR_SIZE 20
using namespace ZipArchiveLib;
@@ -32,36 +34,50 @@ char CZipCentralDir::m_gszSignature64Locator[] = {0x50, 0x4b, 0x06, 0x07};
+#pragma warning(suppress: 26495)
CZipCentralDir::CZipCentralDir()
{
m_pInfo = NULL;
m_pHeaders = NULL;
- m_pFindArray = NULL;
- m_pStorage = NULL;
+ m_pFindArray = NULL;
m_pOpenedFile = NULL;
- m_iIgnoredChecks = 0;
- m_pCallbacks = NULL;
+ m_specialFlags = CZipArchive::sfNone;
+ m_iIgnoredChecks = CZipArchive::checkIgnoredByDefault;
+ m_pArchive = NULL;
+ m_pStorage = NULL;
+ InitUnicode();
}
-void CZipCentralDir::Init(CZipStorage* pStorage, ZipArchiveLib::CZipCallbackProvider* pCallbacks, CZipStringStoreSettings* pStringSettings, CZipCentralDir* pSource)
+void CZipCentralDir::InitUnicode()
+{
+ #ifdef _ZIP_UNICODE_CUSTOM
+ m_iUnicodeMode = CZipArchive::umCustom;
+ #else
+ m_iUnicodeMode = CZipArchive::umNone;
+ #endif
+}
+
+void CZipCentralDir::InitOnCreate(CZipArchive* pArchive)
+{
+ m_pArchive = pArchive;
+ m_pStorage = pArchive->GetStorage();
+}
+
+void CZipCentralDir::Init(CZipCentralDir* pSource)
{
- m_pStorage = pStorage;
- m_pCallbacks = pCallbacks;
- m_pStringSettings = pStringSettings;
- m_pOpenedFile = NULL;
- m_iIgnoredChecks = CZipArchive::checkIgnoredByDefault;
+ m_pOpenedFile = NULL;
// just in case
DestroySharedData();
if (pSource != NULL)
{
-#ifdef ZIP_ARCHIVE_USE_LOCKING
+#ifdef _ZIP_USE_LOCKING
pSource->LockAccess();
#endif
m_pInfo = pSource->m_pInfo;
m_pInfo->m_iReference++;
m_pHeaders = pSource->m_pHeaders;
m_pFindArray = pSource->m_pFindArray;
-#ifdef ZIP_ARCHIVE_USE_LOCKING
+#ifdef _ZIP_USE_LOCKING
// points to the same object now
UnlockAccess();
#endif
@@ -79,28 +95,37 @@ CZipCentralDir::~CZipCentralDir()
DestroySharedData();
}
-void CZipCentralDir::Read(bool bExhaustiveRead)
+void CZipCentralDir::Read()
{
if (!m_pStorage)
{
ASSERT(FALSE);
return;
}
- m_pStorage->m_pFile->SeekToEnd();
-
- // maximum size of end of central dir record
- m_pInfo->m_uEndOffset = (ZIP_SIZE_TYPE)m_pStorage->LocateSignature(m_gszSignature, 0xFFFF + CENTRAL_DIR_END_SIZE);
-
- if (m_pInfo->m_uEndOffset == CZipStorage::SignatureNotFound)
+
+ const ZIP_FILE_USIZE location = LocateSignature();
+
+ if (location == CZipStorage::SignatureNotFound)
ThrowError(CZipException::cdirNotFound);
+
+ const bool isBinary = m_pStorage->IsBinarySplit();
+ if (!isBinary)
+ {
+ m_pInfo->m_uEndOffset = (ZIP_SIZE_TYPE)location;
+ m_pStorage->m_pFile->SafeSeek((ZIP_FILE_USIZE)(m_pInfo->m_uEndOffset + 4));
+ }
+ else
+ {
+ const ZIP_FILE_USIZE uPos = m_pStorage->m_pFile->GetPosition();
+ ASSERT(uPos > location);
+ m_pStorage->SeekInBinary(-(ZIP_FILE_SIZE)(uPos - location) + 4);
+ m_pInfo->m_uEndOffset = m_pStorage->GetPosition() - 4;
+ }
- m_pStorage->m_pFile->Seek((ZIP_FILE_USIZE)(m_pInfo->m_uEndOffset + 4));
- CZipAutoBuffer buf(CENTRAL_DIR_END_SIZE);
+ CZipAutoBuffer buf(CENTRAL_DIR_END_SIZE - 4);
// we can skip the signature, we already know it is good - it was found
- int uRead = m_pStorage->m_pFile->Read(buf, CENTRAL_DIR_END_SIZE - 4);
- if (uRead != CENTRAL_DIR_END_SIZE - 4)
- ThrowError(CZipException::badZipFile);
+ m_pStorage->Read(buf, CENTRAL_DIR_END_SIZE - 4, true);
WORD uCommentSize;
CBytesWriter::ReadBytes(m_pInfo->m_uLastVolume, buf, 2);
@@ -115,29 +140,43 @@ void CZipCentralDir::Read(bool bExhaustiveRead)
if (uCommentSize)
{
m_pInfo->m_pszComment.Allocate(uCommentSize);
- uRead = m_pStorage->m_pFile->Read(m_pInfo->m_pszComment, uCommentSize);
- if (uRead != uCommentSize)
- ThrowError(CZipException::badZipFile);
+ m_pStorage->Read(m_pInfo->m_pszComment, uCommentSize, true);
}
-
- if ( m_pInfo->NeedsZip64() )
+ if (m_pInfo->NeedsZip64())
{
- m_pStorage->m_pFile->Seek((ZIP_FILE_USIZE)(m_pInfo->m_uEndOffset));
- ULONGLONG uPosition = m_pStorage->LocateSignature(m_gszSignature64Locator, ZIP_SIZE_TYPE(-1));
- if (uPosition != CZipStorage::SignatureNotFound)
- ThrowError(CZipException::noZip64);
+ if (isBinary || m_pInfo->m_uEndOffset >= CENTRAL_DIR_END64_LOCATOR_SIZE)
+ {
+ if (isBinary)
+ m_pStorage->SeekInBinary(-(ZIP_FILE_SIZE)CENTRAL_DIR_END_SIZE - uCommentSize - CENTRAL_DIR_END64_LOCATOR_SIZE);
+ else
+ m_pStorage->m_pFile->SafeSeek((ZIP_FILE_USIZE)(m_pInfo->m_uEndOffset) - CENTRAL_DIR_END64_LOCATOR_SIZE);
+ char buffer[4];
+ m_pStorage->Read(buffer, 4, true);
+ if (memcmp(buffer, m_gszSignature64Locator, 4) == 0)
+ ThrowError(CZipException::noZip64);
+ }
// when the zip64 locator is not found, try to treat this archive as normal
}
- // if m_uLastVolume is not zero, it is enough to say that it is a multi-volume archive
- ASSERT((!m_pInfo->m_uLastVolume && (m_pInfo->m_uEntriesNumber == m_pInfo->m_uVolumeEntriesNo) && !m_pInfo->m_uVolumeWithCD) || m_pInfo->m_uLastVolume);
+ // if m_uLastVolume is not zero, it is enough to say that it is a multi-volume archive unless it is a binary split archive
+ if (IsConsistencyCheckOn(CZipArchive::checkVolumeEntries))
+ if (!((!m_pInfo->m_uLastVolume && (m_pInfo->m_uEntriesNumber == m_pInfo->m_uVolumeEntriesNo) && !m_pInfo->m_uVolumeWithCD)
+ || m_pInfo->m_uLastVolume))
+ ThrowError(CZipException::badZipFile);
m_pStorage->UpdateSegmMode(m_pInfo->m_uLastVolume);
+ bool bCheckBytesBeforeZip;
if (!m_pStorage->IsSegmented() && !m_pInfo->CheckIfOK_1())
- ThrowError(CZipException::badZipFile);
+ {
+ if (IsConsistencyCheckOn(CZipArchive::checkTrimmedCentralDir))
+ ThrowError(CZipException::badZipFile);
+ bCheckBytesBeforeZip = false;
+ }
+ else
+ bCheckBytesBeforeZip = true;
- if (m_pStorage->m_uBytesBeforeZip == 0 && m_pInfo->m_uLastVolume == 0)
+ if (bCheckBytesBeforeZip && m_pStorage->m_uBytesBeforeZip == 0 && m_pInfo->m_uLastVolume == 0)
m_pStorage->m_uBytesBeforeZip = m_pInfo->CalculateBytesBeforeZip();
if (!m_pInfo->CheckIfOK_2())
@@ -149,7 +188,7 @@ void CZipCentralDir::Read(bool bExhaustiveRead)
if (!m_pInfo->m_uSize)
return;
- ReadHeaders(bExhaustiveRead);
+ ReadHeaders();
}
@@ -159,40 +198,66 @@ void CZipCentralDir::ThrowError(int err) const
}
-void CZipCentralDir::ReadHeaders(bool bExhaustiveRead)
+void CZipCentralDir::ReadHeaders()
{
- m_pStorage->Seek(m_pInfo->m_uOffset);
+ if (!m_pStorage->IsBinarySplit())
+ m_pStorage->Seek(m_pInfo->m_uOffset);
+ else
+ m_pStorage->SeekInBinary(m_pInfo->m_uOffset, true);
+
RemoveHeaders(); //just in case
- for (ZIP_INDEX_TYPE i = 0; i < m_pInfo->m_uEntriesNumber; i++)
+ for (ZIP_INDEX_TYPE i = 0; ; i++)
{
- CZipFileHeader* pHeader = new CZipFileHeader;
+ if (i == m_pInfo->m_uEntriesNumber)
+ {
+ break;
+ }
+
+ CZipFileHeader* pHeader = new CZipFileHeader(this);
m_pHeaders->Add(pHeader);
- if (!pHeader->Read(*this, true))
+ if (!pHeader->Read(true))
ThrowError(CZipException::badZipFile);
}
- if (bExhaustiveRead)
+ if (m_specialFlags.IsSetAny(CZipArchive::sfExhaustiveRead))
{
- ZIP_FILE_USIZE uPosition = m_pStorage->m_pFile->GetPosition();
+ ZIP_FILE_USIZE uPosition = m_pStorage->GetPosition();
// different offset, or different parts
- if (uPosition != m_pInfo->m_uEndOffset || m_pStorage->IsSegmented() && m_pStorage->GetCurrentVolume() != m_pInfo->m_uLastVolume)
+ if (uPosition != m_pInfo->m_uEndOffset || (m_pStorage->IsSegmented() && !m_pStorage->IsBinarySplit() && m_pStorage->GetCurrentVolume() != m_pInfo->m_uLastVolume))
for(;;)
{
CZipAutoBuffer buf(4);
m_pStorage->Read(buf, 4, true);
if (!CZipFileHeader::VerifySignature(buf))
break;
- CZipFileHeader* pHeader = new CZipFileHeader;
+ CZipFileHeader* pHeader = new CZipFileHeader(this);
m_pHeaders->Add(pHeader);
- if (!pHeader->Read(*this, false))
+ if (!pHeader->Read(false))
ThrowError(CZipException::badZipFile);
}
}
- // this is necessary when removing data descriptors, CZipArchive::MakeSpaceForReplace, deleting, replacing or encrypting files
- // sort always, to yield the same results in requesting files by index regardless of the reason for opening
+ // This is necessary when removing data descriptors, CZipArchive::MakeSpaceForReplace, deleting, replacing or encrypting files
+ // sort always, to yield the same results in requesting files by index regardless of the reason for opening.
+ // We don't want to throw an exception while sorting headers as doing so from within std::sort can have unpredictable results.
+ // That's why we first sort them and then we verify the offsets of headers.
m_pHeaders->Sort(CompareHeaders);
+ // verify the headers
+ size_t iSize = m_pHeaders->GetSize();
+ if (iSize > 1) // need at least 2 items to compare
+ {
+ CZipFileHeader* previous = m_pHeaders->GetAt(0);
+ for (size_t i = 1; i < iSize; i++)
+ {
+ CZipFileHeader* current = m_pHeaders->GetAt(i);
+ if (previous->m_uVolumeStart == current->m_uVolumeStart && previous->m_uOffset == current->m_uOffset)
+ {
+ CZipException::Throw(CZipException::badZipFile);
+ }
+ previous = current;
+ }
+ }
RebuildFindFastArray();
}
@@ -204,6 +269,8 @@ void CZipCentralDir::Close()
m_pInfo = NULL;
m_pHeaders = NULL;
m_pFindArray = NULL;
+ m_specialFlags = CZipArchive::sfNone;
+ InitUnicode();
}
bool CZipCentralDir::IsValidIndex(ZIP_INDEX_TYPE uIndex)const
@@ -213,10 +280,8 @@ bool CZipCentralDir::IsValidIndex(ZIP_INDEX_TYPE uIndex)const
void CZipCentralDir::OpenFile(ZIP_INDEX_TYPE uIndex)
{
- CZipFileHeader* pOpenedFile = (*this)[uIndex];
- m_pStorage->ChangeVolume(pOpenedFile->m_uVolumeStart);
- m_pStorage->Seek(pOpenedFile->m_uOffset);
- if (!pOpenedFile->ReadLocal(*this))
+ CZipFileHeader* pOpenedFile = (*this)[uIndex];
+ if (!pOpenedFile->ReadLocal(this))
ThrowError(CZipException::badZipFile);
m_pOpenedFile = pOpenedFile;
}
@@ -238,31 +303,34 @@ CZipFileHeader* CZipCentralDir::AddNewFile(const CZipFileHeader & header, ZIP_IN
// copy some of the template data
m_pOpenedFile = NULL;
ZIP_INDEX_TYPE uIndex;
- CZipFileHeader* pHeader = new CZipFileHeader();
+ CZipFileHeader* pHeader = new CZipFileHeader(this);
try
{
pHeader->m_uMethod = header.m_uMethod;
pHeader->m_uModDate = header.m_uModDate;
pHeader->m_uModTime = header.m_uModTime;
+ pHeader->m_tModificationTime = header.m_tModificationTime;
+ pHeader->m_tCreationTime = header.m_tCreationTime;
+ pHeader->m_tLastAccessTime = header.m_tLastAccessTime;
pHeader->m_uExternalAttr = header.m_uExternalAttr;
pHeader->m_uLocalComprSize = header.m_uLocalComprSize;
pHeader->m_uLocalUncomprSize = header.m_uLocalUncomprSize;
- if (header.m_pszFileName != NULL)
- pHeader->m_pszFileName = new CZipString(*header.m_pszFileName);
-
- pHeader->m_pszFileNameBuffer = header.m_pszFileNameBuffer;
- pHeader->m_pszComment = header.m_pszComment;
+ pHeader->m_uLocalHeaderSize = header.m_uLocalHeaderSize;
+ pHeader->m_fileName = header.m_fileName;
+ pHeader->m_comment = header.m_comment;
pHeader->m_aLocalExtraData = header.m_aLocalExtraData;
// local will be removed in a moment in PrepareData
pHeader->m_aCentralExtraData = header.m_aCentralExtraData;
pHeader->m_aCentralExtraData.RemoveInternalHeaders();
- pHeader->SetSystemCompatibility(header.GetSystemCompatibility());
- pHeader->m_uEncryptionMethod = header.m_uEncryptionMethod;
-
+ pHeader->m_iSystemCompatibility = header.m_iSystemCompatibility;
+ pHeader->m_uEncryptionMethod = header.m_uEncryptionMethod;
+ pHeader->UpdateStringsFlags(false);
+#ifdef _ZIP_UNICODE_CUSTOM
// current settings
- pHeader->m_stringSettings = *m_pStringSettings;
+ pHeader->m_stringSettings = GetStringStoreSettings();
+#endif
// set only when adding a new file, not in PrepareData (which may be called under different circumstances)
// we need the proper encryption method to be set already
@@ -270,22 +338,24 @@ CZipFileHeader* CZipCentralDir::AddNewFile(const CZipFileHeader & header, ZIP_IN
bool bReplace = IsValidIndex(uReplaceIndex);
- pHeader->PrepareData(iLevel, m_pStorage->IsSegmented() != 0);
+ pHeader->PrepareData(iLevel, m_pStorage->IsSegmented());
if (bRichHeaderTemplateCopy)
{
// call here, because PrepareData will zero them
pHeader->m_uCrc32 = header.m_uCrc32;
pHeader->m_uComprSize = header.m_uComprSize;
- pHeader->m_uUncomprSize = header.m_uUncomprSize;
+ pHeader->m_uUncomprSize = header.m_uUncomprSize;
}
- // local extra field is updated if needed, so we can check the lengths
- if (!pHeader->CheckLengths(true))
- ThrowError(CZipException::tooLongData);
// now that everything is all right, we can add the new file
if (bReplace)
{
+ // PrepareStringBuffers was called in CZipArchive::OpenNewFile
+ // the local extra field is updated if needed, so we can check the lengths
+ if (!pHeader->CheckLengths(true))
+ ThrowError(CZipException::tooLongData);
+
CZipFileHeader* pfh = (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)uReplaceIndex];
m_pStorage->Seek(pfh->m_uOffset);
RemoveFile(pfh, uReplaceIndex, false);
@@ -310,30 +380,18 @@ CZipFileHeader* CZipCentralDir::AddNewFile(const CZipFileHeader & header, ZIP_IN
if (m_pInfo->m_bFindFastEnabled)
InsertFindFastElement(pHeader, uIndex); // GetCount > 0, because we have just added a header
-
+ m_pInfo->m_iLastIndexAdded = uIndex;
return pHeader;
}
-void CZipCentralDir::SetComment(LPCTSTR lpszComment)
-{
- ZipCompatibility::ConvertStringToBuffer(lpszComment, m_pInfo->m_pszComment, m_pStringSettings->m_uCommentCodePage);
- RemoveFromDisk();
-}
-bool CZipCentralDir::SetFileComment(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszComment)
+void CZipCentralDir::SetComment(LPCTSTR lpszComment, UINT codePage)
{
- if (!IsValidIndex(uIndex))
- {
- ASSERT(FALSE);
- return false;
- }
- CZipFileHeader* pHeader = (*this)[uIndex];
- pHeader->m_stringSettings.m_uCommentCodePage = m_pStringSettings->m_uCommentCodePage;
- pHeader->SetComment(lpszComment);
+ ZipCompatibility::ConvertStringToBuffer(lpszComment, m_pInfo->m_pszComment, codePage);
RemoveFromDisk();
- return true;
}
+
void CZipCentralDir::RemoveFromDisk()
{
if (m_pInfo->m_bInArchive)
@@ -418,7 +476,7 @@ void CZipCentralDir::Write()
}
// make sure that in a segmented archive, the whole central directory will fit on the single volume
- if (!bDontAllowVolumeChange)
+ if (!bDontAllowVolumeChange && !m_pStorage->IsBinarySplit())
m_pStorage->AssureFree(uSize);
}
@@ -448,15 +506,23 @@ void CZipCentralDir::Write()
void CZipCentralDir::WriteHeaders(bool bOneDisk)
{
- CZipActionCallback* pCallback = m_pCallbacks->Get(CZipActionCallback::cbSave);
+ CZipActionCallback* pCallback = m_pArchive->GetCallback(CZipActionCallback::cbSave);
m_pInfo->m_uVolumeEntriesNo = 0;
- m_pInfo->m_uVolumeWithCD = m_pStorage->GetCurrentVolume();
-
+ bool binarySplit = m_pStorage->IsBinarySplit();
+ if (binarySplit)
+ {
+ m_pStorage->AssureFree(1);
+ m_pInfo->m_uVolumeWithCD = 0;
+ }
+ else
+ m_pInfo->m_uVolumeWithCD = m_pStorage->GetCurrentVolume();
+
m_pInfo->m_uOffset = m_pStorage->GetPosition();
+
if (!m_pInfo->m_uEntriesNumber)
return;
- ZIP_VOLUME_TYPE uDisk = m_pInfo->m_uVolumeWithCD;
+ ZIP_VOLUME_TYPE uDisk = m_pStorage->GetCurrentVolume();
if (pCallback)
{
@@ -467,15 +533,15 @@ void CZipCentralDir::WriteHeaders(bool bOneDisk)
int iAborted = 0;
if (m_pInfo->m_uEntriesNumber > 0)
{
- ZIP_INDEX_TYPE uLast = (ZIP_INDEX_TYPE)(m_pInfo->m_uEntriesNumber - 1);
+ const ZIP_INDEX_TYPE uLast = (ZIP_INDEX_TYPE)(m_pInfo->m_uEntriesNumber - 1);
ZIP_INDEX_TYPE i = 0;
for (;;)
{
CZipFileHeader* pHeader = (*this)[i];
- m_pInfo->m_uSize += pHeader->Write(m_pStorage);
+ m_pInfo->m_uSize += pHeader->Write(this);
- if (m_pStorage->GetCurrentVolume() != uDisk)
+ if (!binarySplit && m_pStorage->GetCurrentVolume() != uDisk)
{
m_pInfo->m_uVolumeEntriesNo = 1;
uDisk = m_pStorage->GetCurrentVolume();
@@ -544,18 +610,26 @@ void CZipCentralDir::WriteHeaders(bool bOneDisk)
void CZipCentralDir::WriteCentralEnd()
{
- ZIP_SIZE_TYPE uSize = CENTRAL_DIR_END_SIZE + m_pInfo->m_pszComment.GetSize();
+ ZIP_SIZE_TYPE uSize = CENTRAL_DIR_END_SIZE + (ZIP_SIZE_TYPE)m_pInfo->m_pszComment.GetSize();
CZipAutoBuffer buf((DWORD)uSize);
char* pBuf = buf;
ZIP_VOLUME_TYPE uDisk = m_pStorage->GetCurrentVolume();
- if (m_pStorage->IsSegmented() != 0)
+ if (m_pStorage->IsSegmented())
{
// update the volume number
- m_pStorage->AssureFree(uSize);
- m_pInfo->m_uLastVolume = m_pStorage->GetCurrentVolume();
+ if (m_pStorage->IsBinarySplit())
+ {
+ m_pStorage->AssureFree(1);
+ m_pInfo->m_uLastVolume = 0;
+ }
+ else
+ {
+ m_pStorage->AssureFree(uSize);
+ m_pInfo->m_uLastVolume = m_pStorage->GetCurrentVolume();
+ }
}
- if (m_pInfo->m_uLastVolume != uDisk)
+ if (m_pInfo->m_uLastVolume != uDisk && !m_pStorage->IsBinarySplit())
m_pInfo->m_uVolumeEntriesNo = 0;
@@ -576,10 +650,39 @@ void CZipCentralDir::WriteCentralEnd()
void CZipCentralDir::RemoveAll()
{
+ m_pInfo->m_iLastIndexAdded = ZIP_FILE_INDEX_UNSPECIFIED;
ClearFindFastArray();
RemoveHeaders();
}
+ZIP_INDEX_TYPE CZipCentralDir::RemoveFindFastElement(CZipFileHeader* pHeader, bool bShift)
+{
+ // FindFileNameIndex(pHeader->GetFileName()) will not work as the file might have been just renamed
+ ZIP_ARRAY_SIZE_TYPE count = m_pFindArray->GetSize();
+ for (ZIP_ARRAY_SIZE_TYPE i = 0; i < count; i++)
+ {
+ CZipFindFast* pFindFast = (*m_pFindArray)[i];
+ if (pFindFast->m_pHeader == pHeader)
+ {
+ ZIP_INDEX_TYPE uElementIndex = pFindFast->m_uIndex;
+ delete pFindFast;
+ m_pFindArray->RemoveAt((ZIP_ARRAY_SIZE_TYPE)i);
+ // shift down the indexes
+ if (bShift)
+ {
+ ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)m_pFindArray->GetSize();
+ for (ZIP_INDEX_TYPE j = 0; j < uSize; j++)
+ {
+ if ((*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)j]->m_uIndex > uElementIndex)
+ (*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)j]->m_uIndex--;
+ }
+ }
+ return uElementIndex;
+ }
+ }
+ ASSERT(FALSE);
+ return ZIP_FILE_INDEX_NOT_FOUND;
+}
void CZipCentralDir::RemoveFile(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex, bool bShift)
{
@@ -600,30 +703,20 @@ void CZipCentralDir::RemoveFile(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex,
if (m_pInfo->m_bFindFastEnabled)
{
- ZIP_INDEX_TYPE i = FindFileNameIndex(pHeader->GetFileName());
- ASSERT(i != ZIP_FILE_INDEX_NOT_FOUND);
- CZipFindFast* pFindFast = (*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)i];
- ZIP_INDEX_TYPE uBorderIndex = pFindFast->m_uIndex;
- delete pFindFast;
- pFindFast = NULL;
- m_pFindArray->RemoveAt((ZIP_ARRAY_SIZE_TYPE)i);
- // shift down the indexes
-
- if (bShift)
- {
- ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)m_pFindArray->GetSize();
- for (ZIP_INDEX_TYPE j = 0; j < uSize; j++)
- {
- if ((*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)j]->m_uIndex > uBorderIndex)
- (*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)j]->m_uIndex--;
- }
- }
+ RemoveFindFastElement(pHeader, bShift);
}
if (uIndex != ZIP_FILE_INDEX_UNSPECIFIED)
{
delete pHeader;
m_pHeaders->RemoveAt((ZIP_ARRAY_SIZE_TYPE)uIndex);
+ if (m_pInfo->m_iLastIndexAdded != ZIP_FILE_INDEX_UNSPECIFIED)
+ {
+ if (m_pInfo->m_iLastIndexAdded == uIndex)
+ m_pInfo->m_iLastIndexAdded = ZIP_FILE_INDEX_UNSPECIFIED;
+ else if (m_pInfo->m_iLastIndexAdded > uIndex)
+ m_pInfo->m_iLastIndexAdded--;
+ }
}
}
@@ -650,7 +743,7 @@ void CZipCentralDir::RemoveLastFile(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uInd
ZIP_SIZE_TYPE CZipCentralDir::GetSize(bool bWhole) const
{
- ZIP_SIZE_TYPE uTotal = CENTRAL_DIR_END_SIZE + m_pInfo->m_pszComment.GetSize();
+ ZIP_SIZE_TYPE uTotal = CENTRAL_DIR_END_SIZE + (ZIP_SIZE_TYPE)m_pInfo->m_pszComment.GetSize();
ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize();
if (bWhole)
{
@@ -693,7 +786,7 @@ bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer)
for (ZIP_INDEX_TYPE i = 0; i < uCount; i++)
{
CZipFileHeader* pHeader = (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i];
- char* pSour = pFile + pHeader->m_uOffset;
+ char* pSource = pFile + pHeader->m_uOffset;
if (pHeader->NeedsDataDescriptor())
uExtraHeaderLen = (WORD)(pHeader->IsEncrypted() ? 0 : 4);
@@ -704,15 +797,15 @@ bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer)
pHeader->m_uFlag &= ~8;
// update local header:
// write modified flag in the local header
- CBytesWriter::WriteBytes(pSour + 6, pHeader->m_uFlag);
- pHeader->WriteSmallDataDescriptor(pSour + 14, false);
+ CBytesWriter::WriteBytes(pSource + 6, pHeader->m_uFlag);
+ pHeader->WriteSmallDataDescriptor(pSource + 14, false);
}
ZIP_SIZE_TYPE uToCopy = (i == (uCount - 1) ? uSize : (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)(i + 1)]->m_uOffset)
- pHeader->m_uOffset - uExtraHeaderLen;
if (uToCopy > 0)
// TODO: [postponed] the size_t limit on uToCopy, but creating such a big segment is unlikely (at least at the moment of writing)
- memmove(pFile + uPosInBuffer, pSour, (size_t)uToCopy);
+ memmove(pFile + uPosInBuffer, pSource, (size_t)uToCopy);
uPosInBuffer += uToCopy;
pHeader->m_uOffset -= uOffsetToChange;
@@ -901,20 +994,76 @@ ZIP_INDEX_TYPE CZipCentralDir::FindFileNameIndex(LPCTSTR lpszFileName) const
return ZIP_FILE_INDEX_NOT_FOUND;
}
+void CZipCentralDir::GetComment(CZipString& szComment) const
+{
+ ZipCompatibility::ConvertBufferToString(szComment, m_pInfo->m_pszComment, ZipCompatibility::GetDefaultCommentCodePage(m_pArchive->GetSystemCompatibility()));
+}
+
+#ifdef _ZIP_UNICODE_CUSTOM
+
+const CZipStringStoreSettings& CZipCentralDir::GetStringStoreSettings() const
+{
+ return m_pArchive->GetStringStoreSettings();
+}
+
+#endif
+
+bool CZipCentralDir::OnFileNameChange(CZipFileHeader* pHeader, bool bInCentralOnly)
+{
+ bool result;
+ if (m_pArchive->GetCommitMode() == CZipArchive::cmOnChange && !bInCentralOnly)
+ result = m_pArchive->CommitChanges();
+ else
+ result = m_pArchive->CanModify();
+
+ if (result)
+ {
+ if (bInCentralOnly)
+ {
+ RemoveFromDisk();
+ }
+
+ if (m_pInfo->m_bFindFastEnabled)
+ {
+ InsertFindFastElement(pHeader, RemoveFindFastElement(pHeader, false));
+ }
+ }
+ return result;
+}
+
+bool CZipCentralDir::OnFileCentralChange()
+{
+ if (!m_pArchive->CanModify(true))
+ {
+ return false;
+ }
+
+ RemoveFromDisk();
+ m_pArchive->Finalize(true);
+ return true;
+}
void CZipCentralDir::CreateSharedData()
{
m_pInfo = new CInfo();
- m_pInfo->Init();
m_pHeaders = new CZipArray<CZipFileHeader*>();
m_pFindArray = new CZipArray<CZipFindFast*>();
}
+bool CZipCentralDir::IsAnyFileModified() const
+{
+ ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize();
+ for (ZIP_INDEX_TYPE i = 0; i < uCount; i++)
+ if ((*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i]->IsModified())
+ return true;
+ return false;
+}
+
void CZipCentralDir::DestroySharedData()
{
if (!m_pInfo)
return;
-#ifdef ZIP_ARCHIVE_USE_LOCKING
+#ifdef _ZIP_USE_LOCKING
LockAccess();
try
{
@@ -936,13 +1085,13 @@ void CZipCentralDir::DestroySharedData()
delete m_pFindArray;
m_pFindArray = NULL;
}
-#ifdef ZIP_ARCHIVE_USE_LOCKING
+#ifdef _ZIP_USE_LOCKING
UnlockAccess();
#endif
delete m_pInfo;
m_pInfo = NULL;
}
-#ifdef ZIP_ARCHIVE_USE_LOCKING
+#ifdef _ZIP_USE_LOCKING
}
catch(...)
{
@@ -951,5 +1100,11 @@ void CZipCentralDir::DestroySharedData()
}
UnlockAccess();
#endif
+}
+
+ZIP_FILE_USIZE CZipCentralDir::LocateSignature()
+{
+ m_pStorage->m_pFile->SeekToEnd();
+ return m_pStorage->LocateSignature(m_gszSignature, 0xFFFF + CENTRAL_DIR_END_SIZE);
}