summaryrefslogtreecommitdiff
path: root/zip/ZipArchive/ZipStorage.h
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@redhat.com>2023-12-17 21:23:58 +0100
committerTomas Bzatek <tbzatek@redhat.com>2023-12-17 21:23:58 +0100
commit02d6107c97b48888362e7c6a70dcac323c89d741 (patch)
tree5069a77adaf73f7249ac79b6c49a47168a647ef8 /zip/ZipArchive/ZipStorage.h
parent4e17c2527b106f1b493a3ac77c89858d14f834e2 (diff)
downloadtuxcmd-modules-02d6107c97b48888362e7c6a70dcac323c89d741.tar.xz
ZipArchive: Update to the 4.6.9 release
Diffstat (limited to 'zip/ZipArchive/ZipStorage.h')
-rw-r--r--zip/ZipArchive/ZipStorage.h472
1 files changed, 316 insertions, 156 deletions
diff --git a/zip/ZipArchive/ZipStorage.h b/zip/ZipArchive/ZipStorage.h
index 686751c..cc1569e 100644
--- a/zip/ZipArchive/ZipStorage.h
+++ b/zip/ZipArchive/ZipStorage.h
@@ -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
////////////////////////////////////////////////////////////////////////////////
/**
@@ -35,48 +35,36 @@
#include "ZipMemFile.h"
#include "ZipExport.h"
#include "ZipCallback.h"
-
-
+#include "BitFlag.h"
+#include "ZipSplitNamesHandler.h"
+#include "ZipException.h"
+#include "ZipCollections.h"
/**
Represents the storage layer for an archive.
*/
-class ZIP_API CZipStorage
+class ZIP_API CZipStorage
{
friend class CZipArchive;
friend class CZipCentralDir;
public:
-
/**
- The type of the segmentation of the archive.
-
- \see
- <a href="kb">0610051553</a>
- \see
- CZipArchive::GetSegmMode
+ Storage state.
*/
- enum ZipSegmentationMode
+ enum State
{
- noSegments, ///< No archive segmentation.
- spannedArchive, ///< A spanned archive.
- splitArchive, ///< A split archive.
-
- /**
- The archive segmentation type will be auto-detected.
- If the archive is on the removable device,
- assume a spanned archive, otherwise assume a split archive.
- */
- suggestedAuto,
-
- /**
- If a segmented archive is on a removable device, assume a split archive.
- Normally you create spanned archives on removable devices.
- */
- suggestedSplit
- };
+ stateOpened = 0x0001, ///< The storage file is opened.
+ stateReadOnly = 0x0002, ///< The storage file is opened as read-only.
+ stateAutoClose = 0x0004, ///< The storage file will be closed when the storage is closed.
+ stateExisting = 0x0008, ///< The storage file existed before opening.
+ stateSegmented = 0x0010, ///< The current archive is segmented.
+ stateSplit = stateSegmented | 0x0020, ///< The current archive is split.
+ stateBinarySplit = stateSplit | 0x0040, ///< The current archive is binary split.
+ stateSpan = stateSegmented | 0x0080 ///< The current archive is spanned.
+ };
/**
- The direction of seeking operation.
+ The direction of the seeking operation.
\see
CZipStorage::Seek
@@ -86,20 +74,23 @@ public:
seekFromBeginning, ///< Start seeking from the beginning of a file.
seekFromEnd, ///< Start seeking from the end of a file.
/**
- Start seeking from the current position in an archive.
+ Start seeking from the current position in the archive.
This value can cause a volume change when a segmented archive is opened for reading.
*/
seekCurrent
};
+
+ static const ZIP_FILE_USIZE SignatureNotFound;
+
CZipStorage();
virtual ~CZipStorage();
void Initialize();
/**
Opens a new or existing archive in memory.
- The meaning for the parameters is the same as in the CZipArchive::Open(CZipAbstractFile& , int) method.
+ The meaning for the parameters is the same as in the CZipArchive::Open(CZipAbstractFile& , int, bool) method.
*/
- void Open(CZipAbstractFile& af, int iMode);
+ void Open(CZipAbstractFile& af, int iMode, bool bAutoClose);
/**
Opens or creates an archive.
@@ -108,9 +99,35 @@ public:
*/
void Open(LPCTSTR lpszPathName, int iMode, ZIP_SIZE_TYPE uVolumeSize);
+
+ /**
+ Gets the expected path of a volume name in a split archive.
+
+ \param uVolume
+ The volume's zero-based index.
+
+ \param bLast
+ If \c true, the volume is expected to be the last volume; \c false otherwise.
+
+ \return
+ The expected path of a volume name in a split archive.
+ */
+ CZipString GetSplitVolumeName(ZIP_VOLUME_TYPE uVolume, bool bLast)
+ {
+ if (m_pSplitNames == NULL)
+ {
+ ThrowError(CZipException::genericError);
+ return _T(""); // for Code Analysis
+ }
+ int flags = bLast ? CZipSplitNamesHandler::flLast : CZipSplitNamesHandler::flNone;
+ if (IsExisting())
+ flags |= CZipSplitNamesHandler::flExisting;
+ return m_pSplitNames->GetVolumeName(m_szArchiveName, (ZIP_VOLUME_TYPE)(uVolume + 1), flags);
+ }
/**
- Closes a segmented archive in creation and reopens it as an existing segmented archive (no modifications allowed).
+ Closes a segmented archive in creation and reopens it as an existing segmented archive.
+ No modifications are allowed afterwards.
The archive may also turn out to be a not segmented archive.
*/
void FinalizeSegm();
@@ -120,10 +137,7 @@ public:
Called only by CZipCentralDir::Read when opening an existing archive.
\param uLastVolume
- The number of the volme the central directory is on.
-
- \note Throws exceptions.
-
+ The number of the volume the central directory is on.
*/
void UpdateSegmMode(ZIP_VOLUME_TYPE uLastVolume);
@@ -136,8 +150,6 @@ public:
\return
The number of free bytes on the current volume.
- \note
- Throws exceptions.
*/
ZIP_SIZE_TYPE AssureFree(ZIP_SIZE_TYPE uNeeded);
@@ -154,13 +166,11 @@ public:
If \c true, the whole chunk must fit in the current volume.
If there is not enough free space, a volume change is performed.
- \note
- Throws exceptions.
*/
void Write(const void *pBuf, DWORD iSize, bool bAtOnce);
/**
- Gets the total size currently occupied by the archive.
+ Returns the total size currently occupied by the archive.
\return
The length of the current archive file increased by the number of bytes in the write buffer.
@@ -176,9 +186,10 @@ public:
bool IsClosed(bool bArchive) const
{
if (bArchive)
- return GetCurrentVolume() == ZIP_VOLUME_NUMBER_UNSPECIFIED;
+ return !m_state.IsSetAny(stateOpened);
else
- return !m_pFile || !m_bInMemory && m_pFile->IsClosed();
+ // assume not auto-close files always opened
+ return !m_pFile || (m_state.IsSetAny(stateAutoClose) && m_pFile->IsClosed());
}
/**
@@ -191,29 +202,38 @@ public:
The number of bytes to read.
\param bAtOnce
- If \c true, the specified number of bytes must be read
- from the same volume (no volume change is allowed).
+ If \c true, no volume change is allowed during reading.
+ If the requested number of bytes cannot be read from a single volume, an exception is thrown.
- \note
- Throws exceptions.
*/
DWORD Read(void* pBuf, DWORD iSize, bool bAtOnce);
/**
- Gets the position in the file, taking into account the number of bytes in the write buffer
- and the number of bytes before the archive.
+ Returns the position in the file, taking into account the number of bytes in the write buffer
+ and the number of bytes before the archive.
\return
The position in the file.
\note
- Throws exceptions.
+ For binary split archives, it returns the position from the beginning of the first part.
*/
ZIP_SIZE_TYPE GetPosition() const
{
ZIP_SIZE_TYPE uPos = (ZIP_SIZE_TYPE)(m_pFile->GetPosition()) + m_uBytesInWriteBuffer;
if (m_uCurrentVolume == 0)
uPos -= m_uBytesBeforeZip;
+ else if (IsBinarySplit()) // not for the first volume
+ {
+ ZIP_VOLUME_TYPE uVolume = m_uCurrentVolume;
+ ASSERT(m_pCachedSizes->GetSize() > (ZIP_ARRAY_SIZE_TYPE)(uVolume - 1));
+ do
+ {
+ uVolume--;
+ uPos += (ZIP_SIZE_TYPE)m_pCachedSizes->GetAt((ZIP_ARRAY_SIZE_TYPE)uVolume);
+ }
+ while (uVolume > 0);
+ }
return uPos;
}
@@ -221,8 +241,6 @@ public:
/**
Flushes the data from the read buffer to the disk.
- \note
- Throws exceptions.
*/
void Flush();
@@ -232,7 +250,7 @@ public:
*/
void FlushFile()
{
- if (!m_bInMemory && !IsReadOnly())
+ if (!IsReadOnly())
m_pFile->Flush();
}
@@ -248,14 +266,12 @@ public:
\param uNeeded
The number of bytes needed in the volume.
- \note
- Throws exceptions.
*/
void NextVolume(ZIP_SIZE_TYPE uNeeded);
/**
- Gets a zero-based number of the current volume.
+ Returns a zero-based number of the current volume.
*/
ZIP_VOLUME_TYPE GetCurrentVolume() const {return m_uCurrentVolume;}
@@ -277,46 +293,156 @@ public:
}
/**
- Detects the segmentation mode.
-
- \return
- - \c -1 : An existing segmented archive is opened.
- - \c 0 : The archive is not segmented.
- - \c 1 : A segmented archive in creation.
+ Changes the current volume to the previous volume during extract operations.
*/
- int IsSegmented() const
+ void ChangeVolumeDec()
{
- return m_iSegmMode == noSegments ? 0 : (m_bNewSegm ? 1 : -1);
+ if (m_uCurrentVolume == 0)
+ ThrowError(CZipException::badZipFile);
+ ChangeVolume((ZIP_VOLUME_TYPE)(m_uCurrentVolume - 1));
}
-
+
/**
- Checks, if the archive is a split archive.
+ Returns the value indicating whether the archive is a split archive (binary or regular).
\return
\c true, if the archive is a split archive; \c false otherwise.
*/
bool IsSplit() const
{
- return m_iSegmMode == splitArchive;
+ return m_state.IsSetAll(stateSplit);
+ }
+
+ /**
+ Returns the value indicating whether the archive is a binary split archive.
+
+ \return
+ \c true, if the archive is a binary split archive; \c false otherwise.
+ */
+ bool IsBinarySplit() const
+ {
+ return m_state.IsSetAll(stateBinarySplit);
+ }
+
+ /**
+ Returns the value indicating whether the archive is a regular split archive (not binary).
+
+ \return
+ \c true, if the archive is a regular split archive; \c false otherwise.
+ */
+ bool IsRegularSplit() const
+ {
+ return m_state.IsSetAll(stateSplit) && !m_state.IsSetAll(stateBinarySplit);
}
/**
- Checks, if the archive is a spanned archive.
+ Returns the value indicating whether the archive is a spanned archive.
\return
\c true, if the archive is a spanned archive; \c false otherwise.
*/
bool IsSpanned() const
{
- return m_iSegmMode == spannedArchive;
+ return m_state.IsSetAll(stateSpan);
}
/**
The same as the CZipArchive::IsReadOnly method.
*/
- bool IsReadOnly()
+ bool IsReadOnly() const
{
- return m_bReadOnly || IsSegmented() < 0;
+ return m_state.IsSetAny(stateReadOnly) || IsExistingSegmented();
+ }
+
+ /**
+ Returns the value indicating whether the archive is an existing segmented archive.
+
+ \return
+ \c true, if the archive is an existing segmented archive; \c false otherwise.
+ */
+ bool IsExistingSegmented() const
+ {
+ return m_state.IsSetAll(stateSegmented | stateExisting);
+ }
+
+ /**
+ Returns the value indicating whether the archive is a new segmented archive.
+
+ \return
+ \c true, if the archive is a new segmented archive; \c false otherwise.
+ */
+ bool IsNewSegmented() const
+ {
+ return m_state.IsSetAny(stateSegmented) && !IsExisting();
+ }
+
+ /**
+ Returns the value indicating whether the archive is a segmented archive.
+
+ \return
+ \c true, if the archive is a segmented archive; \c false otherwise.
+ */
+ bool IsSegmented() const
+ {
+ return m_state.IsSetAny(stateSegmented);
+ }
+
+ /**
+ Returns the value indicating whether the archive is an existing archive.
+
+ \return
+ \c true, if the archive is an existing archive; \c false, if the archive is a new archive.
+ */
+ bool IsExisting() const
+ {
+ return m_state.IsSetAny(stateExisting);
+ }
+
+ /**
+ Sets the split names handler.
+
+ \see
+ CZipArchive::SetSplitNamesHandler(CZipSplitNamesHandler*, bool)
+ \see
+ CZipSplitNamesHandler
+ */
+ bool SetSplitNamesHandler(CZipSplitNamesHandler* pNames, bool bAutoDelete)
+ {
+ if (m_state != 0)
+ {
+ ZIPTRACE("%s(%i) : The archive is already opened.\n");
+ return false;
+ }
+ ClearSplitNames();
+ m_pSplitNames = pNames;
+ m_bAutoDeleteSplitNames = bAutoDelete;
+ return true;
+ }
+
+ /**
+ Returns the current split names handler.
+
+ \return
+ The current split names handler.
+ \see
+ CZipSplitNamesHandler
+ */
+ CZipSplitNamesHandler* GetSplitNamesHandler()
+ {
+ return m_pSplitNames;
+ }
+
+ /**
+ Returns the current split names handler (const).
+
+ \return
+ The current split names handler.
+ \see
+ CZipSplitNamesHandler
+ */
+ const CZipSplitNamesHandler* GetSplitNamesHandler() const
+ {
+ return m_pSplitNames;
}
/**
@@ -332,7 +458,19 @@ public:
ULONGLONG Seek(ULONGLONG lOff, SeekType iSeekType = seekFromBeginning);
/**
- Gets the number of free bytes on the current volume.
+ Performs the seeking operation in a binary split archive.
+
+ \param lOff
+ The offset to move the file pointer.
+
+ \param bSeekToBegin
+ If \c true, the file pointer is moved to the beginning before seeking.
+ If \c false, the file pointer is moved relatively to the current position.
+ */
+ void SeekInBinary(ZIP_FILE_SIZE lOff, bool bSeekToBegin = false);
+
+ /**
+ Returns the number of free bytes on the current volume.
\return
The number of free bytes on the current volume.
@@ -342,19 +480,20 @@ public:
/**
Closes the storage.
- \param bAfterException
- Set to \c true, if an exception was thrown before.
+ \param bWrite
+ Set to \c false, if the storage should not perform any write operations.
+ \param bGetLastVolumeName
+ Set to \c true, if the storage should return the path.
\return
- The file path of the archive.
+ The file path of the archive or of the last volume in the archive.
+ Only if \a bGetLastVolumeName is set to \c true.
- \note
- Throws exceptions.
*/
- CZipString Close(bool bAfterException);
+ CZipString Close(bool bWrite, bool bGetLastVolumeName = false);
/**
- Represents the physical storage of the current archive segment.
+ Represents the physical storage for the archive (or the current archive segment in segmented archives).
*/
CZipAbstractFile* m_pFile;
@@ -363,6 +502,26 @@ public:
*/
static char m_gszExtHeaderSignat[];
+ ZipArchiveLib::CBitFlag& GetState()
+ {
+ return m_state;
+ }
+
+ /**
+ Reverse-finds the location of the given signature starting from the current position in file.
+
+ \param szSignature
+ The signature to locate.
+
+ \param uMaxDepth
+ The maximum number of bytes to search for \a szSignature.
+
+ \return
+ The location of the signature.
+
+ */
+ ZIP_FILE_USIZE LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMaxDepth);
+
protected:
/**
@@ -375,27 +534,9 @@ protected:
{
return (ZIP_SIZE_TYPE)m_pFile->GetLength() - m_uBytesBeforeZip;
}
-
- /**
- Reverse-finds the location of the given signature starting from the current position in file.
-
- \param szSignature
- The signature to locate.
-
- \param uMaxDepth
- The maximum number of bytes to search for \a szSignature.
-
- \return
- The location of the signature.
-
- \note
- Throws exceptions.
- */
- ZIP_FILE_USIZE LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMaxDepth);
-
/**
- Flushes without writing. Can be used only on not segmented archives.
+ Flushes without writing. It can be used only on not segmented archives.
*/
void EmptyWriteBuffer()
{
@@ -420,7 +561,7 @@ protected:
bool OpenFile(LPCTSTR lpszName, UINT uFlags, bool bThrow = true);
/**
- Renames the last segment file in a split archive when finalizing the whole archive.
+ Renames the last segment file in a split archive when finalizing the archive.
\return
The name of the last segment.
@@ -436,13 +577,11 @@ protected:
\param uSize
The number of bytes to write.
- \note
- Throws exceptions.
*/
void WriteInternalBuffer(const char *pBuf, DWORD uSize);
/**
- Gets the free space size on the current removable disk.
+ Returns the free space size on the current removable disk.
\return
The free space in bytes.
@@ -450,7 +589,7 @@ protected:
ZIP_SIZE_TYPE GetFreeVolumeSpace() const;
/**
- Notifies the callback object.
+ Calls the segmented callback object.
Throws an exception if the callback method returns \c false.
\param uNeeded
@@ -463,25 +602,12 @@ protected:
The string to be used as a filename (as an argument
in the CZipException::Throw method) when an exception must be thrown.
- \note
- Throws exceptions.
- \see
+ \see
CZipArchive::SetSegmCallback
*/
void CallCallback(ZIP_SIZE_TYPE uNeeded, int iCode, CZipString szTemp);
/**
- Constructs the name of a segment in a split archive.
-
- \param bLast
- Set it to \c true, if constructing the last volume name.
-
- \return
- The segment name.
- */
- CZipString GetSplitVolumeName(bool bLast) const;
-
- /**
Changes a file when processing a split archive.
*/
CZipString ChangeSplitRead();
@@ -492,35 +618,30 @@ protected:
CZipString ChangeSpannedRead();
/**
- Gets the free space left in the write buffer.
+ Returns the free space left in the write buffer.
\return
- The free space left in the write buffer in bytes.
+ The free space in bytes.
*/
DWORD GetFreeInBuffer() const {return m_pWriteBuffer.GetSize() - m_uBytesInWriteBuffer;}
/**
The value it holds, depends on the current mode:
- - An opened existing split archive - stores the number of the last volume ( the one with "zip" extension).
- - A split archive in creation - the size of the volume.
+ - An opened existing split archive: the number of the last volume ( usually the one with the "zip" extension).
+ - A split archive in creation: the size of the volume.
This method is used only when processing split archives.
*/
ZIP_SIZE_TYPE m_uSplitData;
/**
- The extension of the last segment.
- */
- CZipString m_szSplitExtension;
-
- /**
The number of bytes available in the write buffer.
*/
DWORD m_uBytesInWriteBuffer;
/**
The value it holds depends on the segmentation mode:
- - A split archive : the total size of the current volume.
+ - A split archive: the total size of the current volume.
- A spanned archive: the free space on the current volume.
*/
ZIP_SIZE_TYPE m_uCurrentVolSize;
@@ -534,29 +655,14 @@ protected:
Stores the number of bytes that have been written physically to the current segment.
Used only when processing a segmented archive in creation.
*/
- ZIP_SIZE_TYPE m_uBytesWritten;
-
- /**
- \c true, if the current archive is a new segmented archive; \c false otherwise.
- */
- bool m_bNewSegm;
+ ZIP_SIZE_TYPE m_uBytesWritten;
/**
The current volume number in a segmented archive.
The value is zero-based.
*/
ZIP_VOLUME_TYPE m_uCurrentVolume;
-
- /**
- \c true when the archive is created in memory; \c false otherwise.
- */
- bool m_bInMemory;
-
- /**
- \c true if OpenMode::zipOpenReadOnly was specified when opening the archive.
- */
- bool m_bReadOnly;
-
+
/**
The number of bytes before the actual zip archive in a file.
\see
@@ -579,12 +685,7 @@ protected:
\see
CZipArchive::SetAdvanced
*/
- int m_iLocateBufferSize;
-
- /**
- Takes one of the #ZipSegmentationMode values.
- */
- int m_iSegmMode;
+ int m_iLocateBufferSize;
/**
A callback object called when there is a need for a volume change
@@ -603,12 +704,71 @@ protected:
CZipArchive::SetSegmCallback
*/
CZipSegmCallback* m_pSplitChangeVolumeFunc;
+
private:
+ ZIP_FILE_USIZE LocateSignature(char* szSignature, ZIP_SIZE_TYPE uMaxDepth, int& leftToFind, bool& found, ZIP_FILE_USIZE uFileLength);
+
+ CZipString GetSplitVolumeName(bool bLast)
+ {
+ return GetSplitVolumeName(m_uCurrentVolume, bLast);
+ }
+
+ void ClearSplitNames()
+ {
+ if (m_pSplitNames)
+ {
+ if (m_bAutoDeleteSplitNames)
+ delete m_pSplitNames;
+ m_pSplitNames = NULL;
+ m_bAutoDeleteSplitNames = false;
+ }
+ }
+
+ void ClearCachedSizes()
+ {
+ if (m_pCachedSizes)
+ {
+ delete m_pCachedSizes;
+ m_pCachedSizes = NULL;
+ }
+ }
+
+ void EnsureSplitNames()
+ {
+ if (IsSplit())
+ {
+ if (m_pSplitNames == NULL)
+ {
+ m_bAutoDeleteSplitNames = true;
+ if (m_state.IsSetAll(stateBinarySplit))
+ m_pSplitNames = new CZipBinSplitNamesHandler();
+ else
+ m_pSplitNames = new CZipRegularSplitNamesHandler();
+ }
+ m_pSplitNames->Initialize(m_szArchiveName);
+ }
+ }
+
+ ZIP_FILE_USIZE GetCachedSize(ZIP_VOLUME_TYPE uVolume)
+ {
+ ASSERT(m_pCachedSizes);
+ if (m_pCachedSizes->GetSize() > (ZIP_ARRAY_SIZE_TYPE)uVolume)
+ return m_pCachedSizes->GetAt((ZIP_ARRAY_SIZE_TYPE)uVolume);
+ ThrowError(CZipException::genericError);
+ // for a compiler
+ return 0;
+ }
+
+ void CacheSizes();
+
+ ZipArchiveLib::CBitFlag m_state;
CZipSegmCallback* m_pChangeVolumeFunc;
CZipString m_szArchiveName;
CZipFile m_internalfile;
- static const ZIP_FILE_USIZE SignatureNotFound;
- void ThrowError(int err);
+ CZipSplitNamesHandler* m_pSplitNames;
+ CZipArray<ZIP_FILE_USIZE>* m_pCachedSizes;
+ bool m_bAutoDeleteSplitNames;
+ void ThrowError(int err) const;
};
#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL)