DragonNest/Common/ZipArchive/ZipStorage.cpp
2024-12-19 09:48:26 +08:00

787 lines
20 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// This source file is part of the ZipArchive library source distribution and
// is Copyrighted 2000 - 2012 by Artpol Software - Tadeusz Dracz
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// For the licensing details refer to the License.txt file.
//
// Web Site: http://www.artpol-software.com
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ZipStorage.h"
#include "ZipArchive.h"
#include "ZipPlatform.h"
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;
CZipStorage::CZipStorage()
{
Initialize();
}
void CZipStorage::Initialize()
{
m_pSplitChangeVolumeFunc = m_pSpanChangeVolumeFunc = m_pChangeVolumeFunc = NULL;
m_iWriteBufferSize = 65536;
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)
{
if (iSize == 0)
return 0;
DWORD iRead;
for(;;)
{
iRead = m_pFile->Read(pBuf, iSize);
if (!iRead)
{
if (IsSegmented())
ChangeVolume();
else
ThrowError(CZipException::badZipFile);
}
else
break;
}
if (iRead == iSize)
return iRead;
else if ((bAtOnce && !IsBinarySplit()) || !IsSegmented())
ThrowError(CZipException::badZipFile);
while (iRead < iSize)
{
ChangeVolume();
UINT iNewRead = m_pFile->Read((char*)pBuf + iRead, iSize - iRead);
if (!iNewRead && iRead < iSize)
ThrowError(CZipException::badZipFile);
iRead += iNewRead;
}
return iRead;
}
void CZipStorage::Open(LPCTSTR lpszPathName, int iMode, ZIP_SIZE_TYPE uVolumeSize)
{
m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
m_pWriteBuffer.Allocate(m_iWriteBufferSize);
m_uBytesInWriteBuffer = 0;
m_state.Set(stateOpened | stateAutoClose);
m_pFile = &m_internalfile;
m_szArchiveName = lpszPathName;
m_pChangeVolumeFunc = NULL;
CBitFlag mode(iMode);
if (mode.IsSetAny(CZipArchive::zipCreate)) // create new archive
{
m_uCurrentVolume = 0;
if (!mode.IsSetAny(CZipArchive::zipModeSegmented))
{
OpenFile(lpszPathName, (mode.IsSetAll(CZipArchive::zipCreateAppend) ? CZipFile::modeNoTruncate : CZipFile::modeCreate) | CZipFile::modeReadWrite);
}
else // create a segmented archive
{
m_uBytesWritten = 0;
if (mode.IsSetAny(CZipArchive::zipModeSpan))
{
if (!m_pSpanChangeVolumeFunc)
ThrowError(CZipException::noCallback);
if (!ZipPlatform::IsDriveRemovable(lpszPathName))
ThrowError(CZipException::nonRemovable);
m_state.Set(stateSpan);
m_pChangeVolumeFunc = m_pSpanChangeVolumeFunc;
}
else if (uVolumeSize <= 0)
ThrowError(CZipException::noVolumeSize);
else
{
m_uSplitData = uVolumeSize;
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;
}
NextVolume(4);
Write(m_gszExtHeaderSignat, 4, true);
}
}
else // open existing
{
m_state.Set(stateExisting);
bool readOnly = mode.IsSetAll(CZipArchive::zipOpenReadOnly);
if (readOnly)
m_state.Set(stateReadOnly);
OpenFile(lpszPathName, CZipFile::modeNoTruncate |
(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, bool bAutoClose)
{
m_pWriteBuffer.Allocate(m_iWriteBufferSize);
m_uBytesInWriteBuffer = 0;
m_state.Set(stateOpened);
if (bAutoClose)
m_state.Set(stateAutoClose);
m_pFile = &af;
CBitFlag mode(iMode);
if (mode.IsSetAny(CZipArchive::zipCreate))
{
m_uCurrentVolume = 0;
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();
}
}
void CZipStorage::ChangeVolume(ZIP_VOLUME_TYPE uNumber)
{
if (uNumber == m_uCurrentVolume || !IsSegmented()) // the second condition may happen in some bad archives
return;
m_uCurrentVolume = uNumber;
OpenFile(IsSpanned() ? ChangeSpannedRead() : ChangeSplitRead(),
CZipFile::modeNoTruncate | CZipFile::modeRead);
}
void CZipStorage::ThrowError(int err) const
{
CZipException::Throw(err, m_pFile->GetFilePath());
}
bool CZipStorage::OpenFile(LPCTSTR lpszName, UINT uFlags, bool bThrow)
{
return m_pFile->Open(lpszName, uFlags | CZipFile::shareDenyWrite, bThrow);
}
CZipString CZipStorage::ChangeSpannedRead()
{
CZipString szTemp = m_pFile->GetFilePath();
m_pFile->Close();
CallCallback(0, CZipSegmCallback::scVolumeNeededForRead, szTemp);
return m_pChangeVolumeFunc->m_szExternalFile;
}
CZipString CZipStorage::ChangeSplitRead()
{
bool lastPart = (ZIP_SIZE_TYPE)m_uCurrentVolume == m_uSplitData;
CZipString szVolumeName = GetSplitVolumeName(lastPart);
if (m_pChangeVolumeFunc)
{
int iCode = CZipSegmCallback::scVolumeNeededForRead;
for(;;)
{
CallCallback(lastPart ? ZIP_SPLIT_LAST_VOLUME : 0, iCode, szVolumeName);
if (ZipPlatform::FileExists(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 szVolumeName;
}
CZipString CZipStorage::RenameLastFileInSplitArchive()
{
ASSERT(IsSplit());
// give to the last volume the zip extension
CZipString szFileName = m_pFile->GetFilePath();
CZipString szNewFileName = GetSplitVolumeName(true);
if (m_pChangeVolumeFunc)
{
int code = CZipSegmCallback::scVolumeNeededForWrite;
for(;;)
{
CallCallback(ZIP_SPLIT_LAST_VOLUME, code, szNewFileName);
szNewFileName = m_pChangeVolumeFunc->m_szExternalFile;
if (ZipPlatform::FileExists(szNewFileName))
code = CZipSegmCallback::scFileNameDuplicated;
else
break;
}
}
m_pFile->Flush();
m_pFile->Close();
ZIPSTRINGCOMPARE pCompare = GetCZipStrCompFunc(ZipPlatform::GetSystemCaseSensitivity());
if ((szFileName.*(pCompare))(szNewFileName) == 0)
{
return szNewFileName;
}
if (!m_pChangeVolumeFunc && ZipPlatform::FileExists(szNewFileName))
{
ZipPlatform::RemoveFile(szNewFileName);
}
ZipPlatform::RenameFile(szFileName, szNewFileName);
return szNewFileName;
}
CZipString CZipStorage::Close(bool bWrite, bool bGetLastVolumeName)
{
bool bClose = true;
CZipString sz;
if (bWrite)
{
Flush();
if (IsSplit() && !IsExisting())
{
sz = RenameLastFileInSplitArchive();
bClose = false;// already closed in RenameLastFileInSplitArchive
}
}
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 (bWrite)
FlushFile();
if (m_state.IsSetAny(stateAutoClose))
m_pFile->Close();
}
m_pWriteBuffer.Release();
m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
m_state = 0;
m_pFile = NULL;
m_uBytesBeforeZip = 0;
ClearSplitNames();
ClearCachedSizes();
return sz;
}
void CZipStorage::NextVolume(ZIP_SIZE_TYPE uNeeded)
{
Flush();
ASSERT(IsSegmented());
bool bSpan = IsSpanned();
if (m_uBytesWritten)
{
m_uBytesWritten = 0;
m_uCurrentVolume++;
ZIP_VOLUME_TYPE uMaxVolumes = (ZIP_VOLUME_TYPE)(bSpan ? 999 : 0xFFFF);
if (m_uCurrentVolume >= uMaxVolumes) // m_uCurrentVolume is a zero-based index
ThrowError(CZipException::tooManyVolumes);
}
CZipString szFileName;
if (bSpan)
szFileName = m_szArchiveName;
else
szFileName = GetSplitVolumeName(false);
if (!m_pFile->IsClosed())
{
m_pFile->Flush();
if (IsBinarySplit())
m_pCachedSizes->Add(m_pFile->GetLength());
m_pFile->Close();
}
if (m_pChangeVolumeFunc)
{
int iCode = CZipSegmCallback::scVolumeNeededForWrite;
for(;;)
{
CallCallback(uNeeded, iCode, szFileName);
// allow changing of the filename
szFileName = m_pChangeVolumeFunc->m_szExternalFile;
if (ZipPlatform::FileExists(szFileName))
iCode = CZipSegmCallback::scFileNameDuplicated;
else
{
if (bSpan)
{
CZipString label;
label.Format(_T("pkback# %.3d"), m_uCurrentVolume + 1);
if (!ZipPlatform::SetVolLabel(szFileName, label))
{
iCode = CZipSegmCallback::scCannotSetVolLabel;
continue;
}
}
if (OpenFile(szFileName, CZipFile::modeCreate | CZipFile::modeReadWrite, false))
break;
else
iCode = CZipSegmCallback::scFileCreationFailure;
}
}
m_uCurrentVolSize = bSpan ? GetFreeVolumeSpace() : m_uSplitData;
}
else
{
if (bSpan)
ThrowError(CZipException::internalError);
m_uCurrentVolSize = m_uSplitData;
OpenFile(szFileName, CZipFile::modeCreate | CZipFile::modeReadWrite);
}
}
void CZipStorage::CallCallback(ZIP_SIZE_TYPE uNeeded, int iCode, CZipString szTemp)
{
if (!m_pChangeVolumeFunc)
ThrowError(CZipException::internalError);
m_pChangeVolumeFunc->m_szExternalFile = szTemp;
m_pChangeVolumeFunc->m_uVolumeNeeded = (ZIP_VOLUME_TYPE)(m_uCurrentVolume + 1);
m_pChangeVolumeFunc->m_iCode = iCode;
if (!m_pChangeVolumeFunc->Callback(uNeeded))
CZipException::Throw(CZipException::aborted, szTemp);
}
ZIP_SIZE_TYPE CZipStorage::GetFreeVolumeSpace() const
{
ASSERT (IsSpanned());
CZipString szTemp = m_pFile->GetFilePath();
if (szTemp.IsEmpty()) // called once when creating a segmented archive
return 0;
else
{
CZipPathComponent zpc(szTemp);
ULONGLONG ret = ZipPlatform::GetDeviceFreeSpace(zpc.GetFilePath());
if (ret > (ZIP_SIZE_TYPE)(-1))
return (ZIP_SIZE_TYPE)(-1);
else
return (ZIP_SIZE_TYPE)ret;
}
}
void CZipStorage::UpdateSegmMode(ZIP_VOLUME_TYPE uLastDisk)
{
bool binarySplit = IsBinarySplit();
if (!binarySplit)
m_uCurrentVolume = uLastDisk;
if (uLastDisk > 0 || binarySplit)
{
// segmentation detected
CZipString szFilePath = m_pFile->GetFilePath();
if (!m_state.IsSetAny(stateSegmented))
m_state.Set(ZipPlatform::IsDriveRemovable(szFilePath) ? stateSpan : stateSplit);
if (IsSpanned())
{
if (!m_pSpanChangeVolumeFunc)
ThrowError(CZipException::noCallback);
m_pChangeVolumeFunc = m_pSpanChangeVolumeFunc;
}
else /*if (IsSplit())*/
{
EnsureSplitNames();
if (!binarySplit)
m_uSplitData = uLastDisk; // the last volume
m_pChangeVolumeFunc = m_pSplitChangeVolumeFunc;
}
m_pWriteBuffer.Release(); // no need for this in this case
}
else
// it will clear all segmented flags
m_state.Clear(stateSpan | stateBinarySplit);
}
ZIP_SIZE_TYPE CZipStorage::AssureFree(ZIP_SIZE_TYPE uNeeded)
{
ZIP_SIZE_TYPE uFree;
while ((uFree = VolumeLeft()) < uNeeded)
{
if (IsSplit() && !m_uBytesWritten && !m_uBytesInWriteBuffer)
// in the splitArchive mode, if the size of the archive is less
// than the size of the packet to be written at once,
// increase once the size of the volume
m_uCurrentVolSize = uNeeded;
else
NextVolume(uNeeded);
}
return uFree;
}
void CZipStorage::Write(const void *pBuf, DWORD iSize, bool bAtOnce)
{
if (!IsSegmented())
WriteInternalBuffer((char*)pBuf, iSize);
else
{
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)
{
ZIP_SIZE_TYPE uFree = AssureFree(iNeeded);
DWORD uLeftToWrite = iSize - uTotal;
DWORD uToWrite = uFree < uLeftToWrite ? (DWORD)uFree : uLeftToWrite;
WriteInternalBuffer((char*)pBuf + uTotal, uToWrite);
if (atOnce)
return;
else
uTotal += uToWrite;
}
}
}
void CZipStorage::WriteInternalBuffer(const char *pBuf, DWORD uSize)
{
DWORD uWritten = 0;
while (uWritten < uSize)
{
DWORD uFreeInBuffer = GetFreeInBuffer();
if (uFreeInBuffer == 0)
{
Flush();
uFreeInBuffer = m_pWriteBuffer.GetSize();
}
DWORD uLeftToWrite = uSize - uWritten;
DWORD uToCopy = uLeftToWrite < uFreeInBuffer ? uLeftToWrite : uFreeInBuffer;
memcpy((char*)m_pWriteBuffer + m_uBytesInWriteBuffer, pBuf + uWritten, uToCopy);
uWritten += uToCopy;
m_uBytesInWriteBuffer += uToCopy;
}
}
ZIP_SIZE_TYPE CZipStorage::VolumeLeft() const
{
// for spanned archives m_uCurrentVolSize is updated after each flush()
ZIP_SIZE_TYPE uBytes = m_uBytesInWriteBuffer + (IsSpanned() ? 0 : m_uBytesWritten);
return uBytes > m_uCurrentVolSize ? 0 : m_uCurrentVolSize - uBytes;
}
void CZipStorage::Flush()
{
if (m_uBytesInWriteBuffer)
{
m_pFile->Write(m_pWriteBuffer, m_uBytesInWriteBuffer);
if (IsSegmented())
m_uBytesWritten += m_uBytesInWriteBuffer;
m_uBytesInWriteBuffer = 0;
}
if (IsSpanned())
// after writing it is difficult to predict the free space due to
// 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)
{
m_pFile->SeekToEnd();
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)
{
CZipAutoBuffer buffer(m_iLocateBufferSize);
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 toRead = m_iLocateBufferSize;
while ( position < max )
{
position += toRead;
if ( position > max )
{
int diff = (int) ( position - max );
toRead -= diff;
offset = diff;
position = max;
}
Seek(position, seekFromEnd);
int actuallyRead = m_pFile->Read((char*)buffer + offset, toRead);
if (actuallyRead != toRead)
ThrowError(CZipException::badZipFile);
int pos = m_iLocateBufferSize - 1;
while ( pos >= offset )
{
if ( buffer[pos] == szSignature[leftToFind] )
{
if ( leftToFind == 0 )
return (ZIP_FILE_USIZE)(uFileLength - ( position - ( pos - offset ) ));
if ( !found )
found = true;
leftToFind--;
pos--;
}
else if ( found )
{
leftToFind = SIGNATURE_SIZE - 1;
found = false;
// do not decrease position, the current pos may be the first to find
}
else
pos--;
}
}
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)
{
if (IsExistingSegmented())
{
ZIP_SIZE_TYPE uPosition = (ZIP_SIZE_TYPE)m_pFile->GetPosition();
ZIP_FILE_USIZE uLength = m_pFile->GetLength();
while (uPosition + lOff >= uLength)
{
ZIP_SIZE_TYPE uCanSeek = (ZIP_SIZE_TYPE)(uLength - uPosition);
lOff -= uCanSeek;
ChangeVolume();
uPosition = 0;
uLength = m_pFile->GetLength();
}
return lOff > 0 ? m_pFile->SafeSeek((ZIP_FILE_USIZE)lOff) : 0;
}
else
return m_pFile->Seek((ZIP_FILE_SIZE)lOff, CZipAbstractFile::current);
}
else
{
if (m_uCurrentVolume == 0 && m_uBytesBeforeZip > 0)
lOff += m_uBytesBeforeZip;
return m_pFile->SafeSeek((ZIP_FILE_USIZE)lOff, iSeekType == seekFromBeginning);
}
}
void CZipStorage::FinalizeSegm()
{
ASSERT(IsNewSegmented()); // spanned archive in creation
CZipString szFileName;
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();
m_pFile->Close();
}
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;
if (IsSplit())
{
m_szArchiveName = szFileName;
}
}
OpenFile(szFileName, CZipFile::modeNoTruncate | (IsSegmented() ? CZipFile::modeReadWrite : CZipFile::modeRead));
}