* contrib/hbziparch/_features.h
* contrib/hbziparch/_platform.h
* contrib/hbziparch/Aes.cpp
* contrib/hbziparch/Aes.h
* contrib/hbziparch/BaseLibCompressor.cpp
* contrib/hbziparch/BaseLibCompressor.h
* contrib/hbziparch/BytesWriter.h
* contrib/hbziparch/Bzip2Compressor.cpp
* contrib/hbziparch/Bzip2Compressor.h
* contrib/hbziparch/DeflateCompressor.cpp
* contrib/hbziparch/DeflateCompressor.h
* contrib/hbziparch/DirEnumerator.cpp
* contrib/hbziparch/DirEnumerator.h
* contrib/hbziparch/FileFilter.cpp
* contrib/hbziparch/FileFilter.h
* contrib/hbziparch/FileInfo.h
* contrib/hbziparch/Hmac.cpp
* contrib/hbziparch/Hmac.h
* contrib/hbziparch/RandomPool.cpp
* contrib/hbziparch/RandomPool.h
* contrib/hbziparch/Sha1.cpp
* contrib/hbziparch/Sha1.h
* contrib/hbziparch/std_mfc.h
* contrib/hbziparch/std_stl.h
* contrib/hbziparch/Wildcard.cpp
* contrib/hbziparch/Wildcard.h
* contrib/hbziparch/ZipAbstractFile.h
* contrib/hbziparch/ZipAesCryptograph.cpp
* contrib/hbziparch/ZipAesCryptograph.h
* contrib/hbziparch/ZipArchive.cpp
* contrib/hbziparch/ZipArchive.h
* contrib/hbziparch/ZipAutoBuffer.cpp
* contrib/hbziparch/ZipAutoBuffer.h
* contrib/hbziparch/ZipBaseException.h
* contrib/hbziparch/ZipCallback.h
* contrib/hbziparch/ZipCallbackProvider.h
* contrib/hbziparch/ZipCentralDir.cpp
* contrib/hbziparch/ZipCentralDir.h
* contrib/hbziparch/ZipCollections.h
* contrib/hbziparch/ZipCollections_mfc.h
* contrib/hbziparch/ZipCollections_stl.h
* contrib/hbziparch/ZipCompatibility.cpp
* contrib/hbziparch/ZipCompatibility.h
* contrib/hbziparch/ZipCompressor.cpp
* contrib/hbziparch/ZipCompressor.h
* contrib/hbziparch/ZipCrc32Cryptograph.cpp
* contrib/hbziparch/ZipCrc32Cryptograph.h
* contrib/hbziparch/ZipCryptograph.cpp
* contrib/hbziparch/ZipCryptograph.h
* contrib/hbziparch/ZipException.cpp
* contrib/hbziparch/ZipException.h
* contrib/hbziparch/ZipExtraData.cpp
* contrib/hbziparch/ZipExtraData.h
* contrib/hbziparch/ZipExtraField.cpp
* contrib/hbziparch/ZipExtraField.h
* contrib/hbziparch/ZipFile.h
* contrib/hbziparch/ZipFile_mfc.cpp
* contrib/hbziparch/ZipFile_mfc.h
* contrib/hbziparch/ZipFile_stl.cpp
* contrib/hbziparch/ZipFile_stl.h
* contrib/hbziparch/ZipFileHeader.cpp
* contrib/hbziparch/ZipFileHeader.h
* contrib/hbziparch/ZipFileMapping.h
* contrib/hbziparch/ZipFileMapping_lnx.h
* contrib/hbziparch/ZipFileMapping_win.h
* contrib/hbziparch/ZipMemFile.cpp
* contrib/hbziparch/ZipMemFile.h
* contrib/hbziparch/ZipMutex.h
* contrib/hbziparch/ZipMutex_lnx.h
* contrib/hbziparch/ZipMutex_win.h
* contrib/hbziparch/ZipPathComponent.h
* contrib/hbziparch/ZipPlatform.h
* contrib/hbziparch/ZipPlatformComm.cpp
* contrib/hbziparch/ZipStorage.cpp
* contrib/hbziparch/ZipStorage.h
* contrib/hbziparch/ZipString.h
* contrib/hbziparch/ZipString_mfc.h
* contrib/hbziparch/ZipString_stl.h
* contrib/hbziparch/ZipStringStoreSettings.h
+ ZipArchive lib update finished.
; Pass 2/2
; Please test.
616 lines
16 KiB
C++
616 lines
16 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
|
// This source file is part of the ZipArchive library source distribution and
|
|
// is Copyrighted 2000 - 2007 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);
|
|
|
|
|
|
CZipStorage::CZipStorage()
|
|
{
|
|
Initialize();
|
|
}
|
|
|
|
void CZipStorage::Initialize()
|
|
{
|
|
m_pSplitChangeVolumeFunc = m_pSpanChangeVolumeFunc = m_pChangeVolumeFunc = NULL;
|
|
m_iWriteBufferSize = 65536;
|
|
m_pFile = NULL;
|
|
m_szSplitExtension = _T("zip");
|
|
m_iLocateBufferSize = 32768;
|
|
m_uBytesBeforeZip = 0;
|
|
m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
|
|
m_szArchiveName.Empty();
|
|
}
|
|
|
|
CZipStorage::~CZipStorage()
|
|
{
|
|
|
|
}
|
|
|
|
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 || !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_bNewSegm = false;
|
|
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;
|
|
m_uCurrentVolume = 0;
|
|
if (iMode == CZipArchive::zipCreate || iMode == CZipArchive::zipCreateAppend)
|
|
{
|
|
m_iSegmMode = noSegments;
|
|
OpenFile(lpszPathName, (iMode == CZipArchive::zipCreate ? CZipFile::modeCreate : CZipFile::modeNoTruncate) | CZipFile::modeReadWrite);
|
|
}
|
|
else // create a segmented archive
|
|
{
|
|
m_bNewSegm = true;
|
|
m_uBytesWritten = 0;
|
|
if (uVolumeSize == ZIP_AUTODETECT_VOLUME_SIZE) // spanned archive
|
|
{
|
|
if (!m_pSpanChangeVolumeFunc)
|
|
ThrowError(CZipException::noCallback);
|
|
if (!ZipPlatform::IsDriveRemovable(lpszPathName))
|
|
ThrowError(CZipException::nonRemovable);
|
|
m_iSegmMode = spannedArchive;
|
|
m_pChangeVolumeFunc = m_pSpanChangeVolumeFunc;
|
|
}
|
|
else
|
|
{
|
|
m_uSplitData = uVolumeSize;
|
|
m_iSegmMode = splitArchive;
|
|
m_pChangeVolumeFunc = m_pSplitChangeVolumeFunc;
|
|
}
|
|
|
|
NextVolume(4);
|
|
Write(m_gszExtHeaderSignat, 4, true);
|
|
}
|
|
}
|
|
else // open existing
|
|
{
|
|
m_bReadOnly = iMode == CZipArchive::zipOpenReadOnly;
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CZipStorage::Open(CZipAbstractFile& af, int iMode)
|
|
{
|
|
m_pWriteBuffer.Allocate(m_iWriteBufferSize);
|
|
m_uBytesInWriteBuffer = 0;
|
|
m_bNewSegm = false;
|
|
m_pFile = ⁡
|
|
m_bInMemory = true;
|
|
|
|
if (iMode == CZipArchive::zipCreate || iMode == CZipArchive::zipCreateAppend)
|
|
{
|
|
m_uCurrentVolume = 0;
|
|
m_iSegmMode = noSegments;
|
|
if (iMode == CZipArchive::zipCreate)
|
|
af.SetLength(0);
|
|
else
|
|
af.SeekToEnd();
|
|
}
|
|
else // open existing
|
|
{
|
|
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
|
|
return;
|
|
|
|
m_uCurrentVolume = uNumber;
|
|
OpenFile(IsSpanned() ? ChangeSpannedRead() : ChangeSplitRead(),
|
|
CZipFile::modeNoTruncate | CZipFile::modeRead);
|
|
}
|
|
|
|
void CZipStorage::ThrowError(int err)
|
|
{
|
|
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 szTemp;
|
|
}
|
|
|
|
CZipString CZipStorage::ChangeSplitRead()
|
|
{
|
|
bool lastPart = (ZIP_SIZE_TYPE)m_uCurrentVolume == m_uSplitData;
|
|
CZipString szTemp = GetSplitVolumeName(lastPart);
|
|
if (m_pChangeVolumeFunc)
|
|
{
|
|
int iCode = CZipSegmCallback::scVolumeNeededForRead;
|
|
for(;;)
|
|
{
|
|
CallCallback(lastPart ? ZIP_SPLIT_LAST_VOLUME : 0, iCode, szTemp);
|
|
if (ZipPlatform::FileExists(m_pChangeVolumeFunc->m_szExternalFile))
|
|
{
|
|
szTemp = m_pChangeVolumeFunc->m_szExternalFile;
|
|
break;
|
|
}
|
|
else
|
|
iCode = CZipSegmCallback::scFileNotFound;
|
|
}
|
|
}
|
|
m_pFile->Close();
|
|
return szTemp;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
if (!m_bInMemory)
|
|
{
|
|
m_pFile->Flush();
|
|
m_pFile->Close();
|
|
}
|
|
if (!m_pChangeVolumeFunc && ZipPlatform::FileExists(szNewFileName))
|
|
ZipPlatform::RemoveFile(szNewFileName);
|
|
ZipPlatform::RenameFile(szFileName, szNewFileName);
|
|
return szNewFileName;
|
|
}
|
|
|
|
CZipString CZipStorage::Close(bool bAfterException)
|
|
{
|
|
bool bClose = true;
|
|
CZipString sz;
|
|
if (!bAfterException)
|
|
{
|
|
Flush();
|
|
if (IsSplit() && m_bNewSegm)
|
|
{
|
|
sz = RenameLastFileInSplitArchive();
|
|
bClose = false;// already closed in RenameLastFileInSplitArchive
|
|
}
|
|
}
|
|
if (sz.IsEmpty())
|
|
sz = m_pFile->GetFilePath();
|
|
if (bClose && !m_bInMemory)
|
|
{
|
|
if (!bAfterException)
|
|
FlushFile();
|
|
m_pFile->Close();
|
|
}
|
|
|
|
m_pWriteBuffer.Release();
|
|
m_uCurrentVolume = ZIP_VOLUME_NUMBER_UNSPECIFIED;
|
|
m_iSegmMode = noSegments;
|
|
m_pFile = NULL;
|
|
m_uBytesBeforeZip = 0;
|
|
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);
|
|
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();
|
|
m_pFile->Close();
|
|
}
|
|
|
|
if (m_pChangeVolumeFunc)
|
|
{
|
|
int iCode = CZipSegmCallback::scVolumeNeededForWrite;
|
|
for(;;)
|
|
{
|
|
CallCallback(uNeeded, iCode, szFileName);
|
|
if (!bSpan)
|
|
// allow the user to change 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)
|
|
{
|
|
m_uCurrentVolume = uLastDisk;
|
|
if (uLastDisk)
|
|
{
|
|
// 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 (IsSpanned())
|
|
{
|
|
if (!m_pSpanChangeVolumeFunc)
|
|
ThrowError(CZipException::noCallback);
|
|
m_pChangeVolumeFunc = m_pSpanChangeVolumeFunc;
|
|
}
|
|
else /*if (IsSplit())*/
|
|
{
|
|
m_uSplitData = uLastDisk; // volume with .zip extension ( the last one)
|
|
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;
|
|
|
|
}
|
|
|
|
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
|
|
{
|
|
// if not at once, one byte is enough free space
|
|
DWORD iNeeded = bAtOnce ? 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 (bAtOnce)
|
|
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 (m_iSegmMode != noSegments)
|
|
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();
|
|
|
|
}
|
|
|
|
ZIP_FILE_USIZE CZipStorage::LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMaxDepth)
|
|
{
|
|
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;
|
|
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 = recordSize - 1;
|
|
found = false;
|
|
// do not decrease position, the current pos may be the first to find
|
|
}
|
|
else
|
|
pos--;
|
|
}
|
|
}
|
|
return SignatureNotFound;
|
|
}
|
|
|
|
ULONGLONG CZipStorage::Seek(ULONGLONG lOff, SeekType iSeekType)
|
|
{
|
|
if (iSeekType == seekCurrent)
|
|
{
|
|
ZIP_SIZE_TYPE uPosition = (ZIP_SIZE_TYPE)m_pFile->GetPosition();
|
|
if (IsSegmented() == -1)
|
|
{
|
|
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->Seek((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->Seek((ZIP_FILE_USIZE)lOff, iSeekType == seekFromBeginning);
|
|
}
|
|
}
|
|
|
|
void CZipStorage::FinalizeSegm()
|
|
{
|
|
ASSERT(IsSegmented() == 1); // spanned archive in creation
|
|
ASSERT(!m_bInMemory);
|
|
|
|
CZipString szFileName;
|
|
if (IsSplit() && m_bNewSegm)
|
|
szFileName = RenameLastFileInSplitArchive();
|
|
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;
|
|
else
|
|
m_uSplitData = m_uCurrentVolume;
|
|
|
|
OpenFile(szFileName, CZipFile::modeNoTruncate | (m_iSegmMode == noSegments ? CZipFile::modeReadWrite : CZipFile::modeRead));
|
|
}
|
|
|