summaryrefslogtreecommitdiff
path: root/zip/ZipArchive/ZipStorage.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zip/ZipArchive/ZipStorage.cpp')
-rw-r--r--zip/ZipArchive/ZipStorage.cpp439
1 files changed, 307 insertions, 132 deletions
diff --git a/zip/ZipArchive/ZipStorage.cpp b/zip/ZipArchive/ZipStorage.cpp
index d416fd6..25f1e3b 100644
--- a/zip/ZipArchive/ZipStorage.cpp
+++ b/zip/ZipArchive/ZipStorage.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
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
@@ -19,8 +19,12 @@
char CZipStorage::m_gszExtHeaderSignat[] = {0x50, 0x4b, 0x07, 0x08};
const ZIP_FILE_USIZE CZipStorage::SignatureNotFound = ZIP_FILE_USIZE(-1);
+#define SIGNATURE_SIZE 4
+using namespace ZipArchiveLib;
+
+#pragma warning(suppress: 26495)
CZipStorage::CZipStorage()
{
Initialize();
@@ -30,17 +34,21 @@ void CZipStorage::Initialize()
{
m_pSplitChangeVolumeFunc = m_pSpanChangeVolumeFunc = m_pChangeVolumeFunc = NULL;
m_iWriteBufferSize = 65536;
- m_pFile = NULL;
- m_szSplitExtension = _T("zip");
+ m_pFile = NULL;
m_iLocateBufferSize = 32768;
m_uBytesBeforeZip = 0;
m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
m_szArchiveName.Empty();
+ m_pSplitNames = NULL;
+ m_pCachedSizes = NULL;
+ m_bAutoDeleteSplitNames = false;
+ m_state = 0;
}
CZipStorage::~CZipStorage()
{
-
+ ClearSplitNames();
+ ClearCachedSizes();
}
DWORD CZipStorage::Read(void *pBuf, DWORD iSize, bool bAtOnce)
@@ -50,7 +58,7 @@ DWORD CZipStorage::Read(void *pBuf, DWORD iSize, bool bAtOnce)
DWORD iRead;
for(;;)
{
- iRead = m_pFile->Read(pBuf, iSize);
+ iRead = (DWORD)m_pFile->Read(pBuf, iSize);
if (!iRead)
{
if (IsSegmented())
@@ -64,13 +72,13 @@ DWORD CZipStorage::Read(void *pBuf, DWORD iSize, bool bAtOnce)
if (iRead == iSize)
return iRead;
- else if (bAtOnce || !IsSegmented())
+ else if ((bAtOnce && !IsBinarySplit()) || !IsSegmented())
ThrowError(CZipException::badZipFile);
while (iRead < iSize)
{
ChangeVolume();
- UINT iNewRead = m_pFile->Read((char*)pBuf + iRead, iSize - iRead);
+ UINT iNewRead = (UINT)m_pFile->Read((char*)pBuf + iRead, iSize - iRead);
if (!iNewRead && iRead < iSize)
ThrowError(CZipException::badZipFile);
iRead += iNewRead;
@@ -84,39 +92,46 @@ void CZipStorage::Open(LPCTSTR lpszPathName, int iMode, ZIP_SIZE_TYPE uVolumeSiz
m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
m_pWriteBuffer.Allocate(m_iWriteBufferSize);
m_uBytesInWriteBuffer = 0;
- m_bNewSegm = false;
+ m_state.Set(stateOpened | stateAutoClose);
m_pFile = &m_internalfile;
- m_bInMemory = false;
m_szArchiveName = lpszPathName;
m_pChangeVolumeFunc = NULL;
- if (iMode == CZipArchive::zipCreate || iMode == CZipArchive::zipCreateSegm
- || iMode == CZipArchive::zipCreateAppend) // create new archive
- {
- m_bReadOnly = false;
+ CBitFlag mode(iMode);
+
+ if (mode.IsSetAny(CZipArchive::zipCreate)) // create new archive
+ {
m_uCurrentVolume = 0;
- if (iMode == CZipArchive::zipCreate || iMode == CZipArchive::zipCreateAppend)
+ if (!mode.IsSetAny(CZipArchive::zipModeSegmented))
{
- m_iSegmMode = noSegments;
- OpenFile(lpszPathName, (iMode == CZipArchive::zipCreate ? CZipFile::modeCreate : CZipFile::modeNoTruncate) | CZipFile::modeReadWrite);
+ OpenFile(lpszPathName, (mode.IsSetAll(CZipArchive::zipCreateAppend) ? CZipFile::modeNoTruncate : CZipFile::modeCreate) | CZipFile::modeReadWrite);
}
else // create a segmented archive
- {
- m_bNewSegm = true;
+ {
m_uBytesWritten = 0;
- if (uVolumeSize == ZIP_AUTODETECT_VOLUME_SIZE) // spanned archive
+ if (mode.IsSetAny(CZipArchive::zipModeSpan))
{
if (!m_pSpanChangeVolumeFunc)
ThrowError(CZipException::noCallback);
if (!ZipPlatform::IsDriveRemovable(lpszPathName))
ThrowError(CZipException::nonRemovable);
- m_iSegmMode = spannedArchive;
+ m_state.Set(stateSpan);
m_pChangeVolumeFunc = m_pSpanChangeVolumeFunc;
}
+ else if (uVolumeSize <= 0)
+ ThrowError(CZipException::noVolumeSize);
else
{
m_uSplitData = uVolumeSize;
- m_iSegmMode = splitArchive;
+ if (mode.IsSetAll(CZipArchive::zipModeBinSplit))
+ {
+ m_state.Set(stateBinarySplit);
+ ClearCachedSizes(); // just in case
+ m_pCachedSizes = new CZipArray<ZIP_FILE_USIZE>();
+ }
+ else
+ m_state.Set(stateSplit);
+ EnsureSplitNames();
m_pChangeVolumeFunc = m_pSplitChangeVolumeFunc;
}
@@ -126,52 +141,95 @@ void CZipStorage::Open(LPCTSTR lpszPathName, int iMode, ZIP_SIZE_TYPE uVolumeSiz
}
else // open existing
{
- m_bReadOnly = iMode == CZipArchive::zipOpenReadOnly;
+ m_state.Set(stateExisting);
+ bool readOnly = mode.IsSetAll(CZipArchive::zipOpenReadOnly);
+ if (readOnly)
+ m_state.Set(stateReadOnly);
OpenFile(lpszPathName, CZipFile::modeNoTruncate |
- (m_bReadOnly ? CZipFile::modeRead : CZipFile::modeReadWrite));
- // m_uData and m_iSegmMode are automatically set during reading the central dir
- m_iSegmMode = uVolumeSize == 0 ? suggestedAuto : suggestedSplit;
- }
-
+ (readOnly ? CZipFile::modeRead : CZipFile::modeReadWrite));
+ // this will be revised in UpdateSegmMode
+ if (mode.IsSetAny(CZipArchive::zipModeSpan))
+ m_state.Set(stateSpan);
+ else if (mode.IsSetAll(CZipArchive::zipModeBinSplit))
+ {
+ m_state.Set(stateBinarySplit);
+ EnsureSplitNames();
+ m_uCurrentVolume = m_pSplitNames->GetVolumeNumber(m_szArchiveName);
+ if (m_uCurrentVolume == 0)
+ ThrowError(CZipException::badZipFile);
+ m_uCurrentVolume -= 1;
+ if (m_uCurrentVolume > 0)
+ {
+ m_uSplitData = m_uCurrentVolume;
+ CacheSizes();
+ }
+ else
+ {
+ ClearSplitNames();
+ m_state.Clear(stateBinarySplit);
+ }
+ }
+ else if (mode.IsSetAny(CZipArchive::zipModeSplit))
+ m_state.Set(stateSplit);
+ }
}
+void CZipStorage::CacheSizes()
+{
+ ClearCachedSizes(); // just in case
+ m_pCachedSizes = new CZipArray<ZIP_FILE_USIZE>();
+ m_pCachedSizes->SetSize((ZIP_ARRAY_SIZE_TYPE)(m_uCurrentVolume + 1));
+ ZIP_VOLUME_TYPE lastVolume = m_uCurrentVolume;
+ for(;;)
+ {
+ m_pCachedSizes->SetAt((ZIP_ARRAY_SIZE_TYPE)m_uCurrentVolume, m_pFile->GetLength());
+ if (m_uCurrentVolume == 0)
+ break;
+ ChangeVolume((ZIP_VOLUME_TYPE)(m_uCurrentVolume - 1));
+ }
+ ChangeVolume(lastVolume);
+}
-void CZipStorage::Open(CZipAbstractFile& af, int iMode)
+void CZipStorage::Open(CZipAbstractFile& af, int iMode, bool bAutoClose)
{
m_pWriteBuffer.Allocate(m_iWriteBufferSize);
m_uBytesInWriteBuffer = 0;
- m_bNewSegm = false;
+ m_state.Set(stateOpened);
+ if (bAutoClose)
+ m_state.Set(stateAutoClose);
m_pFile = &af;
- m_bInMemory = true;
- if (iMode == CZipArchive::zipCreate || iMode == CZipArchive::zipCreateAppend)
- {
+ CBitFlag mode(iMode);
+
+ if (mode.IsSetAny(CZipArchive::zipCreate))
+ {
m_uCurrentVolume = 0;
- m_iSegmMode = noSegments;
- if (iMode == CZipArchive::zipCreate)
- af.SetLength(0);
- else
+ if (mode.IsSetAll(CZipArchive::zipCreateAppend))
af.SeekToEnd();
+ else
+ af.SetLength(0);
}
else // open existing
{
+ m_state.Set(stateExisting);
+ if (mode.IsSetAll(CZipArchive::zipOpenReadOnly))
+ m_state.Set(stateReadOnly);
af.SeekToBegin();
- m_iSegmMode = suggestedAuto;
}
}
void CZipStorage::ChangeVolume(ZIP_VOLUME_TYPE uNumber)
{
- if (uNumber == m_uCurrentVolume || m_iSegmMode == noSegments) // the second condition may happen in some bad archives
+ if (uNumber == m_uCurrentVolume || !IsSegmented()) // the second condition may happen in some bad archives
return;
- m_uCurrentVolume = uNumber;
+ m_uCurrentVolume = uNumber;
OpenFile(IsSpanned() ? ChangeSpannedRead() : ChangeSplitRead(),
CZipFile::modeNoTruncate | CZipFile::modeRead);
}
-void CZipStorage::ThrowError(int err)
+void CZipStorage::ThrowError(int err) const
{
CZipException::Throw(err, m_pFile->GetFilePath());
}
@@ -187,36 +245,41 @@ CZipString CZipStorage::ChangeSpannedRead()
CZipString szTemp = m_pFile->GetFilePath();
m_pFile->Close();
CallCallback(0, CZipSegmCallback::scVolumeNeededForRead, szTemp);
- return szTemp;
+ return m_pChangeVolumeFunc->m_szExternalFile;
}
CZipString CZipStorage::ChangeSplitRead()
{
bool lastPart = (ZIP_SIZE_TYPE)m_uCurrentVolume == m_uSplitData;
- CZipString szTemp = GetSplitVolumeName(lastPart);
+ CZipString szVolumeName = GetSplitVolumeName(lastPart);
if (m_pChangeVolumeFunc)
{
int iCode = CZipSegmCallback::scVolumeNeededForRead;
for(;;)
{
- CallCallback(lastPart ? ZIP_SPLIT_LAST_VOLUME : 0, iCode, szTemp);
+ CallCallback(lastPart ? ZIP_SPLIT_LAST_VOLUME : 0, iCode, szVolumeName);
if (ZipPlatform::FileExists(m_pChangeVolumeFunc->m_szExternalFile))
{
- szTemp = m_pChangeVolumeFunc->m_szExternalFile;
+ szVolumeName = m_pChangeVolumeFunc->m_szExternalFile;
break;
}
else
iCode = CZipSegmCallback::scFileNotFound;
}
}
+ else if (!ZipPlatform::FileExists(szVolumeName))
+ {
+ CZipException::Throw(CZipException::notFound, szVolumeName);
+ }
m_pFile->Close();
- return szTemp;
+ return szVolumeName;
}
CZipString CZipStorage::RenameLastFileInSplitArchive()
{
ASSERT(IsSplit());
- // give to the last volume the zip extension
+
+ // give to the last volume the zip extension
CZipString szFileName = m_pFile->GetFilePath();
CZipString szNewFileName = GetSplitVolumeName(true);
if (m_pChangeVolumeFunc)
@@ -232,70 +295,68 @@ CZipString CZipStorage::RenameLastFileInSplitArchive()
break;
}
}
- if (!m_bInMemory)
+
+ m_pFile->Flush();
+ m_pFile->Close();
+
+ ZIPSTRINGCOMPARE pCompare = GetCZipStrCompFunc(ZipPlatform::GetSystemCaseSensitivity());
+ if ((szFileName.*(pCompare))(szNewFileName) == 0)
{
- m_pFile->Flush();
- m_pFile->Close();
+ return szNewFileName;
}
+
if (!m_pChangeVolumeFunc && ZipPlatform::FileExists(szNewFileName))
+ {
ZipPlatform::RemoveFile(szNewFileName);
+ }
ZipPlatform::RenameFile(szFileName, szNewFileName);
return szNewFileName;
}
-CZipString CZipStorage::Close(bool bAfterException)
+CZipString CZipStorage::Close(bool bWrite, bool bGetLastVolumeName)
{
bool bClose = true;
CZipString sz;
- if (!bAfterException)
+ if (bWrite)
{
Flush();
- if (IsSplit() && m_bNewSegm)
+ if (IsSplit() && !IsExisting())
{
sz = RenameLastFileInSplitArchive();
bClose = false;// already closed in RenameLastFileInSplitArchive
}
}
- if (sz.IsEmpty())
- sz = m_pFile->GetFilePath();
- if (bClose && !m_bInMemory)
+
+ if (bGetLastVolumeName && sz.IsEmpty())
+ {
+ if (IsSplit() && IsExisting())
+ sz = m_pSplitNames->GetVolumeName(m_szArchiveName, (ZIP_VOLUME_TYPE)(m_uSplitData + 1), CZipSplitNamesHandler::flLast | CZipSplitNamesHandler::flExisting);
+ else
+ sz = m_pFile->GetFilePath();
+ }
+
+ if (bClose)
{
- if (!bAfterException)
+ if (bWrite)
FlushFile();
- m_pFile->Close();
+ if (m_state.IsSetAny(stateAutoClose))
+ m_pFile->Close();
}
m_pWriteBuffer.Release();
m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
- m_iSegmMode = noSegments;
+ m_state = 0;
m_pFile = NULL;
m_uBytesBeforeZip = 0;
+ ClearSplitNames();
+ ClearCachedSizes();
return sz;
}
-CZipString CZipStorage::GetSplitVolumeName(bool bLast) const
-{
- CZipString szFilePath = m_szArchiveName;
- CZipPathComponent zpc(szFilePath);
- CZipString szExt;
- if (bLast)
- szExt = m_szSplitExtension;
- else
- {
- DWORD vol = m_uCurrentVolume + 1;
- if (vol < 100)
- szExt.Format(_T("z%.2u"), vol);
- else
- szExt.Format(_T("z%u"), vol);
- }
- zpc.SetExtension(szExt);
- return zpc.GetFullPath();
-}
-
void CZipStorage::NextVolume(ZIP_SIZE_TYPE uNeeded)
{
Flush();
- ASSERT(m_iSegmMode != noSegments);
+ ASSERT(IsSegmented());
bool bSpan = IsSpanned();
if (m_uBytesWritten)
{
@@ -316,8 +377,10 @@ void CZipStorage::NextVolume(ZIP_SIZE_TYPE uNeeded)
if (!m_pFile->IsClosed())
{
m_pFile->Flush();
+ if (IsBinarySplit())
+ m_pCachedSizes->Add(m_pFile->GetLength());
m_pFile->Close();
- }
+ }
if (m_pChangeVolumeFunc)
{
@@ -325,9 +388,8 @@ void CZipStorage::NextVolume(ZIP_SIZE_TYPE uNeeded)
for(;;)
{
CallCallback(uNeeded, iCode, szFileName);
- if (!bSpan)
- // allow the user to change the filename
- szFileName = m_pChangeVolumeFunc->m_szExternalFile;
+ // allow changing of the filename
+ szFileName = m_pChangeVolumeFunc->m_szExternalFile;
if (ZipPlatform::FileExists(szFileName))
iCode = CZipSegmCallback::scFileNameDuplicated;
@@ -365,7 +427,10 @@ void CZipStorage::NextVolume(ZIP_SIZE_TYPE uNeeded)
void CZipStorage::CallCallback(ZIP_SIZE_TYPE uNeeded, int iCode, CZipString szTemp)
{
if (!m_pChangeVolumeFunc)
+ {
ThrowError(CZipException::internalError);
+ return; // for Code Analysis
+ }
m_pChangeVolumeFunc->m_szExternalFile = szTemp;
m_pChangeVolumeFunc->m_uVolumeNeeded = (ZIP_VOLUME_TYPE)(m_uCurrentVolume + 1);
m_pChangeVolumeFunc->m_iCode = iCode;
@@ -384,29 +449,26 @@ ZIP_SIZE_TYPE CZipStorage::GetFreeVolumeSpace() const
CZipPathComponent zpc(szTemp);
ULONGLONG ret = ZipPlatform::GetDeviceFreeSpace(zpc.GetFilePath());
if (ret > (ZIP_SIZE_TYPE)(-1))
- return (ZIP_SIZE_TYPE)(-1);
+ return (ZIP_SIZE_TYPE)(-1);
else
- return (ZIP_SIZE_TYPE)ret;
+ return (ZIP_SIZE_TYPE)ret;
}
}
void CZipStorage::UpdateSegmMode(ZIP_VOLUME_TYPE uLastDisk)
{
- m_uCurrentVolume = uLastDisk;
- if (uLastDisk)
+ bool binarySplit = IsBinarySplit();
+ if (!binarySplit)
+ m_uCurrentVolume = uLastDisk;
+
+ if (uLastDisk > 0 || binarySplit)
{
// segmentation detected
CZipString szFilePath = m_pFile->GetFilePath();
- if (m_iSegmMode == suggestedAuto)
- m_iSegmMode = ZipPlatform::IsDriveRemovable(szFilePath) ?
- spannedArchive : splitArchive;
- else
- {
- ASSERT(m_iSegmMode == suggestedSplit);
- m_iSegmMode = splitArchive;
- }
-
+ if (!m_state.IsSetAny(stateSegmented))
+ m_state.Set(ZipPlatform::IsDriveRemovable(szFilePath) ? stateSpan : stateSplit);
+
if (IsSpanned())
{
if (!m_pSpanChangeVolumeFunc)
@@ -415,16 +477,16 @@ void CZipStorage::UpdateSegmMode(ZIP_VOLUME_TYPE uLastDisk)
}
else /*if (IsSplit())*/
{
- m_uSplitData = uLastDisk; // volume with .zip extension ( the last one)
+ EnsureSplitNames();
+ if (!binarySplit)
+ m_uSplitData = uLastDisk; // the last volume
m_pChangeVolumeFunc = m_pSplitChangeVolumeFunc;
}
- CZipPathComponent zpc(szFilePath);
- m_szSplitExtension = zpc.GetFileExt();
m_pWriteBuffer.Release(); // no need for this in this case
}
- else
- m_iSegmMode = noSegments;
-
+ else
+ // it will clear all segmented flags
+ m_state.Clear(stateSpan | stateBinarySplit);
}
ZIP_SIZE_TYPE CZipStorage::AssureFree(ZIP_SIZE_TYPE uNeeded)
@@ -449,8 +511,9 @@ void CZipStorage::Write(const void *pBuf, DWORD iSize, bool bAtOnce)
WriteInternalBuffer((char*)pBuf, iSize);
else
{
- // if not at once, one byte is enough free space
- DWORD iNeeded = bAtOnce ? iSize : 1;
+ bool atOnce = bAtOnce && !IsBinarySplit();
+ // if not at once, one byte is enough of free space
+ DWORD iNeeded = atOnce ? iSize : 1;
DWORD uTotal = 0;
while (uTotal < iSize)
@@ -459,7 +522,7 @@ void CZipStorage::Write(const void *pBuf, DWORD iSize, bool bAtOnce)
DWORD uLeftToWrite = iSize - uTotal;
DWORD uToWrite = uFree < uLeftToWrite ? (DWORD)uFree : uLeftToWrite;
WriteInternalBuffer((char*)pBuf + uTotal, uToWrite);
- if (bAtOnce)
+ if (atOnce)
return;
else
uTotal += uToWrite;
@@ -500,28 +563,51 @@ void CZipStorage::Flush()
if (m_uBytesInWriteBuffer)
{
m_pFile->Write(m_pWriteBuffer, m_uBytesInWriteBuffer);
- if (m_iSegmMode != noSegments)
+ if (IsSegmented())
m_uBytesWritten += m_uBytesInWriteBuffer;
m_uBytesInWriteBuffer = 0;
}
if (IsSpanned())
// after writing it is difficult to predict the free space due to
- // not completly written clusters, write operation may start from a new cluster
- m_uCurrentVolSize = GetFreeVolumeSpace();
-
+ // not completely written clusters, write operation may start from a new cluster
+ m_uCurrentVolSize = GetFreeVolumeSpace();
}
ZIP_FILE_USIZE CZipStorage::LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMaxDepth)
+{
+ int leftToFind = SIGNATURE_SIZE - 1;
+ bool found = false; // for fast checking if leftToFind needs resetting
+ if (!IsBinarySplit())
+ {
+ return LocateSignature(szSignature, uMaxDepth, leftToFind, found, m_pFile->GetLength());
+ }
+ else
+ {
+ for(;;)
+ {
+ ZIP_FILE_USIZE uFileLength = GetCachedSize(m_uCurrentVolume);
+ ZIP_FILE_USIZE position = LocateSignature(szSignature, uMaxDepth, leftToFind, found, uFileLength);
+ if (position != SignatureNotFound || uMaxDepth <= uFileLength)
+ return position;
+ uMaxDepth -= (ZIP_SIZE_TYPE)uFileLength;
+ if (m_uCurrentVolume == 0)
+ return SignatureNotFound;
+ ChangeVolumeDec();
+ m_pFile->SeekToEnd();
+ }
+ }
+}
+
+ZIP_FILE_USIZE CZipStorage::LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMaxDepth, int& leftToFind, bool& found, ZIP_FILE_USIZE uFileLength)
{
- const int recordSize = 4;
CZipAutoBuffer buffer(m_iLocateBufferSize);
- ZIP_FILE_USIZE uFileLength = m_pFile->GetLength();
+
ZIP_SIZE_TYPE max = (ZIP_SIZE_TYPE)(uFileLength < uMaxDepth ? uFileLength : uMaxDepth);
ZIP_SIZE_TYPE position = (ZIP_SIZE_TYPE)(uFileLength - m_pFile->GetPosition());
int offset = 0;
- int leftToFind = recordSize - 1;
+
int toRead = m_iLocateBufferSize;
- bool found = false; // for fast checking if leftToFind needs resetting
+
while ( position < max )
{
position += toRead;
@@ -533,7 +619,7 @@ ZIP_FILE_USIZE CZipStorage::LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMa
position = max;
}
Seek(position, seekFromEnd);
- int actuallyRead = m_pFile->Read((char*)buffer + offset, toRead);
+ int actuallyRead = (int)m_pFile->Read((char*)buffer + offset, toRead);
if (actuallyRead != toRead)
ThrowError(CZipException::badZipFile);
int pos = m_iLocateBufferSize - 1;
@@ -542,7 +628,7 @@ ZIP_FILE_USIZE CZipStorage::LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMa
if ( buffer[pos] == szSignature[leftToFind] )
{
if ( leftToFind == 0 )
- return (ZIP_FILE_USIZE)(uFileLength - ( position - ( pos - offset ) ));
+ return (ZIP_FILE_SIZE)(uFileLength - ( position - ( (ZIP_FILE_SIZE)pos - offset ) ));
if ( !found )
found = true;
leftToFind--;
@@ -550,7 +636,7 @@ ZIP_FILE_USIZE CZipStorage::LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMa
}
else if ( found )
{
- leftToFind = recordSize - 1;
+ leftToFind = SIGNATURE_SIZE - 1;
found = false;
// do not decrease position, the current pos may be the first to find
}
@@ -558,16 +644,84 @@ ZIP_FILE_USIZE CZipStorage::LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMa
pos--;
}
}
- return SignatureNotFound;
+ return SignatureNotFound;
+}
+
+void CZipStorage::SeekInBinary(ZIP_FILE_SIZE lOff, bool bSeekToBegin)
+{
+ ASSERT(IsBinarySplit());
+ if (bSeekToBegin)
+ m_pFile->SeekToBegin();
+
+ if (lOff == 0)
+ return;
+
+ if (lOff > 0)
+ {
+ ZIP_SIZE_TYPE uPosition = (ZIP_SIZE_TYPE)m_pFile->GetPosition();
+ ZIP_FILE_USIZE uLength = GetCachedSize(m_uCurrentVolume);
+ if ((ZIP_FILE_USIZE)(uPosition + lOff) < uLength)
+ {
+ m_pFile->Seek(lOff, CZipAbstractFile::current);
+ return;
+ }
+ ZIP_VOLUME_TYPE uVolume = (ZIP_VOLUME_TYPE)(m_uCurrentVolume + 1);
+ lOff -= uLength - uPosition;
+ for(;;)
+ {
+ uLength = GetCachedSize(uVolume);
+ if ((ZIP_FILE_USIZE)lOff < uLength)
+ {
+ ChangeVolume(uVolume);
+ if (lOff > 0)
+ {
+ m_pFile->Seek(lOff, CZipAbstractFile::current);
+ }
+ return;
+ }
+ else
+ lOff -= uLength;
+ uVolume++;
+ }
+ }
+ else
+ {
+ ZIP_SIZE_TYPE uPosition = (ZIP_SIZE_TYPE)m_pFile->GetPosition();
+ if (uPosition >= (ZIP_SIZE_TYPE)(-lOff))
+ {
+ m_pFile->Seek(lOff, CZipAbstractFile::current);
+ return;
+ }
+ lOff += uPosition;
+ ZIP_VOLUME_TYPE uVolume = (ZIP_VOLUME_TYPE)(m_uCurrentVolume - 1);
+ for(;;)
+ {
+ ZIP_FILE_USIZE uLength = GetCachedSize(uVolume);
+ if (uLength >= (ZIP_SIZE_TYPE)(-lOff))
+ {
+ ChangeVolume(uVolume);
+ if (lOff < 0)
+ {
+ m_pFile->Seek(lOff, CZipAbstractFile::end);
+ }
+ return;
+ }
+ else
+ lOff += uLength;
+ if (uVolume == 0)
+ ThrowError(CZipException::genericError);
+ uVolume--;
+ }
+ }
}
ULONGLONG CZipStorage::Seek(ULONGLONG lOff, SeekType iSeekType)
{
if (iSeekType == seekCurrent)
- {
- ZIP_SIZE_TYPE uPosition = (ZIP_SIZE_TYPE)m_pFile->GetPosition();
- if (IsSegmented() == -1)
+ {
+ if (IsExistingSegmented())
{
+ ZIP_SIZE_TYPE uPosition = (ZIP_SIZE_TYPE)m_pFile->GetPosition();
ZIP_FILE_USIZE uLength = m_pFile->GetLength();
while (uPosition + lOff >= uLength)
{
@@ -577,7 +731,7 @@ ULONGLONG CZipStorage::Seek(ULONGLONG lOff, SeekType iSeekType)
uPosition = 0;
uLength = m_pFile->GetLength();
}
- return lOff > 0 ? m_pFile->Seek((ZIP_FILE_USIZE)lOff) : 0;
+ return lOff > 0 ? m_pFile->SafeSeek((ZIP_FILE_USIZE)lOff) : 0;
}
else
return m_pFile->Seek((ZIP_FILE_SIZE)lOff, CZipAbstractFile::current);
@@ -586,30 +740,51 @@ ULONGLONG CZipStorage::Seek(ULONGLONG lOff, SeekType iSeekType)
{
if (m_uCurrentVolume == 0 && m_uBytesBeforeZip > 0)
lOff += m_uBytesBeforeZip;
- return m_pFile->Seek((ZIP_FILE_USIZE)lOff, iSeekType == seekFromBeginning);
+ return m_pFile->SafeSeek((ZIP_FILE_USIZE)lOff, iSeekType == seekFromBeginning);
}
}
void CZipStorage::FinalizeSegm()
{
- ASSERT(IsSegmented() == 1); // spanned archive in creation
- ASSERT(!m_bInMemory);
+ ASSERT(IsNewSegmented()); // spanned archive in creation
CZipString szFileName;
- if (IsSplit() && m_bNewSegm)
+ if (IsSplit())
+ {
+ // the file is already closed
szFileName = RenameLastFileInSplitArchive();
+ if (IsBinarySplit() && m_uCurrentVolume != 0)
+ {
+ ZIP_SIZE_TYPE size;
+ ZipPlatform::GetFileSize(szFileName, size);
+ m_pCachedSizes->Add(ZIP_FILE_USIZE(size));
+ }
+ }
else
{
szFileName = m_pFile->GetFilePath();
- // the file is already closed
m_pFile->Close();
}
- m_bNewSegm = false;
- if (m_uCurrentVolume == 0) // one-volume segmented archive was converted to normal archive
- m_iSegmMode = noSegments;
+ m_state.Set(stateExisting);
+ if (m_uCurrentVolume == 0) // one-volume segmented archive was converted to a normal archive
+ {
+ if (IsSplit())
+ {
+ ClearSplitNames();
+ if (IsBinarySplit())
+ ClearCachedSizes();
+ }
+ m_state.Clear(stateSplit | stateBinarySplit | stateSpan);
+ }
else
+ {
m_uSplitData = m_uCurrentVolume;
-
- OpenFile(szFileName, CZipFile::modeNoTruncate | (m_iSegmMode == noSegments ? CZipFile::modeReadWrite : CZipFile::modeRead));
+ if (IsSplit())
+ {
+ m_szArchiveName = szFileName;
+ }
+ }
+
+ OpenFile(szFileName, CZipFile::modeNoTruncate | (IsSegmented() ? CZipFile::modeReadWrite : CZipFile::modeRead));
}