diff --git a/harbour/ChangeLog b/harbour/ChangeLog index ee16ca018b..a8718fe422 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -8,6 +8,90 @@ 2008-12-31 13:59 UTC+0100 Foo Bar */ +2008-06-24 00:35 UTC+0200 Viktor Szakats (harbour.01 syenar hu) + * 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. + 2008-06-24 00:33 UTC+0200 Viktor Szakats (harbour.01 syenar hu) + contrib/hbziparch/readme.txt + contrib/hbziparch/zlib diff --git a/harbour/contrib/hbziparch/Aes.cpp b/harbour/contrib/hbziparch/Aes.cpp new file mode 100644 index 0000000000..b0870db342 --- /dev/null +++ b/harbour/contrib/hbziparch/Aes.cpp @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + diff --git a/harbour/contrib/hbziparch/Aes.h b/harbour/contrib/hbziparch/Aes.h new file mode 100644 index 0000000000..d0a1914a24 --- /dev/null +++ b/harbour/contrib/hbziparch/Aes.h @@ -0,0 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + diff --git a/harbour/contrib/hbziparch/BaseLibCompressor.cpp b/harbour/contrib/hbziparch/BaseLibCompressor.cpp new file mode 100644 index 0000000000..328fccc3b3 --- /dev/null +++ b/harbour/contrib/hbziparch/BaseLibCompressor.cpp @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "BaseLibCompressor.h" + +namespace ZipArchiveLib +{ + +void CBaseLibCompressor::SetOpaque(void** opaque, const COptions* pOptions) +{ + *opaque = pOptions->m_bDetectLibMemoryLeaks ? &m_list : 0; +} + +void CBaseLibCompressor::EmptyPtrList() +{ + if (m_list.GetCount()) + { + // if some memory hasn't been freed due to an error in zlib, so free it now + CZipPtrListIter iter = m_list.GetHeadPosition(); + while (m_list.IteratorValid(iter)) + delete[] (char*) m_list.GetNext(iter); + } + m_list.RemoveAll(); +} + +} // namespace + + + + + + diff --git a/harbour/contrib/hbziparch/BaseLibCompressor.h b/harbour/contrib/hbziparch/BaseLibCompressor.h new file mode 100644 index 0000000000..9282e2ea5e --- /dev/null +++ b/harbour/contrib/hbziparch/BaseLibCompressor.h @@ -0,0 +1,198 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file BaseLibCompressor.h +* Includes the ZipArchiveLib::CBaseLibCompressor class. +* +*/ + +#if !defined(ZIPARCHIVE_BASELIBCOMPRESSOR_DOT_H) +#define ZIPARCHIVE_BASELIBCOMPRESSOR_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "ZipExport.h" +#include "ZipCompressor.h" +#include "ZipCollections.h" +#include "ZipException.h" + +namespace ZipArchiveLib +{ + +/** + A base class for compressors that use external libraries, such as zlib or bzip2. +*/ +class ZIP_API CBaseLibCompressor : public CZipCompressor +{ +public: + /** + Represents options of compressors that use external libraries. + + \see + 0610231446|options + \see + CZipArchive::SetCompressionOptions + */ + struct ZIP_API COptions : CZipCompressor::COptions + { + COptions() + { + m_bDetectLibMemoryLeaks = true; + } + + /** + \c true, if the ZipArchive Library should detect memory leaks in an external library; \c false otherwise. + Recommended to be set to \c true. + */ + bool m_bDetectLibMemoryLeaks; + }; + + /** + Initializes a new instance of the CBaseLibCompressor class. + + \param pStorage + The current storage object. + */ + CBaseLibCompressor(CZipStorage* pStorage) + :CZipCompressor(pStorage) + { + } + + void InitDecompression(CZipFileHeader* pFile, CZipCryptograph* pCryptograph) + { + CZipCompressor::InitDecompression(pFile, pCryptograph); + m_bDecompressionDone = false; + } + + ~CBaseLibCompressor() + { + EmptyPtrList(); + } +protected: + + /** + A memory allocation method called by an external library. + + \param opaque + Internal data. + + \param items + The number of blocks to allocate. + + \param size + The size of each block to allocate. + + \return + The address of a newly allocated memory. + */ + static void* _zipalloc(void* opaque, UINT items, UINT size) + { + void* p = new char[size * items]; + if (opaque) + { + CZipPtrList* list = (CZipPtrList*) opaque; + list->AddTail(p); + } + return p; + } + + /** + A memory deallocation method called by an external library. + + \param opaque + Internal data. + + \param address + Memory address to free. + */ + static void _zipfree(void* opaque, void* address) + { + if (opaque) + { + CZipPtrList* list = (CZipPtrList*) opaque; + CZipPtrListIter iter = list->Find(address); + if (list->IteratorValid(iter)) + list->RemoveAt(iter); + } + delete[] (char*) address; + } + + /** + Frees the memory allocated by an external library that hasn't been freed + due to an error in the library (usually never happens). + */ + void EmptyPtrList(); + + /** + Checks, if \a iErr value is an error code. + + \param iErr + The code to check. + + \return + \c true, if \a iErr is an error code; \c false otherwise. + */ + virtual bool IsCodeErrorOK(int iErr) const = 0; + + /** + Checks, if \a iErr value is an error code and throws an exception, if it is. + + \param iErr + The error code. + + \note + Throws exceptions. + */ + void CheckForError(int iErr) + { + if (!IsCodeErrorOK(iErr)) + ThrowError(iErr, true); + } + + /** + Sets an address of internal data used in ZipArchive Library memory allocation and deallocation methods. + + \param opaque + Receives an address on the internal data. + \param pOptions + The current decompressor options. + */ + void SetOpaque(void** opaque, const COptions* pOptions); + + /** + Signalizes, that the decompression process reached the end of the compressed data. It is internally set by derived classes. + */ + bool m_bDecompressionDone; +private: + typedef CZipPtrList::iterator CZipPtrListIter; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (push) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class +#endif + + CZipPtrList m_list; ///< A list holding pointers to the memory areas allocated by an external library. + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning( pop) +#endif + +}; + +} // namespace + +#endif diff --git a/harbour/contrib/hbziparch/BytesWriter.h b/harbour/contrib/hbziparch/BytesWriter.h new file mode 100644 index 0000000000..da3cd7eb9b --- /dev/null +++ b/harbour/contrib/hbziparch/BytesWriter.h @@ -0,0 +1,180 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file BytesWriter.h +* Includes the ZipArchiveLib::CBytesWriter class. +* +*/ + +#if !defined(ZIPARCHIVE_BYTESWRITER_DOT_H) +#define ZIPARCHIVE_BYTESWRITER_DOT_H + +#if _MSC_VER > 1000 + #pragma once +#endif + +#include "ZipCompatibility.h" + +namespace ZipArchiveLib +{ + /** + Provides implementation for various + buffer operations depending on the current platform and configuration. + */ + class ZIP_API CBytesWriter + { + public: + + #ifdef ZIP_ARCHIVE_LITTLE_ENDIAN + /** + Reads \a iCount bytes from \a pSource into \a pDestination. + + \param[out] pDestination + The buffer to retrieve data with byte-ordering depending on the machine. + + \param[in] pSource + The buffer with little-endian ordered data. + + \param iCount + The number of bytes to read. + */ + static void ReadBytes(WORD& uDestination, const char* pSource, int iCount = 2) + { + uDestination = 0; + memcpy(&uDestination, pSource, iCount); + } + + static void ReadBytes(DWORD& uDestination, const char* pSource, int iCount = 4) + { + uDestination = 0; + memcpy(&uDestination, pSource, iCount); + } + + + #ifndef _ZIP_STRICT_U16 + static void ReadBytes(int& iDestination, const char* pSource, int iCount) + { + iDestination = 0; + memcpy(&iDestination, pSource, iCount); + } + #endif + + + /** + Writes \a iCount bytes from \a pSource into \a pDestination. + + \param[out] pDestination + The buffer to retrieve little-endian ordered data. + + \param[in] pSource + The buffer with byte-ordering depending on the machine. + + \param iCount + The number of bytes to write. + */ + static void WriteBytes(char* pDestination, WORD uSource) + { + memcpy(pDestination, &uSource, 2); + } + + static void WriteBytes(char* pDestination, DWORD uSource, int iCount = 4) + { + memcpy(pDestination, &uSource, iCount); + } + + #ifndef _ZIP_STRICT_U16 + static void WriteBytes(char* pDestination, int uSource, int iCount) + { + memcpy(pDestination, &uSource, iCount); + } + #endif + + #else + + static void ReadBytes(char* pDestination, const char* pSource, int iDestSize, int iCount) + { + int i = iCount - iDestSize; + while (i < 0) + { + *pDestination++ = 0; + i++; + } + for (; i < iCount; i++) + (pDestination)[i] = pSource[iCount - i - 1]; + } + + static void ReadBytes(WORD& uDestination, const char* pSource, int iCount = 2) + { + ReadBytes((char*)&uDestination, pSource, 2, iCount); + } + + static void ReadBytes(DWORD& uDestination, const char* pSource, int iCount = 4) + { + ReadBytes((char*)&uDestination, pSource, 4, iCount); + } + + + #ifndef _ZIP_STRICT_U16 + static void ReadBytes(int& iDestination, const char* pSource, int iCount) + { + ReadBytes((char*)&iDestination, pSource, sizeof(int), iCount); + } + #endif + + + static void WriteBytes(char* pDestination, WORD uSource) + { + for (int i = 0; i < 2; i++) + pDestination[i] = ((char*)&uSource)[2 - i - 1]; + } + + static void WriteBytes(char* pDestination, DWORD uSource, int iCount = 4) + { + for (int i = 0; i < iCount; i++) + pDestination[i] = ((char*)&uSource)[4 - i - 1]; + } + + #ifndef _ZIP_STRICT_U16 + static void WriteBytes(char* pDestination, int iSource, int iCount) + { + for (int i = 0; i < iCount; i++) + pDestination[i] = ((char*)&iSource)[sizeof(int) - i - 1]; + } + #endif + + #endif + + static DWORD WriteSafeU32(DWORD uValue) + { + return uValue; + } + + #ifdef _ZIP_STRICT_U16 + static WORD WriteSafeU16(WORD uValue) + { + return uValue; + } + #else + static WORD WriteSafeU16(int uValue) + { + return (WORD)uValue; + } + #endif + + + }; +} + +#endif diff --git a/harbour/contrib/hbziparch/Bzip2Compressor.cpp b/harbour/contrib/hbziparch/Bzip2Compressor.cpp new file mode 100644 index 0000000000..b0870db342 --- /dev/null +++ b/harbour/contrib/hbziparch/Bzip2Compressor.cpp @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + diff --git a/harbour/contrib/hbziparch/Bzip2Compressor.h b/harbour/contrib/hbziparch/Bzip2Compressor.h new file mode 100644 index 0000000000..d0a1914a24 --- /dev/null +++ b/harbour/contrib/hbziparch/Bzip2Compressor.h @@ -0,0 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + diff --git a/harbour/contrib/hbziparch/DeflateCompressor.cpp b/harbour/contrib/hbziparch/DeflateCompressor.cpp new file mode 100644 index 0000000000..df57497b83 --- /dev/null +++ b/harbour/contrib/hbziparch/DeflateCompressor.cpp @@ -0,0 +1,251 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "DeflateCompressor.h" +#include "zlib/deflate.h" + +namespace ZipArchiveLib +{ + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif + + +CDeflateCompressor::CDeflateCompressor(CZipStorage* pStorage) + :CBaseLibCompressor(pStorage) +{ + m_stream.zalloc = (zarch_alloc_func)_zipalloc; + m_stream.zfree = (zarch_free_func)_zipfree; +} + + +void CDeflateCompressor::InitCompression(int iLevel, CZipFileHeader* pFile, CZipCryptograph* pCryptograph) +{ + CZipCompressor::InitCompression(iLevel, pFile, pCryptograph); + + m_stream.avail_in = (zarch_uInt)0; + m_stream.avail_out = (zarch_uInt)m_pBuffer.GetSize(); + m_stream.next_out = (zarch_Bytef*)(char*)m_pBuffer; + m_stream.total_in = 0; + m_stream.total_out = 0; + + if (pFile->m_uMethod == methodDeflate) + { + SetOpaque(&m_stream.opaque, &m_options); + + int err = zarch_deflateInit2_(&m_stream, iLevel, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(zarch_z_stream)); + + CheckForError(err); + } +} + +void CDeflateCompressor::Compress(const void *pBuffer, DWORD uSize) +{ + m_stream.next_in = (zarch_Bytef*)pBuffer; + m_stream.avail_in = uSize; + UpdateFileCrc(pBuffer, uSize); + + + while (m_stream.avail_in > 0) + { + if (m_stream.avail_out == 0) + { + FlushWriteBuffer(); + m_stream.avail_out = m_pBuffer.GetSize(); + m_stream.next_out = (zarch_Bytef*)(char*)m_pBuffer; + } + + if (m_pFile->m_uMethod == methodDeflate) + { + ZIP_ZLIB_TYPE uTotal = m_stream.total_out; + CheckForError(zarch_deflate(&m_stream, Z_NO_FLUSH)); + m_uComprLeft += m_stream.total_out - uTotal; + } + else + { + DWORD uToCopy = (m_stream.avail_in < m_stream.avail_out) + ? m_stream.avail_in : m_stream.avail_out; + + memcpy(m_stream.next_out, m_stream.next_in, uToCopy); + + m_stream.avail_in -= uToCopy; + m_stream.avail_out -= uToCopy; + m_stream.next_in += uToCopy; + m_stream.next_out += uToCopy; + m_stream.total_in += uToCopy; + m_stream.total_out += uToCopy; + m_uComprLeft += uToCopy; + } + } +} + +void CDeflateCompressor::FinishCompression(bool bAfterException) +{ + m_stream.avail_in = 0; + if (!bAfterException) + { + if (m_pFile->m_uMethod == methodDeflate) + { + int err; + do + { + if (m_stream.avail_out == 0) + { + FlushWriteBuffer(); + m_stream.avail_out = m_pBuffer.GetSize(); + m_stream.next_out = (zarch_Bytef*)(char*)m_pBuffer; + } + ZIP_SIZE_TYPE uTotal = m_stream.total_out; + err = zarch_deflate(&m_stream, Z_FINISH); + m_uComprLeft += m_stream.total_out - uTotal; + } + while (err == Z_OK); + + if (err == Z_STREAM_END) + err = Z_OK; + CheckForError(err); + } + + if (m_uComprLeft > 0) + FlushWriteBuffer(); + + if (m_pFile->m_uMethod == methodDeflate) + CheckForError(zarch_deflateEnd(&m_stream)); + + + // it may be increased by the encrypted header size in CZipFileHeader::PrepareData + m_pFile->m_uComprSize += m_stream.total_out; + m_pFile->m_uUncomprSize = m_stream.total_in; + } + EmptyPtrList(); + ReleaseBuffer(); +} + +void CDeflateCompressor::InitDecompression(CZipFileHeader* pFile, CZipCryptograph* pCryptograph) +{ + CBaseLibCompressor::InitDecompression(pFile, pCryptograph); + if (m_pFile->m_uMethod == methodDeflate) + { + SetOpaque(&m_stream.opaque, &m_options); + CheckForError(zarch_inflateInit2_(&m_stream, -MAX_WBITS, ZLIB_VERSION, sizeof(zarch_z_stream))); + } + m_stream.total_out = 0; + m_stream.avail_in = 0; +} + +DWORD CDeflateCompressor::Decompress(void *pBuffer, DWORD uSize) +{ + if (m_bDecompressionDone) + return 0; + + m_stream.next_out = (zarch_Bytef*)pBuffer; + m_stream.avail_out = uSize > m_uUncomprLeft + ? (DWORD)m_uUncomprLeft : uSize; + + DWORD uRead = 0; + + // may happen when the file is 0 sized + bool bForce = m_stream.avail_out == 0 && m_uComprLeft > 0; + while (m_stream.avail_out > 0 || (bForce && m_uComprLeft > 0)) + { + if ((m_stream.avail_in == 0) && + (m_uComprLeft >= 0)) // Also when there are zero bytes left + { + DWORD uToRead = m_pBuffer.GetSize(); + if (m_uComprLeft < uToRead) + uToRead = (DWORD)m_uComprLeft; + + if (uToRead == 0) + uToRead = 1; // Add dummy byte at end of compressed data. + else + { + m_pStorage->Read(m_pBuffer, uToRead, false); + if (m_pCryptograph) + m_pCryptograph->Decode(m_pBuffer, uToRead); + } + + m_uComprLeft -= uToRead; + + m_stream.next_in = (zarch_Bytef*)(char*)m_pBuffer; + m_stream.avail_in = uToRead; + } + + if (m_pFile->m_uMethod == methodStore) + { + DWORD uToCopy = m_stream.avail_out < m_stream.avail_in + ? m_stream.avail_out : m_stream.avail_in; + + memcpy(m_stream.next_out, m_stream.next_in, uToCopy); + + UpdateCrc(m_stream.next_out, uToCopy); + + m_uUncomprLeft -= uToCopy; + m_stream.avail_in -= uToCopy; + m_stream.avail_out -= uToCopy; + m_stream.next_out += uToCopy; + m_stream.next_in += uToCopy; + m_stream.total_out += uToCopy; + uRead += uToCopy; + } + else + { + ZIP_SIZE_TYPE uTotal = m_stream.total_out; + zarch_Bytef* pOldBuf = m_stream.next_out; + int ret = zarch_inflate(&m_stream, Z_SYNC_FLUSH); + // will not exceed DWORD + DWORD uToCopy = (DWORD)(m_stream.total_out - uTotal); + + UpdateCrc(pOldBuf, uToCopy); + + m_uUncomprLeft -= uToCopy; + uRead += uToCopy; + + if (ret == Z_STREAM_END) + { + m_bDecompressionDone = true; + return uRead; + } + else + CheckForError(ret); + } + } + + if (!uRead && m_options.m_bCheckLastBlock && uSize != 0 && m_pFile->m_uMethod == methodDeflate) + { + if (zarch_inflate(&m_stream, Z_SYNC_FLUSH) != Z_STREAM_END) + // there were no more bytes to read and there was no ending block, + // otherwise the method would return earlier + ThrowError(CZipException::badZipFile); + } + + return uRead; +} + +void CDeflateCompressor::FinishDecompression(bool bAfterException) +{ + if (!bAfterException && m_pFile->m_uMethod == methodDeflate) + zarch_inflateEnd(&m_stream); + EmptyPtrList(); + ReleaseBuffer(); +} + + +} // namespace diff --git a/harbour/contrib/hbziparch/DeflateCompressor.h b/harbour/contrib/hbziparch/DeflateCompressor.h new file mode 100644 index 0000000000..74210377de --- /dev/null +++ b/harbour/contrib/hbziparch/DeflateCompressor.h @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file DeflateCompressor.h +* Includes the ZipArchiveLib::CDeflateCompressor class. +* +*/ + +#if !defined(ZIPARCHIVE_DEFLATECOMPRESSOR_DOT_H) +#define ZIPARCHIVE_DEFLATECOMPRESSOR_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "ZipExport.h" +#include "BaseLibCompressor.h" +#include "ZipException.h" +#include "zlib/zlib.h" + +namespace ZipArchiveLib +{ + +/** + Compresses and decompresses data using the Zlib library. +*/ +class ZIP_API CDeflateCompressor : public CBaseLibCompressor +{ +public: + /** + Represents options of the CDeflateCompressor. + + \see + 0610231446|options + \see + CZipArchive::SetCompressionOptions + */ + struct ZIP_API COptions : CBaseLibCompressor::COptions + { + COptions() + { + m_bCheckLastBlock = true; + } + + int GetType() const + { + return typeDeflate; + } + + CZipCompressor::COptions* Clone() const + { + return new COptions(*this); + } + + /** + Enables or disables checking, if the compressed data ends with an end-of-stream block. + This should be enabled to protect against malformed data. + \c true, if the checking of the last block should be enabled; \c false otherwise. + */ + bool m_bCheckLastBlock; + + }; + + /** + Initializes a new instance of the CDeflateCompressor class. + + \param pStorage + The current storage object. + */ + CDeflateCompressor(CZipStorage* pStorage); + + bool CanProcess(WORD uMethod) {return uMethod == methodStore || uMethod == methodDeflate;} + + void InitCompression(int iLevel, CZipFileHeader* pFile, CZipCryptograph* pCryptograph); + void InitDecompression(CZipFileHeader* pFile, CZipCryptograph* pCryptograph); + + DWORD Decompress(void *pBuffer, DWORD uSize); + void Compress(const void *pBuffer, DWORD uSize); + + void FinishCompression(bool bAfterException); + void FinishDecompression(bool bAfterException); + + + const CZipCompressor::COptions* GetOptions() const + { + return &m_options; + } + + ~CDeflateCompressor() + { + } +protected: + void UpdateOptions(const CZipCompressor::COptions* pOptions) + { + m_options = *(COptions*)pOptions; + } + + int ConvertInternalError(int iErr) const + { + switch (iErr) + { + case Z_NEED_DICT: + return CZipException::needDict; + case Z_STREAM_END: + return CZipException::streamEnd; + case Z_ERRNO: + return CZipException::errNo; + case Z_STREAM_ERROR: + return CZipException::streamError; + case Z_DATA_ERROR: + return CZipException::dataError; + case Z_MEM_ERROR: + return CZipException::memError; + case Z_BUF_ERROR: + return CZipException::bufError; + case Z_VERSION_ERROR: + return CZipException::versionError; + default: + return CZipException::genericError; + } + } + + bool IsCodeErrorOK(int iErr) const + { + return iErr == Z_OK || iErr == Z_NEED_DICT; + } + +private: + COptions m_options; + zarch_z_stream m_stream; +}; + +} // namespace + +#endif + diff --git a/harbour/contrib/hbziparch/DirEnumerator.cpp b/harbour/contrib/hbziparch/DirEnumerator.cpp new file mode 100644 index 0000000000..06934b667a --- /dev/null +++ b/harbour/contrib/hbziparch/DirEnumerator.cpp @@ -0,0 +1,185 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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" +#if defined _MSC_VER && _MSC_VER < 1300 + // STL warnings + #pragma warning (push, 3) +#endif + +#include "DirEnumerator.h" +#include "FileFilter.h" + +#include + +#if defined __GNUC__ && !defined __MINGW32__ + #include + #include +#else + #include + #ifdef __BORLANDC__ + #ifndef _tfindfirsti64 + #define _tfindfirsti64 __tfindfirsti64 + #endif + #ifndef _tfindnexti64 + #define _tfindnexti64 __tfindnexti64 + #endif + #ifndef _tfinddatai64_t + #define _tfinddatai64_t __tfinddatai64_t + #endif + #endif +#endif + +namespace ZipArchiveLib +{ + +#if defined __GNUC__ && !defined __MINGW32__ + #define ZIP_ENUMERATOR_FOR_GNUC +#endif + + +bool CDirEnumerator::Start(CFileFilter& filter) +{ + OnEnumerationBegin(); + std::queue dirs; + dirs.push(CZipString(m_lpszDirectory)); + bool ret = true; + do + { + m_szCurrentDirectory = dirs.front(); + dirs.pop(); + CZipPathComponent::AppendSeparator(m_szCurrentDirectory); + EnterDirectory(); + +#ifdef ZIP_ENUMERATOR_FOR_GNUC + DIR* dp = opendir(m_szCurrentDirectory); + if (dp) + { + while (true) + { + struct dirent* entry = readdir(dp); + if (!entry) + break; + CZipString path(m_szCurrentDirectory + entry->d_name); + #if !defined __APPLE__ && !defined __CYGWIN__ + struct stat64 sStats; + if (stat64(path, &sStats) == -1) + #else + struct stat sStats; + if (stat(path, &sStats) == -1) + #endif + continue; + + LPCTSTR name = entry->d_name; + CFileInfo info; + info.m_uAttributes = sStats.st_mode; + +#else + CZipString szFullFileName = m_szCurrentDirectory + _T("*"); + + _tfinddatai64_t ffInfo; +#if _MSC_VER > 1200 + intptr_t hFile; +#else + long hFile; +#endif + if( (hFile = _tfindfirsti64( (LPTSTR)(LPCTSTR)szFullFileName, &ffInfo )) != -1L ) + { + do + { + LPCTSTR name = ffInfo.name; + CFileInfo info; + info.m_uAttributes = ffInfo.attrib; +#endif + bool isDir; + if (ZipPlatform::IsDirectory(info.m_uAttributes)) + { + if (!m_bRecursive || IsDots(name)) + continue; + isDir = true; + } + else + isDir = false; + +#ifdef ZIP_ENUMERATOR_FOR_GNUC + info.m_uSize = (ZIP_FILE_USIZE)sStats.st_size; + info.m_uCreateTime = sStats.st_ctime; + info.m_uModTime = sStats.st_mtime; + info.m_uAccessTime = sStats.st_atime; +#else + info.m_uSize = (ZIP_FILE_USIZE)ffInfo.size; + info.m_uCreateTime = ffInfo.time_create; + info.m_uModTime = ffInfo.time_write; + info.m_uAccessTime = ffInfo.time_access; + CZipString path(m_szCurrentDirectory + ffInfo.name); +#endif + + if (isDir) + { + bool bAllow; + if (filter.HandlesFile(info)) + bAllow = filter.Evaluate(path, name, info); + else + // examine directory, if the filter cannot decide + bAllow = true; + + if (bAllow) + dirs.push(path); + } + else + { + bool bAllow; + if (filter.HandlesFile(info)) + bAllow = filter.Evaluate(path, name, info); + else + // skip file, if the filter cannot decide + bAllow = false; + + if (bAllow && !Process(path, info)) + { + ret = false; + break; + } + } + +#ifdef ZIP_ENUMERATOR_FOR_GNUC + } + closedir(dp); + } +#else + } + while (_tfindnexti64(hFile, &ffInfo) == 0L); + _findclose(hFile); + } +#endif + ExitDirectory(); + } + while(!dirs.empty() && ret); + OnEnumerationEnd(ret); + return ret; +} + +bool CDirEnumerator::IsDots(LPCTSTR lpszName) +{ + CZipString name(lpszName); + return name.Compare(_T(".")) == 0 || name.Compare(_T("..")) == 0; +} + +} // namespace + +#if defined _MSC_VER && _MSC_VER < 1300 + // STL warnings + #pragma warning (pop) +#endif + diff --git a/harbour/contrib/hbziparch/DirEnumerator.h b/harbour/contrib/hbziparch/DirEnumerator.h new file mode 100644 index 0000000000..51ab881ea7 --- /dev/null +++ b/harbour/contrib/hbziparch/DirEnumerator.h @@ -0,0 +1,198 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file DirEnumerator.h +* Includes the ZipArchiveLib::CDirEnumerator class. +* +*/ + +#if !defined(ZIPARCHIVE_DIRENUMERATOR_DOT_H) +#define ZIPARCHIVE_DIRENUMERATOR_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #pragma warning( push ) + #pragma warning (disable : 4100) // unreferenced formal parameter + #if defined ZIP_HAS_DLL + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class + #endif +#endif + +#include "ZipString.h" +#include "ZipPathComponent.h" +#include "FileFilter.h" + +/** + Includes helper classes. Some of them can be reused in other applications. +*/ +namespace ZipArchiveLib +{ + /** + A base class for processing multiple files in a directory. + It provides a directory enumeration functionality. + */ + class ZIP_API CDirEnumerator + { + LPCTSTR m_lpszDirectory; + LPCTSTR m_lpszFileNameMask; + bool m_bRecursive; + CZipString m_szCurrentDirectory; + protected: + /** + Initializes a new CDirEnumerator object. + + \param lpszDirectory + A directory to process. + + \param bRecursive + The value indicating whether the subfolders of \a lpszDirectory + should be processed recursively or not. + + \see + GetDirectory + \see + IsRecursive + */ + CDirEnumerator(LPCTSTR lpszDirectory, bool bRecursive = true) + { + CZipString dir(lpszDirectory); + if (dir.IsEmpty()) + m_lpszDirectory = _T("."); + else + m_lpszDirectory = lpszDirectory; + m_bRecursive = bRecursive; + } + + /** + Override this method to perform file processing while enumerating directories. + This method is not called for directories, but for files only. + + \param lpszPath + The full path to the current file. + + \param info + A structure containing an information about the current file. + + \return + Return \c true to continue the enumeration. + When you return \c false, the enumeration is aborted. + + \see + CFileFilter::Evaluate + + */ + virtual bool Process(LPCTSTR lpszPath, const CFileInfo& info) = 0; + + /** + This method is called at the beginning of the enumeration process. + + \see + OnEnumerationEnd + */ + virtual void OnEnumerationBegin(){} + + /** + This method is called at the end of the enumeration process. + + \param bResult + It is set to \c false, if the #Process method returned \c false (the enumeration + was aborted). Otherwise, it is set to \c true. + + \see + OnEnumerationBegin + */ + virtual void OnEnumerationEnd(bool bResult){} + + /** + This method is called when an enumeration process enters a new directory. + + \see + GetCurrentDirectory + \see + ExitDirectory + */ + virtual void EnterDirectory(){} + + /** + This method is method called when an enumeration process exits a directory. + + \see + GetCurrentDirectory + \see + EnterDirectory + */ + virtual void ExitDirectory(){} + + public: + + /** + Returns the directory being enumerated. + + \return + The directory being enumerated (root). + + \see + CDirEnumerator::CDirEnumerator + */ + LPCTSTR GetDirectory() const {return m_lpszDirectory;} + + /** + Returns the value indicating whether the subfolders of the root directory + are processed recursively or not. + + \return + \c true, if the enumeration process is recursive; \c false otherwise. + + \see + CDirEnumerator::CDirEnumerator + */ + bool IsRecursive() const {return m_bRecursive;} + + /** + Returns the directory which the enumeration process is currently processing. + + \return + The directory which the enumeration process is currently processing. + */ + LPCTSTR GetCurrentDirectory() const {return m_szCurrentDirectory;} + + /** + Starts the enumeration process. Calls CFileFilter::Evaluate method for every file or directory found. + If CFileFilter::Evaluate returns \c true, the file is processed by the #Process method. + + \param filter + A filter that decides which directories and/or files should be processed and which should not. + + \return + \c false, if the process was aborted (the #Process method returned \c false); \c true otherwise. + + \see + CFileFilter::Evaluate + */ + bool Start(CFileFilter& filter); + + virtual ~CDirEnumerator(){} + private: + static bool IsDots(LPCTSTR lpszName); + }; + +} + +#if _MSC_VER > 1000 + #pragma warning( pop ) +#endif + +#endif + diff --git a/harbour/contrib/hbziparch/FileFilter.cpp b/harbour/contrib/hbziparch/FileFilter.cpp new file mode 100644 index 0000000000..a6b7453e10 --- /dev/null +++ b/harbour/contrib/hbziparch/FileFilter.cpp @@ -0,0 +1,60 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#if defined _MSC_VER && _MSC_VER < 1300 + // STL warnings + #include "stdafx.h" + #pragma warning (push, 3) +#endif + +#include "FileFilter.h" + +namespace ZipArchiveLib +{ + +bool CGroupFileFilter::Accept(LPCTSTR lpszParentDir, LPCTSTR lpszName, const CFileInfo& info) +{ + bool conditionToBreak; + bool valueToReturn; + + // handle the evaluation as quickly as possible + if (m_iType == CGroupFileFilter::And) + { + conditionToBreak = false; + valueToReturn = m_bInverted; + } + else + { + conditionToBreak = true; + valueToReturn = !m_bInverted; + } + + for (ZIP_ARRAY_SIZE_TYPE i = 0; i < m_filters.GetSize(); i++) + { + CFileFilter* pFilter = m_filters[i]; + if (pFilter->HandlesFile(info) && pFilter->Evaluate(lpszParentDir, lpszName, info) == conditionToBreak) + return valueToReturn; + } + + return !valueToReturn; + +} + +} // namespace + + +#if defined _MSC_VER && _MSC_VER < 1300 + // STL warnings + #pragma warning (pop) +#endif diff --git a/harbour/contrib/hbziparch/FileFilter.h b/harbour/contrib/hbziparch/FileFilter.h new file mode 100644 index 0000000000..52eb605b7d --- /dev/null +++ b/harbour/contrib/hbziparch/FileFilter.h @@ -0,0 +1,657 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file FileFilter.h +* Includes the ZipArchiveLib::CFileFilter and the derived classes. +* +*/ + + +#if !defined(ZIPARCHIVE_FILEFILTER_DOT_H) +#define ZIPARCHIVE_FILEFILTER_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #pragma warning( push ) + #pragma warning (disable : 4100) // unreferenced formal parameter +#endif + +#include "stdafx.h" +#include "ZipExport.h" +#include "FileInfo.h" +#include "Wildcard.h" +#include "ZipPlatform.h" +#include "ZipCollections.h" + +namespace ZipArchiveLib +{ + /** + A base class for filters used in the directory enumeration process. + + \see + 0610231446|filters + \see + CDirEnumerator::Start + */ + class ZIP_API CFileFilter + { + public: + + /** + Initializes a new instance of the CFileFilter class. + + \param bInverted + Set to \c true to invert the behavior of the filter or to \c false for the normal behavior. + + \see + SetInverted + */ + CFileFilter(bool bInverted = false) + :m_bInverted(bInverted) + { + } + + /** + This method is directly called by the CDirEnumerator::Start for each file or directory that was + previously accepted with the #HandlesFile method. + + It internally calls the #Accept method and inverts it's result, if the filter is in the inverted + mode and does not handle the inversion internally. + + - If this method returns \c true for a file, then the file is processed (the CDirEnumerator::Process method + is called for the file). Otherwise the file is not processed. + - If this method returns \c true for a directory, then the directory can be traversed for files and subfolders + (depending on the CDirEnumerator::IsRecursive() method). Otherwise the directory is not traversed. + + + \param lpszParentDir + The parent directory containing the file to accept. + + \param lpszName + The name of the file to accept (without a path). + + \param info + A structure containing the information about the current file. + + \return + \c true, if the file is accepted (taking inversion into account); \c false otherwise. + + \see + Accept + \see + HandlesFile + \see + HandlesInversion + \see + SetInverted + \see + IsInverted + \see + CDirEnumerator::Start + \see + CDirEnumerator::Process + */ + bool Evaluate(LPCTSTR lpszParentDir, LPCTSTR lpszName, const CFileInfo& info) + { + bool ret = Accept(lpszParentDir, lpszName, info); + if (!HandlesInversion()) + return m_bInverted ? !ret : ret; + return ret; + } + + /** + Sets the filter to operate in the inverted or in the normal mode. + If the filter operates in an inverted mode, the file that this filer accepts + is \b not processed and vice versa. Normal mode means that a file is processed + (the CDirEnumerator::Process method is called for that file), + if the filter accepts the file. + + \param bInverted + \c true to make the filter operate in an inverted mode or \c false to make + the filter operate in a normal mode. + + \see + HandlesInversion + \see + IsInverted + */ + void SetInverted(bool bInverted = true) { m_bInverted = bInverted;} + + /** + Returns the value indicating whether the filter operates in an inverted mode or in a normal mode. + + \return + \c true, if the filter operates in an inverted mode; \c false otherwise. + + \see + SetInverted + \see + HandlesInversion + */ + bool IsInverted() const {return m_bInverted;} + + /** + Returns the value indicating whether the filter can decide about processing of the \a info file. + If it can, then the #Evaluate method will be called for the \a info file. + By default this method returns \c true for files and \c false for directories. Override this method + to change it's behavior. + + - If \a info is a file and this method returns \c false, then the file is not processed. + - If \a info is a directory and this method returns \c false, then the directory can still be traversed for files + and subfolders (depending on the CDirEnumerator::IsRecursive() method). + + The #Evaluate method is not called in both cases. + + \param info + A structure containing the information about the file. + + \return + \c true, if the \a info file should be evaluated by the #Evaluate method; \c false otherwise. + + \note + This method is particularly useful when the filter operates in the inverted mode (see #SetInverted). + For example, if a filter should accept directories in both inverted and non-inverted mode, it would need + to particularly handle inversion for directories without this method. With this method it can just not accept + directories for evaluation and they still will be traversed. + */ + virtual bool HandlesFile(const CFileInfo& info) + { + return !info.IsDirectory(); + } + + virtual ~CFileFilter() + { + } +protected: + /** + This method is directly called by the #Evaluate method during an enumeration process. + + If this method returns \c true, the file will later be processed + by the CDirEnumerator::Process method. If this method returns \c false for a directory, + the directory is not enumerated at all. + + The meaning of the return value can be reversed by the #SetInverted method. + If this filter handles the inversion internally, the return value from this method + is not reversed by the #Evaluate method. + + \param lpszParentDir + The parent directory containing the file to accept. + + \param lpszName + The name of the file to accept (without a path). + + \param info + A structure containing the information about the current file. + + \return + \c true, if the file is accepted; \c false otherwise. + + \see + Evaluate + \see + HandlesInversion + \see + CDirEnumerator::Start + \see + CDirEnumerator::Process + */ + virtual bool Accept(LPCTSTR lpszParentDir, LPCTSTR lpszName, const CFileInfo& info) + { + return true; + } + + /** + Returns the value indicating, whether the current filter handles the inversion mode internally + or not. + - If the filter is in the inverted mode and it handles the inversion, then the return value \c true + from the #Accept method means that the file should be processed. + - If the filter is in the inverted mode and it does not handle the inversion, then the return value \c true + from the #Accept method means that the file should not be processed. + + It may be more efficient to handle the inversion internally in some cases. + + \return + \c true, if the filter handles the inversion internally; \c false otherwise. + + \note + This method returns \c false by default. Override this method to change this behavior. + + \see + SetInverted + \see + IsInverted + */ + virtual bool HandlesInversion() const + { + return false; + } + bool m_bInverted; + + }; + + + /** + A filter that allows filtering files by a filename mask while an enumeration process. + + \see + 0610231446|filters + \see + 0610242025|wildcards + \see + CDirEnumerator::Start + */ + class ZIP_API CNameFileFilter : public CFileFilter + { + CWildcard m_matcher; + int m_iAppliesToTypes; + public: + + /** + The file type to which the CNameFileFilter filter can be applied. + You can use the logical \c OR to combine them. + + \see + SetAppliesToTypes + \see + GetAppliesToTypes + */ + enum AppliesToTypes + { + toFile = 0x1, ///< Regular files only. + toDirectory = 0x2, ///< Directories only. + toAll = toFile | toDirectory ///< Both regular files and directories. + }; + + /** + Initializes a new instance of the CNameFileFilter class. + + \param lpszPattern + A mask to match against a filename. This filter uses the CWildcard functionality for this purpose. + + \param iAppliesToTypes + The file type to which this filter applies. The file type to which this filter applies. Can be one or more of the #AppliesToTypes values. + + \param bInverted + Set to \c true to invert the behavior of the filter or to \c false for the normal behavior. + + \param bCaseSensitive + \c true, if the matching process is case-sensitive; \c false otherwise. + By default, a system case-sensitivity setting is used. + + \see + 0610231446|filters + \see + 0610242025|wildcards + \see + SetInverted + \see + SetAppliesToTypes + \see + CWildcard + \see + ZipPlatform::GetSystemCaseSensitivity + */ + CNameFileFilter(LPCTSTR lpszPattern = _T("*.*"), bool bInverted = false, int iAppliesToTypes = toFile, bool bCaseSensitive = ZipPlatform::GetSystemCaseSensitivity()) + :CFileFilter(bInverted), m_matcher(lpszPattern, bCaseSensitive) + { + m_iAppliesToTypes = iAppliesToTypes; + } + + /** + Returns the value indicating whether the filter can be applied to the given \a iType type. + + \param iType + Can be one or more of the #AppliesToTypes values. + + \return + \c true, if the filter can be applied to \a iType type; \c false otherwise. + + \see + SetAppliesToTypes + \see + GetAppliesToTypes + */ + bool AppliesToType(int iType) + { + return (m_iAppliesToTypes & iType) == iType; + } + + /** + Set the file type to which this filter applies. + + \param iType + The file type to which this filter applies. Can be one or more of the #AppliesToTypes values. + + \see + GetAppliesToTypes + + */ + void SetAppliesToTypes(int iType) { m_iAppliesToTypes = iType; } + + /** + Return the file type to which this filter applies. + + \return + The file type to which this filter applies. Can be one or more of the #AppliesToTypes values. + + \see + SetAppliesToTypes + */ + int GetAppliesToTypes() {return m_iAppliesToTypes;} + + /** + Returns the value indicating whether the filter can decide about processing of the \a info file. + The CNameFileFilter returns the value depending on the #GetAppliesToTypes value. + + \param info + A structure containing the information about the file. + + \return + \c true, if the \a info file will be evaluated by the #Evaluate method; \c false otherwise. + + \see + GetAppliesToTypes + \see + SetAppliesToTypes + + */ + bool HandlesFile(const CFileInfo& info) + { + return info.IsDirectory() ? AppliesToType(toDirectory) : AppliesToType(toFile); + } + protected: + virtual bool Accept(LPCTSTR, LPCTSTR lpszName, const CFileInfo& info) + { + return m_matcher.IsMatch(lpszName); + } + }; + + /** + A filter that allows grouping of other filters. + + \see + 0610231446|filters + \see + CDirEnumerator::Start + */ + class ZIP_API CGroupFileFilter : public CFileFilter + { + + public: + + /** + The grouping type. + */ + enum GroupType + { + And, ///< Logical AND. All the grouped filters must accept a file for the file to be processed. + Or ///< Logical OR. At least one of the grouped filters must accept a file for the file to be processed. + }; + + /** + Initializes a new instance of the CGroupFileFilter class. + + \param groupType + The grouping type. Should be one of the #GroupType values. + + \param bAutoDelete + \c true, if the grouped filters should be automatically destroyed by this filter; \c false otherwise. + + \param bInverted + Set to \c true to invert the behavior of the filter or to \c false for the normal behavior. + This filter handles the inversion mode internally. + + \see + 0610231446|filters + \see + SetType + \see + SetAutoDelete + \see + SetInverted + \see + HandlesInversion + */ + CGroupFileFilter(GroupType groupType = CGroupFileFilter::And, bool bAutoDelete = true, bool bInverted = false) + :CFileFilter(bInverted), m_iType(groupType), m_bAutoDelete(bAutoDelete) + { + } + + /** + Add \a pFilter to the filter's group. + + \param pFilter + The filter to add. + */ + void Add(CFileFilter* pFilter) + { + m_filters.Add(pFilter); + } + + /** + Returns the filter at the given position. + + \param uIndex + The index of the filter to return. + */ + CFileFilter* GetAt(ZIP_ARRAY_SIZE_TYPE uIndex) + { + return m_filters[uIndex]; + } + + /** + Returns the filter at the given position. + + \param uIndex + The index of the filter to return. + */ + const CFileFilter* GetAt(ZIP_ARRAY_SIZE_TYPE uIndex) const + { + return m_filters[uIndex]; + } + + /** + Returns the filter at the given position. + + \param uIndex + The index of the filter to return. + */ + const CFileFilter* operator[] (ZIP_ARRAY_SIZE_TYPE uIndex) const + { + return GetAt(uIndex); + } + + /** + Returns the filter at the given position. + + \param uIndex + The index of the filter to return. + */ + CFileFilter* operator[] (ZIP_ARRAY_SIZE_TYPE uIndex) + { + return GetAt(uIndex); + } + + /** + Remove the filter at the given position. + The removed filter is deleted from memory, + if the CGroupFileFilter object is in the auto-delete mode. + + \param uIndex + The index of the filter to remove. + + \see + SetAutoDelete + */ + void RemoveAt(ZIP_ARRAY_SIZE_TYPE uIndex) + { + CFileFilter* filter = m_filters[uIndex]; + // first remove, then delete + m_filters.RemoveAt(uIndex); + if (m_bAutoDelete) + delete filter; + } + + + /** + Removes all contained filters from the collection. + + The removed filters are deleted from memory, + if the CGroupFileFilter object is in the auto-delete mode. + + \see + SetAutoDelete + + */ + void Clear() + { + if (m_filters.GetSize() == 0) + return; + + ZIP_ARRAY_SIZE_TYPE i = m_filters.GetSize() - 1; + for (; ;) + { + RemoveAt(i); + if (i == 0) + break; + i--; + } + } + + /** + Returns the number of grouped filters. + + \return + The number of grouped filters. + + */ + ZIP_ARRAY_SIZE_TYPE GetSize() + { + return m_filters.GetSize(); + } + + /** + Sets the type of grouping. + + \param iType + The type of grouping. Should be one of the #GroupType values. + + \see + GetType + */ + void SetType(GroupType iType) {m_iType = iType;} + + /** + Returns the type of grouping. + + \return + The type of groupgroupeding. Can be one of the #GroupType values. + + \see + SetType + */ + GroupType GetType() const {return m_iType;} + + /** + Enable or disable auto-deletion of grouped filters. + If auto-deletion is enabled, the grouped filters are released from memory + when they are removed from the group or when the CGroupFileFilter + object is destroyed. + + \param bAutoDelete + \c true, to enable auto-deletion; \c false to disable. + + \see + IsAutoDelete + */ + void SetAutoDelete(bool bAutoDelete) {m_bAutoDelete = bAutoDelete;} + + /** + Return the value indicating whether the auto-deletion is enabled or not. + + \return + \c true, if the auto-deletion is enabled; \c false otherwise. + + \see + SetAutoDelete + */ + bool IsAutoDelete() const {return m_bAutoDelete;} + + /** + Returns the value indicating whether the filter can decide about processing of the \a info file. + The CGroupFileFilter returns the value depending on the value returned by the grouped filters. + + \param info + A structure containing the information about the file. + + \return + \c true, if any of the grouped filters accepts \a info; \c false otherwise. + + */ + bool HandlesFile(const CFileInfo& info) + { + for (ZIP_ARRAY_SIZE_TYPE i = 0; i < m_filters.GetSize(); i++) + // it is enough that one filter handles it + if (m_filters[i]->HandlesFile(info)) + return true; + return false; + } + + + ~CGroupFileFilter() + { + Clear(); + } + + protected: + + virtual bool Accept(LPCTSTR lpszParentDir, LPCTSTR lpszName, const CFileInfo& info); + /** + This filter handles inversion internally. + + \return + This method returns \c true for this class. + + \see + CFileFilter::HandlesInversion + */ + bool HandlesInversion() const + { + return true; + } + GroupType m_iType; ///< Set with the #SetType method or in constructor. + bool m_bAutoDelete; ///< Set with the #SetAutoDelete or in constructor. + + private: + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (push) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class +#endif + + CZipArray m_filters; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning( pop) +#endif + + }; +} + +#if _MSC_VER > 1000 + #pragma warning( pop ) +#endif + +#endif diff --git a/harbour/contrib/hbziparch/FileInfo.h b/harbour/contrib/hbziparch/FileInfo.h new file mode 100644 index 0000000000..286c855b4c --- /dev/null +++ b/harbour/contrib/hbziparch/FileInfo.h @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file FileInfo.h +* Includes the ZipArchiveLib::CFileInfo class. +* +*/ + +#if !defined(ZIPARCHIVE_FILEINFO_DOT_H) +#define ZIPARCHIVE_FILEINFO_DOT_H + +#if _MSC_VER > 1000 + #pragma once +#endif + +#include "stdafx.h" +#include "ZipExport.h" +#include "ZipPlatform.h" + +namespace ZipArchiveLib +{ + /** + A structure holding a file or a directory information. + */ + struct ZIP_API CFileInfo + { + public: + /** + Initializes a new instance of the CFileInfo class. + */ + CFileInfo() + { + m_uSize = 0; + m_uAttributes = 0; + m_uCreateTime = m_uModTime = m_uAccessTime = 0; + } + ZIP_FILE_USIZE m_uSize; ///< The file size. + DWORD m_uAttributes; ///< The file system attributes. + time_t m_uCreateTime; ///< Creation time. + time_t m_uModTime; ///< Last modification time. + time_t m_uAccessTime; ///< Last access time. + + /** + Returns the value indicating whether the current CFileInfo + object represents a directory or a regular file. + + \return + \c true, if the current CFileInfo object represents + a directory; \c false, if it represents a regular file. + */ + bool IsDirectory() const + { + return ZipPlatform::IsDirectory(m_uAttributes); + } + }; +} +#endif diff --git a/harbour/contrib/hbziparch/Hmac.cpp b/harbour/contrib/hbziparch/Hmac.cpp new file mode 100644 index 0000000000..b0870db342 --- /dev/null +++ b/harbour/contrib/hbziparch/Hmac.cpp @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + diff --git a/harbour/contrib/hbziparch/Hmac.h b/harbour/contrib/hbziparch/Hmac.h new file mode 100644 index 0000000000..d0a1914a24 --- /dev/null +++ b/harbour/contrib/hbziparch/Hmac.h @@ -0,0 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + diff --git a/harbour/contrib/hbziparch/RandomPool.cpp b/harbour/contrib/hbziparch/RandomPool.cpp new file mode 100644 index 0000000000..b0870db342 --- /dev/null +++ b/harbour/contrib/hbziparch/RandomPool.cpp @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + diff --git a/harbour/contrib/hbziparch/RandomPool.h b/harbour/contrib/hbziparch/RandomPool.h new file mode 100644 index 0000000000..d0a1914a24 --- /dev/null +++ b/harbour/contrib/hbziparch/RandomPool.h @@ -0,0 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + diff --git a/harbour/contrib/hbziparch/Sha1.cpp b/harbour/contrib/hbziparch/Sha1.cpp new file mode 100644 index 0000000000..b0870db342 --- /dev/null +++ b/harbour/contrib/hbziparch/Sha1.cpp @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + diff --git a/harbour/contrib/hbziparch/Sha1.h b/harbour/contrib/hbziparch/Sha1.h new file mode 100644 index 0000000000..d0a1914a24 --- /dev/null +++ b/harbour/contrib/hbziparch/Sha1.h @@ -0,0 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + diff --git a/harbour/contrib/hbziparch/Wildcard.cpp b/harbour/contrib/hbziparch/Wildcard.cpp new file mode 100644 index 0000000000..70633c15d7 --- /dev/null +++ b/harbour/contrib/hbziparch/Wildcard.cpp @@ -0,0 +1,401 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "Wildcard.h" + +namespace ZipArchiveLib +{ + +bool CWildcard::IsPatternValid(LPCTSTR lpszPattern, int* iErrorType) +{ + try + { + /* loop through pattern to EOS */ + while (*lpszPattern) + { + /* determine pattern type */ + switch (*lpszPattern) + { + /* check literal escape, it cannot be at end of pattern */ + case _T('\\'): + if (!*++lpszPattern) + throw patternEsc; + lpszPattern++; + break; + + /* the [..] construct must be well formed */ + case _T('['): + lpszPattern++; + + /* if the next character is ']' then bad pattern */ + if (*lpszPattern == _T(']')) + throw patternEmpty; + + /* if end of pattern here then bad pattern */ + if (!*lpszPattern) + throw patternClose; + + /* loop to end of [..] construct */ + while (*lpszPattern != _T(']')) + { + /* check for literal escape */ + if (*lpszPattern == _T('\\')) + { + lpszPattern++; + + /* if end of pattern here then bad pattern */ + if (!*lpszPattern++) + throw patternEsc; + } + else lpszPattern++; + + /* if end of pattern here then bad pattern */ + if (!*lpszPattern) + throw patternClose; + + /* if this a range */ + if (*lpszPattern == _T('-')) + { + /* we must have an end of range */ + if (!*++lpszPattern || *lpszPattern == ']') + throw patternRange; + else + { + + /* check for literal escape */ + if (*lpszPattern == _T('\\')) + lpszPattern++; + + /* if end of pattern here + then bad pattern */ + if (!*lpszPattern++) + throw patternEsc; + } + } + } + break; + + /* all other characters are valid pattern elements */ + case '*': + case '?': + default: + lpszPattern++; /* "normal" character */ + break; + } + } + throw patternValid; + } + catch (int i) + { + if (iErrorType) + *iErrorType = i; + return i == patternValid; + } + + +} + +bool CWildcard::IsPattern(LPCTSTR lpszPattern) +{ + while (*lpszPattern) + { + switch (*lpszPattern++) + { + case _T('?'): + case _T('*'): + case _T('['): + case _T('\\'): + return true; + } + } + return false; + +} + +bool CWildcard::IsMatch(LPCTSTR lpszText, int *iRetCode) +{ + CZipString sz; + if (!m_bCaseSensitive) + { + sz = lpszText; + sz.MakeLower(); + lpszText = (LPCTSTR)sz; + } + int i = Match((LPCTSTR)m_szPattern, lpszText); + if (iRetCode) + *iRetCode = i; + return i == matchValid; +} + +int CWildcard::MatchAfterStar(LPCTSTR p, LPCTSTR t) +{ + int iMatch = matchNone; + TCHAR nextp; + + /* pass over existing ? and * in pattern */ + + while ( *p == _T('?') || *p == _T('*') ) + { + /* take one char for each ? and + */ + + if (*p == _T('?')) + { + /* if end of text then no match */ + if (!*t++) + return matchAbort; + } + + /* move to next char in pattern */ + + p++; + } + + /* if end of pattern we have matched regardless of text left */ + + if (!*p) + return matchValid; + + /* get the next character to match which must be a literal or '[' */ + + nextp = *p; + if (nextp == _T('\\')) + { + nextp = p[1]; + + /* if end of text then we have a bad pattern */ + + if (!nextp) + return matchPattern; + } + + /* Continue until we run out of text or definite result seen */ + + do + { + /* a precondition for matching is that the next character + in the pattern match the next character in the text or that + the next pattern char is the beginning of a range. Increment + text pointer as we go here */ + + if (nextp == *t || nextp == _T('[')) + iMatch = Match(p, t); + + /* try finding another precondition */ + if (iMatch == matchPattern) + iMatch = matchNone; + /* if the end of text is reached then no iMatch */ + + if (!*t++) + iMatch = matchAbort; + + } while ( iMatch != matchValid && + iMatch != matchAbort); + + /* return result */ + + return iMatch; +} + + +int CWildcard::Match(LPCTSTR lpszPattern, LPCTSTR lpszText) +{ + TCHAR range_start, range_end; /* start and end in range */ + bool bInvert; /* is this [..] or [!..] */ + bool bMemberMatch; /* have I matched the [..] construct? */ + bool bLoop; /* should I terminate? */ + + for ( ; *lpszPattern; lpszPattern++, lpszText++) + { + /* if this is the end of the text + then this is the end of the match */ + + if (!*lpszText) + { + if ( *lpszPattern == _T('*') && *++lpszPattern == _T('\0') ) + return matchValid; + else + return matchAbort; + } + + /* determine and react to pattern type */ + + switch (*lpszPattern) + { + case _T('?'): /* single any character match */ + break; + + case _T('*'): /* multiple any character match */ + return MatchAfterStar (lpszPattern, lpszText); + + /* [..] construct, single member/exclusion character match */ + case _T('['): + { + /* move to beginning of range */ + + lpszPattern++; + + /* check if this is a member match or exclusion match */ + + bInvert = false; + if (*lpszPattern == _T('!') || *lpszPattern == _T('^')) + { + bInvert = true; + lpszPattern++; + } + + /* if closing bracket here or at range start then we have a + malformed pattern */ + + if (*lpszPattern == _T(']')) + return matchPattern; + + bMemberMatch = false; + bLoop = true; + + while (bLoop) + { + /* if end of construct then bLoop is done */ + + if (*lpszPattern == _T(']')) + { + bLoop = false; + continue; + } + + /* matching a '!', '^', '-', '\' or a ']' */ + + if (*lpszPattern == _T('\\')) + range_start = range_end = *++lpszPattern; + else + range_start = range_end = *lpszPattern; + + /* if end of pattern then bad pattern (Missing ']') */ + + if (!*lpszPattern) + return matchPattern; + + /* check for range bar */ + if (*++lpszPattern == _T('-')) + { + /* get the range end */ + + range_end = *++lpszPattern; + + /* if end of pattern or construct + then bad pattern */ + + if (range_end == _T('\0') || range_end == _T(']')) + return matchPattern; + /* special character range end */ + if (range_end == _T('\\')) + { + range_end = *++lpszPattern; + + /* if end of text then + we have a bad pattern */ + if (!range_end) + return matchPattern; + } + + /* move just beyond this range */ + lpszPattern++; + } + + /* if the text character is in range then match found. + make sure the range letters have the proper + relationship to one another before comparison */ + + if (range_start < range_end) + { + if (*lpszText >= range_start && *lpszText <= range_end) + { + bMemberMatch = true; + bLoop = false; + } + } + else + { + if (*lpszText >= range_end && *lpszText <= range_start) + { + bMemberMatch = true; + bLoop = false; + } + } + } + + /* if there was a match in an exclusion set then no match */ + /* if there was no match in a member set then no match */ + + if ((bInvert && bMemberMatch) || !(bInvert || bMemberMatch)) + return matchRange; + + /* if this is not an exclusion then skip the rest of + the [...] construct that already matched. */ + + if (bMemberMatch) + { + while (*lpszPattern != _T(']')) + { + /* bad pattern (Missing ']') */ + if (!*lpszPattern) + return matchPattern; + + /* skip exact match */ + if (*lpszPattern == _T('\\')) + { + lpszPattern++; + + /* if end of text then + we have a bad pattern */ + + if (!*lpszPattern) + return matchPattern; + } + + /* move to next pattern char */ + + lpszPattern++; + } + } + break; + } + case _T('\\'): /* next character is quoted and must match exactly */ + + /* move pattern pointer to quoted char and fall through */ + + lpszPattern++; + + /* if end of text then we have a bad pattern */ + + if (!*lpszPattern) + return matchPattern; + + /* must match this character exactly */ + + default: + if (*lpszPattern != *lpszText) + return matchPattern; + } + } + /* if end of text not reached then the pattern fails */ + + if (*lpszText) + return matchEnd; + else + return matchValid; +} + + +} // namespace diff --git a/harbour/contrib/hbziparch/Wildcard.h b/harbour/contrib/hbziparch/Wildcard.h new file mode 100644 index 0000000000..b49f5b8033 --- /dev/null +++ b/harbour/contrib/hbziparch/Wildcard.h @@ -0,0 +1,195 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/* + This class is based on code by J. Kercheval, created 01/05/1991 + and available as a public domain at http://www.snippets.org. +*/ + +/** +* \file Wildcard.h +* Includes the ZipArchiveLib::CWildcard class. +* +*/ + +#if !defined(ZIPARCHIVE_WILDCARD_DOT_H) +#define ZIPARCHIVE_WILDCARD_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning( push ) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class + #endif +#endif + +#include "ZipString.h" + +namespace ZipArchiveLib +{ + /** + A class used in the wildcard pattern matching. + + \see + 0610242025|wildcards + */ + class ZIP_API CWildcard + { + public: + + enum Match + { + matchNone, ///< For internal use. + matchValid, ///< Valid match. + matchEnd, ///< Premature end of the pattern string. + matchAbort, ///< Premature end of the text string. + matchRange, ///< Match failure on the \c [..] construct. + matchLiteral, ///< Match failure on a literal match + matchPattern ///< Bad pattern. + }; + + enum Pattern + { + patternEmpty = -4, ///< The \c [..] construct is empty + patternClose, ///< There is no end bracket in the \c [..] construct. + patternRange, ///< Malformed range in the \c [..] construct. + patternEsc, ///< Literal escape at the end of the pattern. + patternValid, ///< Valid pattern. + }; + + + /** + Matches \a lpszText against the pattern. + A match means the entire \a lpszText is used up in matching. + Set the pattern with the #SetPattern method or in the constructor. + + \param lpszText + The string to match against the pattern. + + \param iRetCode + If not \c NULL, receives one of #Match values indicating a return code. + + \return + \c true, if \a lpszText matches the pattern. + + \see + SetPattern + */ + bool IsMatch(LPCTSTR lpszText, int* iRetCode = NULL); + + /** + Gets a value indicating if \a lpszPattern has any special wildcard characters. + + \param lpszPattern + The pattern to test. + + \return + \c true, if the pattern has wildcard characters; \c false otherwise. + + */ + static bool IsPattern(LPCTSTR lpszPattern); + + /** + Tests \a lpszPattern for validity. + + \param lpszPattern + The pattern to test. + + \param iErrorType + If not \c NULL, receives one of the #Pattern values indicating a return code. + + \return + \c true, if \a lpszPattern is a well formed regular expression according + to the CWildcard class syntax (see #SetPattern); \c false otherwise. + */ + static bool IsPatternValid(LPCTSTR lpszPattern, int* iErrorType = NULL); + + /** + Matches \a lpszText against \a lpszPattern. + + A match means the entire \a lpszText is used in matching. + + \param lpszPattern + The pattern to match. + + \param lpszText + The string to match against the pattern. + + \return + One of #Match values. + + \see + SetPattern + */ + static int Match(LPCTSTR lpszPattern, LPCTSTR lpszText); + + /** + Initializes a new instance of the CWildcard class. + */ + CWildcard(){} + + /** + Initializes a new instance of the CWildcard class. + + \param lpszPattern + The pattern to use in matching. + + \param bCaseSensitive + The case-sensitivity of matching. + + \see + 0610242025|wildcards + */ + CWildcard(LPCTSTR lpszPattern, bool bCaseSensitive) + { + SetPattern(lpszPattern, bCaseSensitive); + } + + virtual ~CWildcard(){} + + /** + Sets the current pattern + + \param lpszPattern + The pattern used in matching. + + \param bCaseSensitive + The case-sensitivity of matching. + + \see + 0610242025|wildcards + */ + void SetPattern(LPCTSTR lpszPattern, bool bCaseSensitive) + { + m_szPattern = lpszPattern; + m_bCaseSensitive=bCaseSensitive; + if (!bCaseSensitive) + m_szPattern.MakeLower(); + } + operator LPCTSTR() + { + return (LPCTSTR)m_szPattern; + } + private: + bool m_bCaseSensitive; + static int MatchAfterStar(LPCTSTR p , LPCTSTR t); + CZipString m_szPattern; + }; +} + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + +#endif diff --git a/harbour/contrib/hbziparch/ZipAbstractFile.h b/harbour/contrib/hbziparch/ZipAbstractFile.h new file mode 100644 index 0000000000..22b352e8ba --- /dev/null +++ b/harbour/contrib/hbziparch/ZipAbstractFile.h @@ -0,0 +1,74 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipAbstractFile.h +* Includes the CZipAbstractFile class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPABSTRACTFILE_DOT_H) +#define ZIPARCHIVE_ZIPABSTRACTFILE_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif +#include "ZipExport.h" +#include "ZipString.h" + +class ZIP_API CZipAbstractFile +{ +public: + + enum { begin = SEEK_SET, // 0 + current = SEEK_CUR, // 1 + end = SEEK_END // 2 + }; + CZipAbstractFile(){} + virtual bool Open(LPCTSTR , UINT , bool ){return false;} + virtual void Close() = 0; + virtual void Flush() = 0; + virtual ZIP_FILE_USIZE GetPosition() const = 0; + virtual ZIP_FILE_USIZE Seek(ZIP_FILE_SIZE lOff, int nFrom) = 0; + ZIP_FILE_USIZE Seek(ZIP_FILE_USIZE lOff, bool fromBeginning = true) + { + ZIP_FILE_SIZE offset; + if (lOff > ZIP_FILE_SIZEMAX) + { + offset = GetLength() - lOff; + fromBeginning = !fromBeginning; + } + else + offset = (ZIP_FILE_USIZE)lOff; + + if (fromBeginning) + return Seek(offset, CZipAbstractFile::begin); + else + return Seek(-offset, CZipAbstractFile::end); + } + virtual ZIP_FILE_USIZE GetLength() const = 0; + virtual void SetLength(ZIP_FILE_USIZE nNewLen) = 0; + virtual ZIP_FILE_USIZE SeekToBegin(){return Seek(0, begin);} + virtual ZIP_FILE_USIZE SeekToEnd(){return Seek(0, end);} + virtual CZipString GetFilePath() const = 0; + virtual UINT Read(void *lpBuf, UINT nCount) = 0; + virtual void Write(const void* lpBuf, UINT nCount) = 0; + virtual bool IsClosed() const = 0; + virtual ~CZipAbstractFile(){}; + +}; + + + +#endif // !defined(ZIPARCHIVE_ZIPABSTRACTFILE_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipAesCryptograph.cpp b/harbour/contrib/hbziparch/ZipAesCryptograph.cpp new file mode 100644 index 0000000000..b0870db342 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipAesCryptograph.cpp @@ -0,0 +1,16 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + diff --git a/harbour/contrib/hbziparch/ZipAesCryptograph.h b/harbour/contrib/hbziparch/ZipAesCryptograph.h new file mode 100644 index 0000000000..d0a1914a24 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipAesCryptograph.h @@ -0,0 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + diff --git a/harbour/contrib/hbziparch/ZipArchive.cpp b/harbour/contrib/hbziparch/ZipArchive.cpp new file mode 100644 index 0000000000..406aa00ef2 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipArchive.cpp @@ -0,0 +1,3152 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipArchive.h" +#include "ZipPlatform.h" +#include "ZipCompatibility.h" +#include "Wildcard.h" +#include "BytesWriter.h" + +#include + +using namespace ZipArchiveLib; + +const char CZipArchive::m_gszCopyright[] = {"ZipArchive Library Copyright (C) 2000 - 2007 Artpol Software - Tadeusz Dracz"}; +const char CZipArchive::m_gszVersion[] = {"3.2.0"}; + +void CZipAddNewFileInfo::Defaults() +{ + m_iSmartLevel = CZipArchive::zipsmSafeSmart; + m_uReplaceIndex = ZIP_FILE_INDEX_UNSPECIFIED; + m_nBufSize = 65536; + m_iComprLevel = -1; // default +} + + + + CZipArchive:: CZipArchive() +{ + Initialize(); +} + +void CZipArchive::Initialize() +{ + m_bRemoveDriveLetter = true; + m_bExhaustiveRead = false; + m_bAutoFlush = false; + m_iFileOpened = nothing; + SetCaseSensitivity(ZipPlatform::GetSystemCaseSensitivity()); + m_uCompressionMethod = CZipCompressor::methodDeflate; + m_iEncryptionMethod = CZipCryptograph::encStandard; + m_pCryptograph = NULL; + m_pCompressor = NULL; + m_iBufferSize = 65536; +} + + + CZipArchive::~ CZipArchive() +{ + // Close(); // cannot be here: if an exception is thrown strange things can happen + ClearCompressor(); + ClearCryptograph(); +} + +bool CZipArchive::Open(LPCTSTR szPathName, int iMode, ZIP_SIZE_TYPE uVolumeSize) +{ + if (!IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive already opened.\n"); + return false; + } + m_storage.Open(szPathName, iMode, uVolumeSize); + OpenInternal(iMode); + return true; +} + +bool CZipArchive::Open(CZipAbstractFile& af, int iMode) +{ + if (!IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is already opened.\n"); + return false; + } + if (iMode != zipOpen && iMode != zipOpenReadOnly && iMode != zipCreate && iMode != zipCreateAppend) + { + ZIPTRACE("%s(%i) : Mode is not supported.\n"); + return false; + } + m_storage.Open(af, iMode); + OpenInternal(iMode); + return true; +} + +bool CZipArchive::OpenFrom( CZipArchive& zip) +{ + if (zip.IsClosed()) + { + ZIPTRACE("%s(%i) : The source archive must be opened.\n"); + return false; + } + if (!zip.IsReadOnly()) + { + ZIPTRACE("%s(%i) : The source archive must be opened in the read-only mode.\n"); + return false; + } + if (zip.m_storage.m_bInMemory) + { + ZIPTRACE("%s(%i) : ZipArchive cannot share an archive in memory.\n"); + return false; + } + + m_storage.Open(zip.GetArchivePath(), CZipArchive::zipOpenReadOnly, zip.m_storage.IsSplit() ? 1 : 0); + InitOnOpen(zip.GetSystemCompatibility(), &zip.m_centralDir); + + return true; +} + +void CZipArchive::InitOnOpen(int iArchiveSystCompatib, CZipCentralDir* pSource) +{ + m_pszPassword.Release(); + m_iFileOpened = nothing; + m_szRootPath.Empty(); + m_centralDir.Init(&m_storage, &m_callbacks, &m_stringSettings, pSource); + m_iArchiveSystCompatib = iArchiveSystCompatib; +} + +void CZipArchive::OpenInternal(int iMode) +{ + InitOnOpen(ZipPlatform::GetSystemID()); + if ((iMode == zipOpen) ||(iMode == zipOpenReadOnly)) + { + m_centralDir.Read(m_bExhaustiveRead); + // if there is at least one file, get system comp. from the first one + if (m_centralDir.IsValidIndex(0)) + { + int iSystemComp = m_centralDir[0]->GetSystemCompatibility(); + if (ZipCompatibility::IsPlatformSupported(iSystemComp)) + m_iArchiveSystCompatib = iSystemComp; + } + } +} + +void CZipArchive::ThrowError(int err) +{ + CZipException::Throw(err, IsClosed() ? _T("") : (LPCTSTR)m_storage.m_pFile->GetFilePath()); +} + +bool CZipArchive::GetFileInfo(CZipFileHeader & fhInfo, ZIP_INDEX_TYPE uIndex) const +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (!m_centralDir.IsValidIndex(uIndex)) + return false; + + fhInfo = *(m_centralDir[uIndex]); + return true; +} + +CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return NULL; + } + + if (!m_centralDir.IsValidIndex(uIndex)) + return NULL; + return m_centralDir[uIndex]; +} + +const CZipFileHeader* CZipArchive::GetFileInfo(ZIP_INDEX_TYPE uIndex) const +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return NULL; + } + + if (!m_centralDir.IsValidIndex(uIndex)) + return NULL; + return m_centralDir[uIndex]; +} + + + +ZIP_INDEX_TYPE CZipArchive::FindFile(LPCTSTR lpszFileName, int iCaseSensitive, bool bFileNameOnly) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return ZIP_FILE_INDEX_NOT_FOUND; + } + bool bCS; + bool bSporadically; + switch (iCaseSensitive) + { + case ffCaseSens: + bCS = true; + bSporadically = true; + break; + case ffNoCaseSens: + bCS = false; + bSporadically = true; + break; + default: + bCS = m_bCaseSensitive; + bSporadically = false; + } + return m_centralDir.FindFile(lpszFileName, bCS, bSporadically, bFileNameOnly); +} + +bool CZipArchive::OpenFile(ZIP_INDEX_TYPE uIndex) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (!m_centralDir.IsValidIndex(uIndex)) + { + ASSERT(FALSE); + return false; + } + if (m_storage.IsSegmented() == 1) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot extract from a segmented archive in creation.\n"); + return false; + } + + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : A file already opened.\n"); + return false; + } + + m_centralDir.OpenFile(uIndex); + + // check it now, not when reading central to allow reading information + // but disallow extraction now - unsupported method + if (!CZipCompressor::IsCompressionSupported(CurrentFile()->m_uMethod)) + { + m_centralDir.CloseFile(true); + ZIPTRACE("%s(%i) : The compression method is not supported.\n"); + return false; + } + + if (CurrentFile()->IsEncrypted()) + { + if (m_pszPassword.GetSize() == 0) + { + ZIPTRACE("%s(%i) : Password not set for the encrypted file.\n"); + ThrowError(CZipException::badPassword); + } + CreateCryptograph(CurrentFile()->m_uEncryptionMethod); + if (!m_pCryptograph->InitDecode(m_pszPassword, *CurrentFile(), m_storage)) + ThrowError(CZipException::badPassword); + + } + else + { + ClearCryptograph(); + if (m_pszPassword.GetSize() != 0) + { + ZIPTRACE("%s(%i) : Password set for a not encrypted file. Ignoring password.\n"); + } + } + + CreateCompressor(CurrentFile()->m_uMethod); + m_pCompressor->InitDecompression(CurrentFile(), m_pCryptograph); + + m_iFileOpened = extract; + return true; +} + +CZipFileHeader* CZipArchive::CurrentFile() +{ + ASSERT(m_centralDir.m_pOpenedFile); + return m_centralDir.m_pOpenedFile; +} + +DWORD CZipArchive::ReadFile(void *pBuf, DWORD uSize) +{ + if (m_iFileOpened != extract) + { + ZIPTRACE("%s(%i) : Current file must be opened.\n"); + return 0; + } + + if (!pBuf || !uSize) + return 0; + + return m_pCompressor->Decompress(pBuf, uSize); +} + + +void CZipArchive::Close(int iAfterException, bool bUpdateTimeStamp) +{ + // if after an exception - the archive may be closed, but the file may be opened + if (IsClosed() && (!iAfterException || IsClosed(false))) + { + ZIPTRACE("%s(%i) : ZipArchive is already closed.\n"); + return; + } + + if (m_iFileOpened == extract) + CloseFile(NULL, iAfterException != afNoException); + + if (m_iFileOpened == compress) + CloseNewFile(iAfterException != afNoException); + + bool bWrite = iAfterException != afAfterException && !IsClosed(false);// in segmented archive when user aborts + + if (bWrite) + WriteCentralDirectory(false); // we will flush in CZipStorage::Close + + time_t tNewestTime = 0; + + if (bUpdateTimeStamp) + { + ZIP_INDEX_TYPE iSize = (ZIP_INDEX_TYPE)m_centralDir.GetCount(); + for (ZIP_INDEX_TYPE i = 0; i < iSize; i++) + { + time_t tFileInZipTime = m_centralDir[i]->GetTime(); + if (tFileInZipTime > tNewestTime) + tNewestTime = tFileInZipTime; + } + } + m_centralDir.Close(); + m_stringSettings.Reset(); + CZipString szFileName = m_storage.Close(!bWrite); + if (bUpdateTimeStamp && !szFileName.IsEmpty()) + ZipPlatform::SetFileModTime(szFileName, tNewestTime); +} + +void CZipArchive::WriteCentralDirectory(bool bFlush) +{ + m_centralDir.Write(); + if (bFlush) + m_storage.Flush(); +} + +void CZipArchive::SetAdvanced(int iWriteBuffer, int iGeneralBuffer, int iSearchBuffer) +{ + if (!IsClosed()) + { + ZIPTRACE("%s(%i) : Set these options before opening the archive.\n"); + return; + } + + m_storage.m_iWriteBufferSize = iWriteBuffer < 1024 ? 1024 : iWriteBuffer; + m_iBufferSize = iGeneralBuffer < 1024 ? 1024 : iGeneralBuffer; + m_storage.m_iLocateBufferSize = iSearchBuffer < 1024 ? 1024 : iSearchBuffer; +} + +int CZipArchive::CloseFile(CZipFile &file) +{ + CZipString temp = file.GetFilePath(); + file.Close(); + return CloseFile(temp); +} + +int CZipArchive::CloseFile(LPCTSTR lpszFilePath, bool bAfterException) +{ + if (m_iFileOpened != extract) + { + ZIPTRACE("%s(%i) : No opened file.\n"); + return 0; + } + + int iRet = 1; + if (bAfterException) + m_pCompressor->FinishDecompression(true); + else + { + if (m_pCompressor->m_uUncomprLeft == 0) + { + if (m_centralDir.IsConsistencyCheckOn(checkCRC) + && !CurrentFile()->m_bIgnoreCrc32 + && m_pCompressor->m_uCrc32 != CurrentFile()->m_uCrc32) + ThrowError(CZipException::badCrc); + } + else + iRet = -1; + + m_pCompressor->FinishDecompression(false); + + if (lpszFilePath) + { + if (!ZipPlatform::SetFileModTime(lpszFilePath, CurrentFile()->GetTime()) + ||!ZipPlatform::SetFileAttr(lpszFilePath, CurrentFile()->GetSystemAttr())) + iRet = -2; + } + if (m_pCryptograph) + m_pCryptograph->FinishDecode(*CurrentFile(), m_storage); + } + + m_centralDir.CloseFile(bAfterException); + + m_iFileOpened = nothing; + ClearCryptograph(); + return iRet; +} + +bool CZipArchive::OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpszFilePath, + ZIP_INDEX_TYPE uReplaceIndex) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : A file already opened.\n"); + return false; + } + + if (m_storage.IsSegmented() == -1) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot add files to an existing segmented archive.\n"); + return false; + } + + if (GetCount() ==(WORD)USHRT_MAX) + { + ZIPTRACE("%s(%i) : Maximum file count inside archive reached.\n"); + return false; + } + + DWORD uAttr = 0; + time_t ttime; + if (lpszFilePath) + { + if (!ZipPlatform::GetFileAttr(lpszFilePath, uAttr)) + // do not continue - if the file was a directory then not recognizing it will cause + // serious errors (need uAttr to recognize it) + return false; + ZipPlatform::GetFileModTime(lpszFilePath, ttime); + } + + if (lpszFilePath) + { + header.SetTime(ttime); + SetFileHeaderAttr(header, uAttr); // set system compatibility as well + } + else + { + header.SetSystemCompatibility(m_iArchiveSystCompatib); + if (!header.HasTime()) + header.SetTime(time(NULL)); + } + + CZipString szFileName = header.GetFileName(); + + + bool bIsDirectory = header.IsDirectory(); + if (bIsDirectory) + { + int iNameLen = szFileName.GetLength(); + if (!iNameLen || !CZipPathComponent::IsSeparator(szFileName[iNameLen-1])) + { + szFileName += CZipPathComponent::m_cSeparator; + header.SetFileName(szFileName); + } + } + + if (szFileName.IsEmpty()) + { + szFileName.Format(_T("file%u"), GetCount()); + header.SetFileName(szFileName); + } + + bool bEncrypted = WillEncryptNextFile(); + +#if defined _DEBUG && !defined NOZIPTRACE + if (bIsDirectory && bEncrypted) + ZIPTRACE("%s(%i) : Encrypting a directory. You may want to consider clearing the password before adding a directory.\n"); +#endif + + bool bReplace = uReplaceIndex != ZIP_FILE_INDEX_UNSPECIFIED; + + if (iLevel < -1 || iLevel > 9) + iLevel = -1; + + if (bEncrypted) + { + header.m_uEncryptionMethod = (BYTE)m_iEncryptionMethod; + CreateCryptograph(m_iEncryptionMethod); + } + else + { + header.m_uEncryptionMethod = CZipCryptograph::encNone; + ClearCryptograph(); + } + + if (iLevel == 0 || bIsDirectory) + header.m_uMethod = CZipCompressor::methodStore; + else + header.m_uMethod = m_uCompressionMethod; + + CreateCompressor(header.m_uMethod); + CZipFileHeader* pHeader = m_centralDir.AddNewFile(header, uReplaceIndex, iLevel); + + // replace can happen only from AddNewFile and the compressed size is already known and set (the file is stored, not compressed) + if (bReplace) + { + // this will be used in GetLocalSize and WriteLocal + pHeader->PrepareFileName(); + // we use the local size, because the real does not exist yet + ZIP_SIZE_TYPE uFileSize = pHeader->GetDataSize(true, false) + pHeader->GetLocalSize(false) + pHeader->GetDataDescriptorSize(&m_storage); + InitBuffer(); + MakeSpaceForReplace(uReplaceIndex, uFileSize, szFileName); + ReleaseBuffer(); + } + + CurrentFile()->WriteLocal(&m_storage); + + if (m_pCryptograph) + m_pCryptograph->InitEncode(m_pszPassword, *pHeader, m_storage); + + m_pCompressor->InitCompression(iLevel, CurrentFile(), m_pCryptograph); + + m_iFileOpened = compress; + return true; +} + + +bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, + LPCTSTR lpszPath, + bool bFullPath, + LPCTSTR lpszNewName, + DWORD nBufSize) +{ + + if (!nBufSize && !lpszPath) + return false; + + CZipFileHeader* pHeader = (*this)[uIndex]; + CZipString szFileNameInZip = pHeader->GetFileName(); + CZipString szFile = PredictExtractedFileName(szFileNameInZip, lpszPath, bFullPath, lpszNewName); + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbExtract); + if (pCallback) + pCallback->Init(szFileNameInZip, szFile); + + + if (pHeader->IsDirectory()) + { + if (pCallback) + pCallback->SetTotal(0); // in case of calling LeftToProcess() afterwards + + ZipPlatform::ForceDirectory(szFile); + ZipPlatform::SetFileAttr(szFile, pHeader->GetSystemAttr()); + + if (pCallback) + pCallback->CallbackEnd(); + return true; + } + else + { + if (!OpenFile(uIndex)) + return false; + if (pCallback) + pCallback->SetTotal(pHeader->m_uUncomprSize); + + CZipPathComponent zpc(szFile); + ZipPlatform::ForceDirectory(zpc.GetFilePath()); + CZipFile f(szFile, CZipFile::modeWrite | + CZipFile::modeCreate | CZipFile::shareDenyWrite); + DWORD iRead; + CZipAutoBuffer buf(nBufSize); + int iAborted = 0; + for(;;) + { + iRead = ReadFile(buf, buf.GetSize()); + if (!iRead) + { + if (pCallback && !pCallback->RequestLastCallback()) + iAborted = CZipException::abortedSafely; + break; + } + f.Write(buf, iRead); + if (pCallback && !pCallback->RequestCallback(iRead)) + { + if (iRead == buf.GetSize() && ReadFile(buf, 1) != 0) // test one byte if there is something left + iAborted = CZipException::abortedAction; + else + iAborted = CZipException::abortedSafely; + break; + } + } + + if (pCallback) + { + if (!iAborted) + { + bool bRet = CloseFile(f) == 1; + pCallback->CallbackEnd(); + return bRet; + } + else + { + if (iAborted == CZipException::abortedAction) + CloseFile(NULL, true); + else + { + bool bRet; + try + { + bRet = CloseFile(f) == 1; + } + // if any exception was thrown, then we are not successful + // catch all exceptions to throw aborted exception only +#ifdef ZIP_ARCHIVE_MFC + catch(CException* e) + { + e->Delete(); + bRet = false; + } +#endif + catch(...) + { + bRet = false; + } + if (!bRet) + { + CloseFile(NULL, true); + iAborted = CZipException::abortedAction; + } + } + + pCallback->CallbackEnd(); + CZipException::Throw(iAborted, szFile); + return false; // for the compiler + } + } + else + return CloseFile(f) == 1; + } +} + +bool CZipArchive::ExtractFile(ZIP_INDEX_TYPE uIndex, + CZipMemFile& mf, + bool bRewind, + DWORD nBufSize) +{ + if (!nBufSize) + return false; + + CZipFileHeader* pHeader = (*this)[uIndex]; + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbExtract); + if (pCallback) + pCallback->Init(pHeader->GetFileName()); + + if (pHeader->IsDirectory() || !OpenFile(uIndex)) + return false; + + if (pCallback) + pCallback->SetTotal(pHeader->m_uUncomprSize); + + + CZipAutoBuffer buf(nBufSize); + //mf.SeekToEnd(); + ZIP_FILE_USIZE oldPos = 0; + + if (bRewind) + oldPos = mf.GetPosition(); + + DWORD iRead; + int iAborted = 0; + for(;;) + { + iRead = ReadFile(buf, buf.GetSize()); + if (!iRead) + { + if (pCallback && !pCallback->RequestLastCallback()) + iAborted = CZipException::abortedSafely; + break; + } + mf.Write(buf, iRead); + if (pCallback && !pCallback->RequestCallback(iRead)) + { + if (iRead == buf.GetSize() && ReadFile(buf, 1) != 0) // test one byte if there is something left + iAborted = CZipException::abortedAction; + else + iAborted = CZipException::abortedSafely; // we did it! + break; + } + } + + bool bRet; + if (pCallback) + { + if (!iAborted) + { + bRet = CloseFile() == 1; + pCallback->CallbackEnd(); + } + else + { + if (iAborted == CZipException::abortedAction) + CloseFile(NULL, true); + else + { + bRet = false; + try + { + bRet = CloseFile() == 1; + } + // if any exception was thrown, then we are not successful + // catch all exceptions to thrown aborted exception only + #ifdef ZIP_ARCHIVE_MFC + catch(CException* e) + { + e->Delete(); + bRet = false; + } + #endif + catch(...) + { + bRet = false; + } + if (!bRet) + { + CloseFile(NULL, true); + iAborted = CZipException::abortedAction; + } + } + + pCallback->CallbackEnd(); + if (bRewind) + mf.Seek(oldPos, CZipMemFile::begin); + CZipException::Throw(iAborted); + return false; // for the compiler + } + } + else + bRet = CloseFile() == 1; + + if (bRewind) + mf.Seek(oldPos, CZipMemFile::begin); + return bRet; +} + + +bool CZipArchive::WriteNewFile(const void *pBuf, DWORD uSize) +{ + if (m_iFileOpened != compress) + { + ZIPTRACE("%s(%i) : A new file must be opened.\n"); + return false; + } + + m_pCompressor->Compress(pBuf, uSize); + return true; +} + +bool CZipArchive::CloseNewFile(bool bAfterException) +{ + if (m_iFileOpened != compress) + { + ZIPTRACE("%s(%i) : A new file must be opened.\n"); + return false; + } + + m_pCompressor->FinishCompression(bAfterException); + if (bAfterException) + m_centralDir.m_pOpenedFile = NULL; + else + { + if (m_pCryptograph) + m_pCryptograph->FinishEncode(*CurrentFile(), m_storage); + + m_centralDir.CloseNewFile(); + } + m_iFileOpened = nothing; + ClearCryptograph(); + if (m_bAutoFlush && !bAfterException) + Flush(); + + return true; +} + +bool CZipArchive::RemoveFile(ZIP_INDEX_TYPE uIndex) +{ + CZipIndexesArray indexes; + indexes.Add(uIndex); + return RemoveFiles(indexes); +} + +void CZipArchive::GetIndexes(const CZipStringArray &aNames, CZipIndexesArray& aIndexes) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return; + } + ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)aNames.GetSize(); + for (ZIP_INDEX_TYPE i = 0; i < uSize; i++) + aIndexes.Add(FindFile(aNames[(ZIP_ARRAY_SIZE_TYPE)i], ffDefault, false)); +} + +bool CZipArchive::RemoveFiles(const CZipStringArray &aNames) +{ + CZipIndexesArray indexes; + GetIndexes(aNames, indexes); + return RemoveFiles(indexes); +} + +struct CZipDeleteInfo +{ + CZipDeleteInfo(){m_pHeader = NULL; m_bDelete = false;} + CZipDeleteInfo(CZipFileHeader* pHeader, bool bDelete) + :m_pHeader(pHeader), m_bDelete (bDelete){} + CZipFileHeader* m_pHeader; + bool m_bDelete; +}; + +bool CZipArchive::RemoveFiles(CZipIndexesArray &aIndexes) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_storage.IsSegmented()) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot delete files from a segmented archive.\n"); + return false; + } + + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot delete files if there is a file opened.\n"); + return false; + } + + if (GetCount() == 0) + { + ZIPTRACE("%s(%i) : There is nothing to delete: the archive is empty.\n"); + return false; + } + + ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)aIndexes.GetSize(); + if (!uSize) + { + ZIPTRACE("%s(%i) : The indexes array is empty.\n"); + return true; + } + + aIndexes.Sort(true); + // remove all - that's easy so don't waste the time + if (uSize == GetCount()) + { + // check that the indexes are correct + bool allIncluded = true; + // iterate all indexes, if all are sorted then the condition should always be true + for (ZIP_INDEX_TYPE i = 0; i < uSize; i++) + if (aIndexes[(ZIP_ARRAY_SIZE_TYPE)i] != i) + { + allIncluded = false; + break; + } + + if (allIncluded) + { + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbDelete); + if (pCallback) + { + // do it right and sent the notification + pCallback->Init(); + pCallback->SetTotal(uSize); + } + + m_centralDir.RemoveFromDisk(); + m_storage.m_pFile->SetLength((ZIP_FILE_USIZE) m_storage.m_uBytesBeforeZip); + m_centralDir.RemoveAll(); + if (m_bAutoFlush) + Flush(); + if (pCallback) + pCallback->CallbackEnd(); + return true; + } + } + else + { + for (ZIP_INDEX_TYPE i = 0; i < uSize; i++) + if (!m_centralDir.IsValidIndex(aIndexes[(ZIP_ARRAY_SIZE_TYPE)i])) + return false; + } + + ZIP_INDEX_TYPE i; + + CZipArray aInfo; + + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbDeleteCnt); + if (pCallback) + { + pCallback->Init(); + pCallback->SetTotal(GetCount()); + } + + ZIP_INDEX_TYPE uDelIndex = 0; + ZIP_INDEX_TYPE uMaxDelIndex = aIndexes[(ZIP_ARRAY_SIZE_TYPE)(uSize - 1)]; + i = aIndexes[0]; + // GetCount() is greater than 0 (checked before) and when it is unsigned we do not cause overflow + ZIP_INDEX_TYPE uLastPosition = (ZIP_INDEX_TYPE)(GetCount() - 1); + bool bAborted = false; + if (i <= uLastPosition) + for(;;) + { + CZipFileHeader* pHeader = m_centralDir[i]; + bool bDelete; + if (i <= uMaxDelIndex && i == aIndexes[(ZIP_ARRAY_SIZE_TYPE)uDelIndex]) + { + uDelIndex++; + bDelete = true; + } + else + bDelete = false; + aInfo.Add(CZipDeleteInfo(pHeader, bDelete)); + if (i == uLastPosition) + { + if (pCallback && !pCallback->RequestLastCallback(1)) + bAborted = true; + break; + } + else + { + if (pCallback && !pCallback->RequestCallback()) + { + bAborted = true; + break; + } + i++; + } + } + + ASSERT(uDelIndex == uSize); + + if (pCallback) + { + pCallback->CallbackEnd(); + if (bAborted) + ThrowError(CZipException::abortedSafely); + } + + uSize = (ZIP_INDEX_TYPE)aInfo.GetSize(); + if (!uSize) // it is possible + return true; + + // they should already be sorted after reading the in CZipCentralDir::ReadHeaders and when replacing, the index is placed at the same place as the old one + //aInfo.Sort(true); // sort by offsets (when operators uncommented in CZipDeleteInfo) + + // now we start deleting (not safe to break) + pCallback = GetCallback(CZipActionCallback::cbDelete); + if (pCallback) + pCallback->Init(); + + m_centralDir.RemoveFromDisk(); + + ZIP_SIZE_TYPE uTotalToMoveBytes = 0, uLastOffset = m_storage.GetLastDataOffset(); + // count the number of bytes to move + i = uSize; + while(i > 0) + { + i--; + // cannot use a decreasing loop because i is unsigned and instead negative at the end of the loop it will be maximum positive + const CZipDeleteInfo& di = aInfo[(ZIP_ARRAY_SIZE_TYPE)i]; + if (!di.m_bDelete) + uTotalToMoveBytes += uLastOffset - di.m_pHeader->m_uOffset; + uLastOffset = di.m_pHeader->m_uOffset; + } + + if (pCallback) + pCallback->SetTotal(uTotalToMoveBytes); + + + InitBuffer(); + + ZIP_SIZE_TYPE uMoveBy = 0, uOffsetStart = 0; + for (i = 0; i < uSize; i++) + { + const CZipDeleteInfo& di = aInfo[(ZIP_ARRAY_SIZE_TYPE)i]; + + if (di.m_bDelete) + { + // next hole + ZIP_SIZE_TYPE uTemp = di.m_pHeader->m_uOffset; + m_centralDir.RemoveFile(di.m_pHeader); // first remove + if (uOffsetStart) + { + // copy the files over a previous holes + MovePackedFiles(uOffsetStart, uTemp, uMoveBy, pCallback, false, false); + uOffsetStart = 0; // never be at the beginning, because the first file is always to be deleted + } + if (i == uSize - 1) + uTemp = (m_storage.GetLastDataOffset()) - uTemp; + else + uTemp = aInfo[(ZIP_ARRAY_SIZE_TYPE)(i + 1)].m_pHeader->m_uOffset - uTemp; + + uMoveBy += uTemp; + + } + else + { + if (uOffsetStart == 0) // find continuous area to move + uOffsetStart = di.m_pHeader->m_uOffset; + di.m_pHeader->m_uOffset -= uMoveBy; + } + } + + if (uOffsetStart) + { + // will call the last callback, if necessary + MovePackedFiles(uOffsetStart, m_storage.GetLastDataOffset(), uMoveBy, pCallback); + } + else + { + // call last callback (it was not called in the MovePackedFiles calls in the loop) + if (pCallback && !pCallback->RequestLastCallback()) + { + pCallback->CallbackEnd(); + ThrowError(CZipException::abortedAction); + } + } + + ReleaseBuffer(); + if (uMoveBy) // just in case + m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(m_storage.m_pFile->GetLength() - uMoveBy)); + + if (pCallback) + pCallback->CallbackEnd(); + + if (m_bAutoFlush) + Flush(); + return true; +} + + + +bool CZipArchive::ShiftData(ZIP_SIZE_TYPE uOffset) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n"); + return false; + } + + if (m_storage.IsSegmented() != 0) + { + ZIPTRACE("%s(%i) : Cannot shift data for a segmented archive.\n"); + return false; + } + + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : A file should not be opened.\n"); + return false; + } + + if (m_storage.m_uBytesBeforeZip != 0) + { + ZIPTRACE("%s(%i) : Bytes before zip file must not be present.\n"); + return false; + } + + if (uOffset == 0) + return true; + + m_centralDir.RemoveFromDisk(); // does m_storage.Flush(); + InitBuffer(); + + ZIP_SIZE_TYPE uFileLen = (ZIP_SIZE_TYPE)m_storage.m_pFile->GetLength(); + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbMoveData); + if (pCallback) + { + pCallback->Init(NULL, GetArchivePath()); + pCallback->SetTotal(uFileLen); + } + + m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + uOffset)); // ensure the seek is correct + + MovePackedFiles(0, uFileLen, uOffset, pCallback, true); + + ZIP_INDEX_TYPE uSize = GetCount(); + for (ZIP_INDEX_TYPE i = 0; i < uSize; i++) + m_centralDir[i]->m_uOffset += uOffset; + + if (pCallback) + pCallback->CallbackEnd(); + + return true; +} + +bool CZipArchive::PrependData(LPCTSTR lpszFilePath, LPCTSTR lpszNewExt) +{ + CZipFile file(lpszFilePath, CZipFile::modeRead | CZipFile::shareDenyNone); + return PrependData(file, lpszNewExt); +} + +bool CZipArchive::PrependData(CZipAbstractFile& file, LPCTSTR lpszNewExt) +{ + if (file.IsClosed()) + { + ZIPTRACE("%s(%i) : File to prepend should be opened.\n"); + return false; + } + + ZIP_SIZE_TYPE uOffset = (ZIP_SIZE_TYPE)file.GetLength(); + if (uOffset == 0) + return true; + + if (!ShiftData(uOffset)) + return false; + file.SeekToBegin(); + // do not use callback - self-extracting stubs should be small + m_storage.Seek(0); + + char* buf = (char*)m_pBuffer; + + ZIP_SIZE_TYPE uTotalToMove = uOffset; + ZIP_SIZE_TYPE uToRead; + UINT uSizeRead; + bool bBreak = false; + DWORD bufSize = m_pBuffer.GetSize(); + do + { + uToRead = uTotalToMove > bufSize ? bufSize : uTotalToMove; + uSizeRead = (UINT)file.Read(buf, (UINT)uToRead); + if (!uSizeRead) + break; + uTotalToMove -= uSizeRead; + if (uTotalToMove == 0) + bBreak = true; + m_storage.m_pFile->Write(buf, uSizeRead); + } + while (!bBreak); + + if (m_storage.m_bInMemory || lpszNewExt == NULL) + return true; + + CZipString szInitialPath = m_storage.m_pFile->GetFilePath(); + // must close to rename + Close(); + CZipPathComponent zpc(szInitialPath); + zpc.SetExtension(lpszNewExt); + CZipString szNewPath = zpc.GetFullPath(); + if (!ZipPlatform::RenameFile(szInitialPath, szNewPath, false)) + return false; +#ifdef ZIP_ARCHIVE_LNX + return ZipPlatform::SetExeAttr(szNewPath); +#else + return true; +#endif +} + +bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath, + int iComprLevel, + bool bFullPath, + int iSmartLevel, + unsigned long nBufSize) +{ + + CZipAddNewFileInfo zanfi (lpszFilePath, bFullPath); + zanfi.m_iComprLevel = iComprLevel; + zanfi.m_iSmartLevel = iSmartLevel; + zanfi.m_nBufSize = nBufSize; + return AddNewFile(zanfi); +} + +bool CZipArchive::AddNewFile(LPCTSTR lpszFilePath, + LPCTSTR lpszFileNameInZip, + int iComprLevel, + int iSmartLevel, + unsigned long nBufSize) +{ + CZipAddNewFileInfo zanfi(lpszFilePath, lpszFileNameInZip); + zanfi.m_iComprLevel = iComprLevel; + zanfi.m_iSmartLevel = iSmartLevel; + zanfi.m_nBufSize = nBufSize; + return AddNewFile(zanfi); +} + +bool CZipArchive::AddNewFile(CZipMemFile& mf, + LPCTSTR lpszFileNameInZip, + int iComprLevel, + int iSmartLevel, + unsigned long nBufSize) +{ + CZipAddNewFileInfo zanfi(&mf, lpszFileNameInZip); + zanfi.m_iComprLevel = iComprLevel; + zanfi.m_iSmartLevel = iSmartLevel; + zanfi.m_nBufSize = nBufSize; + return AddNewFile(zanfi); +} + +/** + A structure for the internal use only. Clears the password if necessary and + restores it later (also in case of an exception). +*/ +struct CZipSmClrPass +{ + CZipSmClrPass() + { + m_pZip = NULL; + } + + void ClearPasswordSmartly( CZipArchive* pZip) + { + m_pZip = pZip; + m_szPass = pZip->GetPassword(); + if (!m_szPass.IsEmpty()) + pZip->SetPassword(); + } + + ~CZipSmClrPass() + { + if (!m_szPass.IsEmpty()) + m_pZip->SetPassword(m_szPass); + } +private: + CZipString m_szPass; + CZipArchive* m_pZip; +}; + +bool CZipArchive::AddNewFile(CZipAddNewFileInfo& info) +{ + // no need for ASSERT and TRACE here - it will be done by OpenNewFile + + if (!m_iBufferSize) + return false; + + if (info.m_pFile) + info.m_szFilePath = info.m_pFile->GetFilePath(); + else + { + CZipPathComponent::RemoveSeparators(info.m_szFilePath); + if (info.m_szFilePath.IsEmpty()) + return false; + } + + bool bSegm = GetSegmMode() != 0; + + // checking the replace index + if (!UpdateReplaceIndex(info.m_uReplaceIndex)) + return false; + + bool bReplace = info.m_uReplaceIndex != ZIP_FILE_INDEX_UNSPECIFIED; + + DWORD uAttr; + time_t ttime; + if (info.m_pFile) + { + uAttr = ZipPlatform::GetDefaultAttributes(); + ttime = time(NULL); + } + else + { + if (!ZipPlatform::GetFileAttr(info.m_szFilePath, uAttr)) + return false; // we don't know whether it is a file or a directory + ZipPlatform::GetFileModTime(info.m_szFilePath, ttime); + } + CZipFileHeader header; + SetFileHeaderAttr(header, uAttr); + if (info.m_szFileNameInZip.IsEmpty()) + info.m_szFileNameInZip = PredictFileNameInZip(info.m_szFilePath, info.m_bFullPath, header.IsDirectory() ? prDir : prFile); + header.SetFileName(info.m_szFileNameInZip); + header.SetTime(ttime); + bool bInternal = (info.m_iSmartLevel & zipsmInternal01) != 0; + + if (header.IsDirectory()) // will never be when m_pFile is not NULL, so we don't check it + { + ASSERT(!info.m_pFile); // should never happened + ASSERT(!bInternal); + + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbAdd); + + if (pCallback) + { + pCallback->Init(info.m_szFileNameInZip, info.m_szFilePath); + pCallback->SetTotal(0); // in case of calling LeftToProcess() afterwards + } + + // clear password for a directory + CZipSmClrPass smcp; + if (info.m_iSmartLevel & zipsmCPassDir) + smcp.ClearPasswordSmartly(this); + + bool bRet = OpenNewFile(header, CZipCompressor::levelStore, NULL, info.m_uReplaceIndex); + + CloseNewFile(); + if (pCallback) + pCallback->CallbackEnd(); + + return bRet; + } + + CZipSmClrPass smcp; + bool bIsCompression = info.m_iComprLevel != 0; + bool bEff = (info.m_iSmartLevel & zipsmCheckForEff)&& bIsCompression; + bool bCheckForZeroSized = (info.m_iSmartLevel & zipsmCPFile0) && WillEncryptNextFile(); + bool bCheckForSmallFiles = (info.m_iSmartLevel & zipsmNotCompSmall) && bIsCompression; + ZIP_SIZE_TYPE uFileSize = ZIP_SIZE_TYPE(-1); + bool bNeedTempArchive = (bEff && bSegm) || (bReplace && bIsCompression); + if (bCheckForSmallFiles || bCheckForZeroSized || bNeedTempArchive) + { + + if (info.m_pFile) + uFileSize = (ZIP_SIZE_TYPE)info.m_pFile->GetLength(); + else + { + if (!ZipPlatform::GetFileSize(info.m_szFilePath, uFileSize) && bEff) + bEff = false; // the file size is needed only when efficient in a segmented archive + } + + if (uFileSize != ZIP_SIZE_TYPE(-1)) + { + if (bCheckForZeroSized && uFileSize == 0) + smcp.ClearPasswordSmartly(this); + if (bCheckForSmallFiles && uFileSize < 5) + info.m_iComprLevel = 0; + } + } + bool bEffInMem = bEff && (info.m_iSmartLevel & zipsmMemoryFlag); + CZipString szTempFileName; + if (bNeedTempArchive && (bEffInMem || + !(szTempFileName = ZipPlatform::GetTmpFileName( + m_szTempPath.IsEmpty() ? NULL : (LPCTSTR)m_szTempPath, uFileSize) + ).IsEmpty())) + { + CZipMemFile* pmf = NULL; + CZipArchive zip; + try + { + // compress first to a temporary file, if ok - copy the data, if not - add storing + + if (bEffInMem) + { + pmf = new CZipMemFile; + zip.Open(*pmf, zipCreate); + } + else + zip.Open(szTempFileName, zipCreate); + zip.SetRootPath(m_szRootPath); + zip.SetPassword(GetPassword()); + zip.SetEncryptionMethod(m_iEncryptionMethod); + zip.SetSystemCompatibility(m_iArchiveSystCompatib); + zip.SetCallback(GetCallback(CZipActionCallback::cbAdd), CZipActionCallback::cbAdd); + // create a temporary file + ZIP_INDEX_TYPE uTempReplaceIndex = info.m_uReplaceIndex; + info.m_iSmartLevel = zipsmLazy; + info.m_uReplaceIndex = ZIP_FILE_INDEX_UNSPECIFIED; + if (!zip.AddNewFile(info)) + throw false; + info.m_uReplaceIndex = uTempReplaceIndex; + + // this may also happen when bReplace, but not in a segmented archive + if (bEff) + { + if (!zip[0]->CompressionEfficient()) + { + info.m_iComprLevel = 0; + info.m_iSmartLevel = zipsmInternal01; + // compression is not efficient, store instead + throw AddNewFile(info); + } + } + zip.m_storage.Flush(); + InitBuffer(); + throw GetFromArchive(zip, 0, NULL, info.m_uReplaceIndex, true, GetCallback(CZipActionCallback::cbAddTmp)); + } + catch (bool bRet) + { + zip.Close(!bRet); // that doesn't really matter how it will be closed + if (pmf) + delete pmf; + if (!bEffInMem) + ZipPlatform::RemoveFile(szTempFileName, false); + ReleaseBuffer(); + return bRet; + } + catch (...) + { + zip.Close(true); + if (pmf) + delete pmf; + if (!bEffInMem) + ZipPlatform::RemoveFile(szTempFileName, false); + ReleaseBuffer(); + throw; + } + } + + // try to open before adding + CZipFile f; + CZipAbstractFile *pf; + if (info.m_pFile) + { + pf = info.m_pFile; + pf->SeekToBegin(); + } + else + { + // cannot be shareDenyWrite + // If you specify the GENERIC_READ and GENERIC_WRITE access modes along with the FILE_SHARE_READ and FILE_SHARE_WRITE sharing modes in your first call to CreateFile. If you specify the GENERIC_READ and GENERIC_WRITE access modes and the FILE_SHARE_READ sharing mode only in your second call to CreateFile, the function will fail with a sharing violation because the read-only sharing mode specified in the second call conflicts with the read/write access that has been granted in the first call. + // Original information was here (but not any longer): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/creating_and_opening_files.asp + if (!f.Open(info.m_szFilePath, CZipFile::modeRead | CZipFile::shareDenyNone, false)) + return false; + pf = &f; + } + + ASSERT(pf); + // call init before opening (in case of exception we have the names) + uFileSize = (ZIP_SIZE_TYPE)pf->GetLength(); + + // predict sizes in local header, so that zip64 can write extra header if needed + header.m_uLocalUncomprSize = uFileSize; + if (!bIsCompression) + header.m_uLocalComprSize = uFileSize; + + bool bRet; + if (bReplace) + { + ASSERT(!bIsCompression); + bRet = OpenNewFile(header, CZipCompressor::levelStore, NULL, info.m_uReplaceIndex); + } + else + bRet = OpenNewFile(header, info.m_iComprLevel); + if (!bRet) + return false; + + // we do it here, because if in OpenNewFile is replacing + // then we get called cbMoveData callback before and it would + // overwrite callback information written in pCallback->Init() + CZipActionCallback* pCallback = GetCallback(bInternal ? CZipActionCallback::cbAddStore : CZipActionCallback::cbAdd); + + if (pCallback) + { + // Init cbAdd here as well - after smart add - to avoid double initiation when + // temporary archive is used - it would init cbAdd again + pCallback->Init(info.m_szFileNameInZip, info.m_szFilePath); + pCallback->SetTotal(uFileSize); + } + + CZipAutoBuffer buf(info.m_nBufSize); + DWORD iRead; + int iAborted = 0; + do + { + iRead = pf->Read(buf, info.m_nBufSize); + if (iRead) + { + WriteNewFile(buf, iRead); + if (pCallback && !pCallback->RequestCallback(iRead)) + { + if (iRead == buf.GetSize() && pf->Read(buf, 1) != 0) // test one byte if there is something left + { + if (!m_storage.IsSegmented() && !bReplace) + { + RemoveLast(true); + iAborted = CZipException::abortedSafely; + } + else + iAborted = CZipException::abortedAction; + // close new file with bException set to true, even if abortedSafely, + // because in that case we have removed the last file - there is nothing to close + CloseNewFile(true); + } + else + // temporary value - possible safe abort + iAborted = CZipException::aborted; + break; + } + } + } + while (iRead == buf.GetSize()); + + if (pCallback) + { + if (!iAborted && !pCallback->RequestLastCallback()) + // temporaty value - safe abort + iAborted = CZipException::aborted; + + if (!iAborted) + { + CloseNewFile(); + pCallback->CallbackEnd(); + } + else + { + // possible safe abort + if (iAborted == CZipException::aborted) + { + bool bRet; + try + { + bRet = CloseNewFile(); + } +#ifdef ZIP_ARCHIVE_MFC + catch(CException* e) + { + e->Delete(); + bRet = false; + } +#endif + catch(...) + { + bRet = false; + } + if (bRet) + iAborted = CZipException::abortedSafely; + else + { + CloseNewFile(true); + iAborted = CZipException::abortedAction; + } + } + pCallback->CallbackEnd(); + CZipException::Throw(iAborted); // throw to distinguish from other return codes + } + } + else + CloseNewFile(); + + if (bEff) + { + // remove the last file and add it without the compression if needed + if (!info.m_pFile) + f.Close(); + + buf.Release(); + if (RemoveLast()) + { + info.m_iComprLevel = 0; + info.m_iSmartLevel = zipsmInternal01; + return AddNewFile(info); + } + } + return true; +} + +bool CZipArchive::RemoveLast(bool bRemoveAnyway) +{ + if (GetCount() == 0) + return false; + ZIP_INDEX_TYPE uIndex = (ZIP_INDEX_TYPE)(GetCount() - 1); + CZipFileHeader* pHeader = m_centralDir[uIndex]; + + if (!bRemoveAnyway && pHeader->CompressionEfficient()) + return false; + + m_centralDir.RemoveLastFile(pHeader, uIndex); + return true; +} + +class CZipRootPathRestorer +{ + CZipString m_szOldRootPath; + CZipArchive* m_pZip; +public: + CZipRootPathRestorer() + { + m_pZip = NULL; + } + void SetNewRootPath( CZipArchive* pZip, LPCTSTR lpszNewRoot) + { + m_pZip = pZip; + m_szOldRootPath = m_pZip->GetRootPath(); + m_pZip->SetRootPath(lpszNewRoot); + } + ~CZipRootPathRestorer() + { + if (m_pZip) + m_pZip->SetRootPath(m_szOldRootPath); + } +}; + +class CCalculateAddFilesEnumerator : public ZipArchiveLib::CDirEnumerator +{ + CZipActionCallback* m_pCallback; +public: + ZIP_FILE_USIZE m_uTotalBytes; + ZIP_FILE_USIZE m_uTotalFiles; + CCalculateAddFilesEnumerator(LPCTSTR lpszDirectory, bool bRecursive, CZipActionCallback* pCallback) + :ZipArchiveLib::CDirEnumerator(lpszDirectory, bRecursive) + { + m_pCallback = pCallback; + m_uTotalFiles = m_uTotalBytes = 0; + } +protected: + void OnEnumerationBegin() + { + if (m_pCallback) + m_pCallback->Init(); + } + + bool Process(LPCTSTR, const ZipArchiveLib::CFileInfo& info) + { + m_uTotalFiles++; + m_uTotalBytes += info.m_uSize; + if (m_pCallback && !m_pCallback->RequestCallback()) + return false; + else + return true; + } + + void OnEnumerationEnd(bool bResult) + { + if (m_pCallback) + { + if (bResult) + bResult = m_pCallback->RequestLastCallback(); + m_pCallback->CallbackEnd(); + // can be false only, if the callback returns false + if (!bResult) + CZipException::Throw(CZipException::abortedSafely); + } + } +}; + +class CAddFilesEnumerator : public ZipArchiveLib::CDirEnumerator +{ + CZipArchive* m_pZip; + CZipActionCallback* m_pMultiCallback; + int m_iComprLevel; + int m_iSmartLevel; + unsigned long m_nBufSize; +public: + CAddFilesEnumerator(LPCTSTR lpszDirectory, + bool bRecursive, + CZipArchive* pZip, + int iComprLevel, + int iSmartLevel, + unsigned long nBufSize, + CZipActionCallback* pMultiCallback) + :ZipArchiveLib::CDirEnumerator(lpszDirectory, bRecursive), m_pZip(pZip) + { + m_iComprLevel = iComprLevel; + m_nBufSize = nBufSize; + m_iSmartLevel = iSmartLevel; + m_pMultiCallback = pMultiCallback; + } +protected: + bool Process(LPCTSTR lpszPath, const ZipArchiveLib::CFileInfo&) + { + bool ret = m_pZip->AddNewFile(lpszPath, m_iComprLevel, m_pZip->GetRootPath().IsEmpty() != 0, m_iSmartLevel, m_nBufSize); + if (ret && m_pMultiCallback) + if (!m_pMultiCallback->MultiActionsNext()) + CZipException::Throw(CZipException::abortedSafely); + return ret; + } +}; + +bool CZipArchive::AddNewFiles(LPCTSTR lpszPath, + CFileFilter& filter, + bool bRecursive, + int iComprLevel, + bool bSkipInitialPath, + int iSmartLevel, + unsigned long nBufSize) +{ + CZipRootPathRestorer restorer; + if (bSkipInitialPath) + restorer.SetNewRootPath(this, lpszPath); + + CZipActionCallback* pMultiCallback = GetCallback(CZipActionCallback::cbMultiAdd); + if (pMultiCallback) + { + // if multi callback is set, calculate total data to process + // call cbCalculateForMulti in the meantime + CCalculateAddFilesEnumerator calculateEnumerator(lpszPath, bRecursive, GetCallback(CZipActionCallback::cbCalculateForMulti)); + if (!calculateEnumerator.Start(filter)) + return false; + if (pMultiCallback->m_iType != CZipActionCallback::cbMultiAdd) + // may happen, if it is the same as calculate + pMultiCallback->m_iType = CZipActionCallback::cbMultiAdd; + pMultiCallback->MultiActionsInit((ZIP_SIZE_TYPE)calculateEnumerator.m_uTotalFiles, (ZIP_SIZE_TYPE)calculateEnumerator.m_uTotalBytes, CZipActionCallback::cbAdd); + } + + try + { + CAddFilesEnumerator addFilesEnumerator(lpszPath, bRecursive, this, iComprLevel, iSmartLevel, nBufSize, pMultiCallback); + bool ret = addFilesEnumerator.Start(filter); + if (pMultiCallback) + pMultiCallback->MultiActionsEnd(); + return ret; + } + catch(...) + { + if (pMultiCallback) + pMultiCallback->MultiActionsEnd(); + throw; + } +} + + +CZipString CZipArchive::GetArchivePath() const +{ + if (IsClosed(false)) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return _T(""); + } + return m_storage.m_pFile->GetFilePath(); +} + +CZipString CZipArchive::GetGlobalComment() const +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return _T(""); + } + CZipString temp; + m_centralDir.GetComment(temp); + return temp; +} + +bool CZipArchive::SetGlobalComment(LPCTSTR lpszComment) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + if (m_storage.IsSegmented() == -1) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot modify the global comment of an existing segmented archive.\n"); + return false; + } + + m_centralDir.SetComment(lpszComment); + if (m_bAutoFlush) + Flush(); + + return true; +} + + + +ZIP_VOLUME_TYPE CZipArchive::GetCurrentVolume() const +{ + return (ZIP_VOLUME_TYPE)(m_storage.GetCurrentVolume() + 1); +} + +bool CZipArchive::SetFileComment(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszComment) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + if (m_storage.IsSegmented() == -1) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot modify the file comment in an existing segmented archive.\n"); + return false; + } + + m_centralDir.SetFileComment(uIndex, lpszComment); + if (m_bAutoFlush) + Flush(); + return true; +} + +bool CZipArchive::SetPassword(LPCTSTR lpszPassword) +{ + if (m_iFileOpened != nothing) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot change the password when a file is opened.\n"); + return false; // it's important not to change the password when the file inside archive is opened + } + if (IsClosed()) + { + ZIPTRACE("%s(%i) : Setting the password for a closed archive has no effect.\n"); + } + if (lpszPassword) + ZipCompatibility::ConvertStringToBuffer(lpszPassword, m_pszPassword, CP_ACP); + else + m_pszPassword.Release(); + return true; +} + +bool CZipArchive::SetEncryptionMethod(int iEncryptionMethod) +{ + if (m_iFileOpened == compress) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot change the encryption method when there is a file opened for compression.\n"); + return false; + } + + if (iEncryptionMethod != CZipCryptograph::encNone && !CZipCryptograph::IsEncryptionSupported(iEncryptionMethod)) + return false; + m_iEncryptionMethod = iEncryptionMethod; + return true; +} + +struct CZipEncryptFileInfo +{ + CZipEncryptFileInfo() + { + m_pHeader = NULL; + m_uLocalSizeDiff = 0; + m_uDescriptorSizeDiff = 0; + m_uIndex = 0; + } + CZipEncryptFileInfo(CZipFileHeader* pHeader, DWORD uLocalSizeDiff, + DWORD uDescriptorSizeDiff, ZIP_INDEX_TYPE uIndex, ZIP_SIZE_TYPE uDataOffset) + :m_pHeader(pHeader), m_uLocalSizeDiff(uLocalSizeDiff), + m_uDescriptorSizeDiff(uDescriptorSizeDiff), m_uIndex(uIndex), m_uUncompressedOffset(uDataOffset) + { + } + + CZipFileHeader* m_pHeader; + DWORD m_uLocalSizeDiff; + DWORD m_uDescriptorSizeDiff; + ZIP_INDEX_TYPE m_uIndex; + ZIP_SIZE_TYPE m_uUncompressedOffset; + ZIP_SIZE_TYPE GetLastDataOffset() + { + return m_uUncompressedOffset + m_pHeader->m_uOffset; + } +}; + +bool CZipArchive::EncryptFilesInternal(CZipIndexesArray* pIndexes) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_storage.IsSegmented()) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot encrypt existing files in a segmented archive.\n"); + return false; + } + + if (m_storage.m_bReadOnly) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot encrypt files in a read-only archive.\n"); + return false; + } + + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot encrypt files if there is a file opened.\n"); + return false; + } + + if (GetCount() == 0) + { + ZIPTRACE("%s(%i) : There is nothing to encrypt: the archive is empty.\n"); + return false; + } + + if (!WillEncryptNextFile()) + { + ZIPTRACE("%s(%i) : An encryption method and a password must be set.\n"); + return false; + } + + bool bAll; + ZIP_ARRAY_SIZE_TYPE i; + if (pIndexes == NULL) + { + bAll = true; + i = (ZIP_ARRAY_SIZE_TYPE)GetCount(); + } + else + { + bAll = false; + pIndexes->Sort(true); + i = pIndexes->GetSize(); + } + + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbEncryptPrepare); + if (pCallback) + { + pCallback->Init(); + pCallback->SetTotal((ZIP_SIZE_TYPE)i); + } + bool bAborted = false; + + CZipArray infos; + ZIP_SIZE_TYPE uExtraData = 0; + while (i > 0) + { + i--; + ZIP_INDEX_TYPE idx; + if (bAll) + idx = (ZIP_INDEX_TYPE)i; + else + { + idx = pIndexes->GetAt(i); + if (!m_centralDir.IsValidIndex(idx)) + { + if (pCallback && !pCallback->RequestCallback()) + { + bAborted = true; + break; + } + continue; + } + } + CZipFileHeader* pHeader = GetFileInfo(idx); + + if (pHeader->IsEncrypted()) + { + if (pCallback && !pCallback->RequestCallback()) + { + bAborted = true; + break; + } + continue; + } + + ReadLocalHeaderInternal(idx); + DWORD uOrigSize = pHeader->GetLocalSize(true); + DWORD uOrigDescriptorSize = pHeader->GetDataDescriptorSize(&m_storage); + + pHeader->m_uEncryptionMethod = (BYTE)m_iEncryptionMethod; + pHeader->UpdateFlag(m_storage.IsSegmented() != 0); + + // needed for GetLocalSize + pHeader->PrepareFileName(); + DWORD uLocalDiff = pHeader->GetLocalSize(false) - uOrigSize; + DWORD uDescriptorDiff = pHeader->GetDataDescriptorSize(&m_storage) - uOrigDescriptorSize; + uExtraData += uLocalDiff + uDescriptorDiff; + infos.Add(CZipEncryptFileInfo(pHeader, uLocalDiff, uDescriptorDiff, idx, pHeader->m_uOffset + uOrigSize)); + if (pCallback && !pCallback->RequestCallback()) + { + bAborted = true; + break; + } + } + + if (pCallback) + { + if (!bAborted && !pCallback->RequestLastCallback()) + bAborted = true; + pCallback->CallbackEnd(); + if (bAborted) + CZipException::Throw(CZipException::abortedAction); + } + + ZIP_ARRAY_SIZE_TYPE uSize = infos.GetSize(); + if (!uSize) + { + ZIPTRACE("%s(%i) : There are no files to encrypt.\n"); + return true; + } + + m_centralDir.RemoveFromDisk(); + + CZipActionCallback* pMultiCallback = GetCallback(CZipActionCallback::cbMultiEncrypt); + + ZIP_ARRAY_SIZE_TYPE idxIdx; + ZIP_INDEX_TYPE idx; + + if (pMultiCallback) + { + ZIP_SIZE_TYPE uTotalToMove = 0; + ZIP_SIZE_TYPE uTotalToEncrypt = 0; + + // move files + idxIdx = 0; + // infos array has data from largest index to the smallest + CZipEncryptFileInfo info = infos[0]; + idx = GetCount(); + + ZIP_SIZE_TYPE uLastOffset = m_storage.GetLastDataOffset(); + ZIP_INDEX_TYPE lastNormalIdx = ZIP_FILE_INDEX_UNSPECIFIED; + while (idx > 0) + { + idx--; + if (idx == info.m_uIndex) + { + if (lastNormalIdx != ZIP_FILE_INDEX_UNSPECIFIED) + { + // compensate changed offset + uTotalToMove += uLastOffset - GetFileInfo(lastNormalIdx)->m_uOffset; + lastNormalIdx = ZIP_FILE_INDEX_UNSPECIFIED; + } + uTotalToMove += info.m_pHeader->m_uComprSize; + uTotalToEncrypt += info.m_pHeader->m_uComprSize; + + // no more files to encrypt + if (++idxIdx == uSize) + break; + uLastOffset = info.m_pHeader->m_uOffset; + info = infos[idxIdx]; + } + else + lastNormalIdx = idx; + } + pMultiCallback->MultiActionsInit((ZIP_SIZE_TYPE)uSize, uTotalToMove + uTotalToEncrypt, CZipActionCallback::cbEncryptMoveData); + } + + + try + { + // move files + idxIdx = 0; + // infos array has data from largest index to the smallest + CZipEncryptFileInfo info = infos[0]; + idx = GetCount(); + + DWORD uExtraBefore = CZipCryptograph::GetEncryptedInfoSizeBeforeData(m_iEncryptionMethod); + DWORD uExtraAfter = CZipCryptograph::GetEncryptedInfoSizeAfterData(m_iEncryptionMethod); + // the total amount of extra data + uExtraData += ((uExtraBefore + uExtraAfter) * infos.GetSize()); + + ZIP_SIZE_TYPE uLastOffset = m_storage.GetLastDataOffset(); + ZIP_INDEX_TYPE lastNormalIdx = ZIP_FILE_INDEX_UNSPECIFIED; + InitBuffer(); + pCallback = GetCallback(CZipActionCallback::cbEncryptMoveData); + while (idx > 0) + { + idx--; + if (idx == info.m_uIndex) + { + if (lastNormalIdx != ZIP_FILE_INDEX_UNSPECIFIED) + { + // compensate changed offset + ZIP_SIZE_TYPE uStartOffset = GetFileInfo(lastNormalIdx)->m_uOffset - uExtraData; + if (pCallback) + { + pCallback->Init(); + pCallback->SetTotal(uLastOffset - uStartOffset); + } + MovePackedFiles(uStartOffset, uLastOffset, uExtraData, pCallback, true); + if (pCallback) + pCallback->CallbackEnd(); + lastNormalIdx = ZIP_FILE_INDEX_UNSPECIFIED; + } + uExtraData -= (uExtraAfter + info.m_uDescriptorSizeDiff); + if (pCallback) + { + pCallback->Init(); + pCallback->SetTotal(info.m_pHeader->m_uComprSize); + } + MovePackedFiles(info.m_uUncompressedOffset, info.m_uUncompressedOffset + info.m_pHeader->m_uComprSize, uExtraData, pCallback, true); + if (pCallback) + pCallback->CallbackEnd(); + + // no more files to encrypt + if (++idxIdx == uSize) + break; + + uExtraData -= (uExtraBefore + info.m_uLocalSizeDiff); + // use original offsett + uLastOffset = info.m_pHeader->m_uOffset; + // now change the offset (not counting expanded local header - it changed the offset of data, not the offset of local header) + info.m_pHeader->m_uOffset += uExtraData; + + info = infos[idxIdx]; + } + else + { + lastNormalIdx = idx; + GetFileInfo(idx)->m_uOffset += uExtraData; + } + } + bAborted = false; + ZIP_SIZE_TYPE uToEncrypt = 0; + i = uSize; + // now encrypt the files (starting from the first one in the archive - this way the general direction of data copying is kept + CreateCryptograph(m_iEncryptionMethod); + if (pMultiCallback) + pMultiCallback->SetReactType(CZipActionCallback::cbEncrypt); + pCallback = GetCallback(CZipActionCallback::cbEncrypt); + while (i > 0) + { + i--; + CZipEncryptFileInfo inf = infos[i]; + CZipFileHeader* pHeader = inf.m_pHeader; + uToEncrypt = pHeader->m_uComprSize; + if (pCallback) + { + pCallback->Init(pHeader->GetFileName()); + pCallback->SetTotal(uToEncrypt); + } + + m_storage.Seek(pHeader->m_uOffset); + pHeader->WriteLocal(&m_storage); + // take the number of bytes to encode, before m_uComprSize is modified + m_pCryptograph->InitEncode(m_pszPassword, *pHeader, m_storage); + m_storage.Flush(); + + if (uToEncrypt) + { + DWORD bufSize = m_pBuffer.GetSize(); + char* buf = (char*)m_pBuffer; + ZIP_SIZE_TYPE uToRead; + UINT uSizeRead; + bool bBreak = false; + CZipAbstractFile* pFile = m_storage.m_pFile; + ZIP_FILE_USIZE uPosition = pFile->GetPosition(); + // the file pointer should be already positioned on the data + do + { + uToRead = uToEncrypt > bufSize ? bufSize : uToEncrypt; + uSizeRead = (UINT)pFile->Read(buf, (UINT)uToRead); + if (!uSizeRead) + break; + uToEncrypt -= uSizeRead; + if (uToEncrypt == 0) + bBreak = true; + + m_pCryptograph->Encode(buf, uSizeRead); + pFile->Seek(uPosition); + pFile->Write(buf, uSizeRead); + uPosition += uSizeRead; + + if (pCallback && !pCallback->RequestCallback(uSizeRead)) + { + bAborted = true; + break; + } + if (pMultiCallback) + pMultiCallback->MultiActionsNext(); + } + while (!bBreak); + } + + // copying from a not segmented to a segmented archive so add the data descriptor + + // we want write the additional data only if everything is all right, but we don't want to flush the storage before + // (and we want to flush the storage before throwing an exception, if something is wrong) + if (uToEncrypt == 0) + { + m_pCryptograph->FinishEncode(*pHeader, m_storage); + // it will be written only if needed + pHeader->WriteDataDescriptor(&m_storage); + m_storage.Flush(); + } + + if (pCallback) + { + if (!bAborted && !pCallback->RequestLastCallback()) + bAborted = true; + + if (bAborted) + { + pCallback->CallbackEnd(); + CZipException::Throw(CZipException::abortedAction); + } + } + + if (uToEncrypt > 0) + ThrowError(CZipException::badZipFile); + + if (pCallback) + pCallback->CallbackEnd(); + } + + m_storage.FlushFile(); + ClearCryptograph(); + + } + catch(...) + { + if (pMultiCallback) + pMultiCallback->MultiActionsEnd(); + throw; + } + + if (pMultiCallback) + pMultiCallback->MultiActionsEnd(); + return true; + +} + + +bool CZipArchive::SetCompressionMethod(WORD uCompressionMethod) +{ + if (m_iFileOpened == compress) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot change the compression method when there is a file opened for compression.\n"); + return false; + } + if (uCompressionMethod == CZipCompressor::methodStore) + { + ZIPTRACE("%s(%i) : Use the compression level CZipCompressor::levelStore when compressing files instead.\n"); + return false; + } + + if (!CZipCompressor::IsCompressionSupported(uCompressionMethod)) + { + ZIPTRACE("%s(%i) : The compression method is not supported.\n"); + return false; + } + + m_uCompressionMethod = uCompressionMethod; + return true; +} + +CZipString CZipArchive::GetPassword()const +{ + CZipString temp; + ZipCompatibility::ConvertBufferToString(temp, m_pszPassword, CP_ACP); + return temp; +} + +bool CZipArchive::TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_storage.IsSegmented() == 1) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot test a segmented archive in creation.\n"); + return false; + } + if (!uBufSize) + return false; + + CZipFileHeader* pHeader = m_centralDir[uIndex]; + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbTest); + if (pCallback) + { + pCallback->Init(pHeader->GetFileName()); + } + + if (pHeader->IsDirectory()) + { + if (pCallback) + pCallback->SetTotal(0); + + // we do not test whether the password for the encrypted directory + // is correct, since it seems to be senseless (anyway password + // encrypted directories should be avoided - it adds 12 bytes) + ZIP_SIZE_TYPE uSize = pHeader->m_uComprSize; + if ((uSize != 0 || uSize != pHeader->m_uUncomprSize) + // different treating compressed directories + && !(pHeader->IsEncrypted() && uSize == 12 && !pHeader->m_uUncomprSize)) + CZipException::Throw(CZipException::dirWithSize); + + if (pCallback) + pCallback->CallbackEnd(); + + return true; + } + else + { + try + { + if (pCallback) + pCallback->SetTotal(pHeader->m_uUncomprSize); + + if (!OpenFile(uIndex)) + return false; + CZipAutoBuffer buf(uBufSize); + DWORD iRead; + int iAborted = 0; + for(;;) + { + iRead = ReadFile(buf, buf.GetSize()); + if (!iRead) + { + if (pCallback && !pCallback->RequestLastCallback()) + iAborted = CZipException::abortedSafely; + break; + } + if (pCallback && !pCallback->RequestCallback(iRead)) + { + if (iRead == buf.GetSize() && ReadFile(buf, 1) != 0) // test one byte if there is something left + iAborted = CZipException::abortedAction; + else + iAborted = CZipException::abortedSafely; // we did it! + break; + } + } + + if (!iAborted) + { + if (CloseFile() == 1) + { + if (pCallback) + pCallback->CallbackEnd(); + return true; + } + else + CZipException::Throw(CZipException::badZipFile); + } + else + { + if (iAborted == CZipException::abortedAction) + CloseFile(NULL, true); + else + { + bool bRet; + try + { + bRet = CloseFile() == 1; + } + // if any exception was thrown, then we are not successful + // catch all exceptions to thrown aborted exception only +#ifdef ZIP_ARCHIVE_MFC + catch(CException* e) + { + e->Delete(); + bRet = false; + } +#endif + catch(...) + { + bRet = false; + } + if (!bRet) + { + CloseFile(NULL, true); + iAborted = CZipException::abortedAction; + } + } + + pCallback->CallbackEnd(); + CZipException::Throw(iAborted); + } + return false; // to satisfy some compilers (some will complain)... + } + catch(...) + { + CloseFile(NULL, true); + throw; + } + } +} + +void CZipArchive::SetFileHeaderAttr(CZipFileHeader& header, DWORD uAttr)const +{ + header.SetSystemCompatibility(m_iArchiveSystCompatib); + header.SetSystemAttr(uAttr); +} + +void CZipArchive::EnableFindFast(bool bEnable) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : Set it after opening the archive.\n"); + return; + } + m_centralDir.EnableFindFast(bEnable, m_bCaseSensitive); +} + +bool CZipArchive::SetSystemCompatibility(int iSystemComp) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : Set it after opening the archive.\n"); + return false; + } + + if (m_iFileOpened == compress) + { + ZIPTRACE("%s(%i) : Set it before opening a file inside archive.\n"); + return false; + } + + if (!ZipCompatibility::IsPlatformSupported(iSystemComp)) + return false; + // change the name coding page, if it was not changed before + if (m_stringSettings.IsStandardNameCodePage(m_iArchiveSystCompatib)) + m_stringSettings.SetDefaultNameCodePage(iSystemComp); + m_iArchiveSystCompatib = iSystemComp; + + return true; +} + +void CZipArchive::SetRootPath(LPCTSTR szPath) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : Set it after opening the archive.\n"); + return; + } + + if (m_iFileOpened != nothing) + { + ZIPTRACE("%s(%i) : Set it before opening a file inside archive.\n"); + return; + } + + if (szPath) + { + m_szRootPath = szPath; + CZipPathComponent::RemoveSeparators(m_szRootPath); + } + else + m_szRootPath.Empty(); +} + +CZipString CZipArchive::TrimRootPath(CZipPathComponent &zpc)const +{ + if (m_szRootPath.IsEmpty()) + return zpc.GetFileName(); + CZipString szPath = zpc.GetFullPath(); + return RemovePathBeginning(m_szRootPath, szPath, m_pZipCompare) ? szPath : zpc.GetFileName(); +} + +bool CZipArchive::RemovePathBeginning(LPCTSTR lpszBeginning, CZipString& szPath, ZIPSTRINGCOMPARE pCompareFunction) +{ + CZipString szBeginning(lpszBeginning); + CZipPathComponent::RemoveSeparators(szBeginning); + int iRootPathLength = szBeginning.GetLength(); + if (iRootPathLength && szPath.GetLength() >= iRootPathLength && + (szPath.Left(iRootPathLength).*pCompareFunction)(szBeginning) == 0) + { + // the beginning is the same + if (szPath.GetLength() == iRootPathLength) + { + szPath.Empty(); + return true; + } + // is the end of m_szPathRoot only a beginning of a directory name? + // check for a separator + // we know the length is larger, so we can write: + if (CZipPathComponent::IsSeparator(szPath[iRootPathLength])) + { + szPath = szPath.Mid(iRootPathLength); + CZipPathComponent::RemoveSeparatorsLeft(szPath); + return true; + } + } + return false; +} + +void CZipArchive::SetTempPath(LPCTSTR lpszPath, bool bForce) +{ + m_szTempPath = lpszPath; + if (lpszPath && bForce) + ZipPlatform::ForceDirectory(lpszPath); + CZipPathComponent::RemoveSeparators(m_szTempPath); +} + +CZipString CZipArchive::PredictFileNameInZip(LPCTSTR lpszFilePath, + bool bFullPath, int iWhat)const +{ + CZipString sz = lpszFilePath; + if (sz.IsEmpty()) + return _T(""); + bool bAppend; + switch (iWhat) + { + case prFile: + bAppend = false; + break; + case prDir: + bAppend = true; + break; + default: + bAppend = CZipPathComponent::IsSeparator(sz[sz.GetLength() - 1]); + } + + // remove for CZipPathComponent treating last name as a file even if dir + CZipPathComponent::RemoveSeparators(sz); + // it may be empty after removing separators, e.g.: "/" + if (sz.IsEmpty()) + return _T(""); + CZipPathComponent zpc(sz); + + if (bFullPath) + { + if (m_bRemoveDriveLetter) + sz = zpc.GetNoDrive(); + } + else + sz = TrimRootPath(zpc); + + if (bAppend && !sz.IsEmpty()) + CZipPathComponent::AppendSeparator(sz); + return sz; +} + +CZipString CZipArchive::PredictExtractedFileName(LPCTSTR lpszFileNameInZip, LPCTSTR lpszPath, bool bFullPath, LPCTSTR lpszNewName)const +{ + CZipString szFile = lpszPath; + CZipString sz = lpszNewName ? lpszNewName : lpszFileNameInZip; + if (sz.IsEmpty()) + return szFile; + if (!szFile.IsEmpty()) + CZipPathComponent::AppendSeparator(szFile); + + + // remove for CZipPathComponent treating last name as a file even if dir + CZipPathComponent::RemoveSeparators(sz); + CZipPathComponent zpc(sz); + szFile += bFullPath ? (m_bRemoveDriveLetter ? zpc.GetNoDrive() : sz) + : TrimRootPath(zpc); + return szFile; +} + +ZIP_SIZE_TYPE CZipArchive::PredictMaximumFileSizeInArchive(LPCTSTR lpszFilePath, bool bFullPath) const +{ + DWORD attr; + if (!ZipPlatform::GetFileAttr(lpszFilePath, attr)) + return 0; + CZipFileHeader fh; + SetFileHeaderAttr(fh, attr); + if (!fh.IsDirectory()) + if (!ZipPlatform::GetFileSize(lpszFilePath, fh.m_uUncomprSize)) + return 0; + fh.SetFileName(PredictFileNameInZip(lpszFilePath, bFullPath, fh.IsDirectory() ? prDir : prFile)); + return PredictMaximumFileSizeInArchive(fh); +} + +ZIP_SIZE_TYPE CZipArchive::PredictMaximumFileSizeInArchive(CZipFileHeader& fh) const +{ + fh.m_stringSettings = m_stringSettings; + fh.m_uEncryptionMethod = WillEncryptNextFile() ? (BYTE)m_iEncryptionMethod : (BYTE)CZipCryptograph::encNone; + fh.m_uMethod = CZipCompressor::methodStore; + fh.PrepareData(CZipCompressor::levelStore, m_storage.IsSegmented() != 0); + DWORD uLocalSize = fh.GetLocalSize(true); + return fh.GetSize() + uLocalSize + fh.GetDataSize(true, false) + fh.GetDataDescriptorSize(&m_storage); +} + +void CZipArchive::SetAutoFlush(bool bAutoFlush) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n"); + return; + } + if (m_storage.IsSegmented() != 0) + { + ZIPTRACE("%s(%i) : Cannot set auto-flush for a segmented archive.\n"); + return; + } + m_bAutoFlush = bAutoFlush; +} + +void CZipArchive::Flush() +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n"); + return; + } + + if (m_storage.IsSegmented() < 0) + { + ZIPTRACE("%s(%i) : Cannot flush an existing segmented archive.\n"); + return; + } + WriteCentralDirectory(); + m_storage.FlushFile(); + if (m_storage.IsSegmented() > 0) // try to finalize a segmented archive without closing it + m_storage.FinalizeSegm(); +} + + +void CZipArchive::GetCentralDirInfo(CZipCentralDir::CInfo& info)const +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n"); + return; + + } + m_centralDir.GetInfo(info); + if (GetSegmMode() > 0) + info.m_uLastVolume = m_storage.GetCurrentVolume(); +} + +void CZipArchive::FindMatches(LPCTSTR lpszPattern, CZipIndexesArray &ar, bool bFullPath) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return; + } + + // ar.RemoveAll(); don't do this + ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)GetCount(); + CWildcard wc(lpszPattern, m_bCaseSensitive); + for (ZIP_INDEX_TYPE i = 0; i < uCount; i++) + { + CZipString sz = m_centralDir[i]->GetFileName(); + if (!bFullPath) + { + CZipPathComponent::RemoveSeparators(sz); + CZipPathComponent zpc(sz); + sz = zpc.GetFileName(); + } + if (wc.IsMatch(sz)) + ar.Add(i); + } +} + +ZIP_INDEX_TYPE CZipArchive::WillBeDuplicated(LPCTSTR lpszFilePath, bool bFullPath, bool bFileNameOnly , int iWhat) +{ + CZipString szFile; + if (bFileNameOnly) + { + CZipPathComponent zpc(lpszFilePath); + szFile = PredictFileNameInZip(zpc.GetFileName(), false, iWhat); + } + else + szFile = PredictFileNameInZip(lpszFilePath, bFullPath, iWhat); + return FindFile(szFile, ffDefault, bFileNameOnly); +} + + +bool CZipArchive::GetFromArchive( CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewFileName, ZIP_INDEX_TYPE uReplaceIndex, bool bKeepSystComp, CZipActionCallback* pCallback) +{ + if (this == &zip) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot get files from the same archive.\n"); + return false; + } + + if (IsClosed() || zip.IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_iFileOpened || zip.m_iFileOpened) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot get files from another archive if there is a file opened.\n"); + return false; + } + + if (m_storage.IsSegmented() == -1) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot add files to an existing segmented archive.\n"); + return false; + } + + ASSERT(m_pBuffer.GetSize() > 0); + + bool bSegm = m_storage.IsSegmented() == 1; + + if (!zip.m_centralDir.IsValidIndex(uIndex)) + return false; + + zip.ReadLocalHeaderInternal(uIndex); + + CZipFileHeader originalHeader; + // we need a copy - we are going to modify this + if (!zip.GetFileInfo(originalHeader, uIndex)) + return false; + if (zip.m_storage.IsSegmented() != 0 && originalHeader.m_uLocalComprSize == 0) + // we must compensate for adding the encrypted info size to m_uLocalComprSize at the beginning of CZipFileHeader::WriteLocal() + originalHeader.m_uLocalComprSize = originalHeader.m_uComprSize - originalHeader.GetEncryptedInfoSize(); + bool bConvertSystem = !bKeepSystComp && originalHeader.GetSystemCompatibility() != m_iArchiveSystCompatib; + CZipString szFileName; + if (lpszNewFileName != NULL) + { + szFileName = lpszNewFileName; + originalHeader.SetFileName(lpszNewFileName); + } + else + szFileName = originalHeader.GetFileName(); // empty + + if (bConvertSystem) + { + DWORD uAttr = originalHeader.GetSystemAttr(); + originalHeader.SetSystemCompatibility(m_iArchiveSystCompatib); + originalHeader.SetSystemAttr(uAttr); + } + + if (!UpdateReplaceIndex(uReplaceIndex)) + return false; + + bool bReplace = uReplaceIndex != ZIP_FILE_INDEX_UNSPECIFIED; + if (bReplace && bSegm) + return false; + + int iCallbackType = 0; + if (pCallback) + iCallbackType = pCallback->m_iType; + + if (!originalHeader.IsEncrypted() && WillEncryptNextFile()) + { + originalHeader.m_uEncryptionMethod = (BYTE)m_iEncryptionMethod; + CreateCryptograph(m_iEncryptionMethod); + } + else + ClearCryptograph(); + + // if the same callback is applied to cbMoveData, then the previous information about the type will be lost + // we restore it later + CZipFileHeader* pHeader = m_centralDir.AddNewFile(originalHeader, uReplaceIndex, originalHeader.GetCompressionLevel(), true); + pHeader->m_stringSettings.m_uCommentCodePage = originalHeader.m_stringSettings.m_uCommentCodePage; + + // prepare this here: it will be used for GetLocalSize and WriteLocal + pHeader->PrepareFileName(); + + ZIP_SIZE_TYPE uTotalToMove = pHeader->m_uComprSize; + + if (bReplace) + { + ZIP_SIZE_TYPE uDataSize; + if (m_pCryptograph) + // the file will be encrypted and have not yet increased pHeader->m_uComprSize (in m_pCryptograph->InitEncode) + uDataSize = pHeader->GetDataSize(false, false); + else + uDataSize = uTotalToMove; + MakeSpaceForReplace(uReplaceIndex, uDataSize + pHeader->GetLocalSize(false) + pHeader->GetDataDescriptorSize(&m_storage), szFileName); + } + + if (pCallback) + { + // must be set before Init() + pCallback->m_iType = iCallbackType; + pCallback->Init(szFileName, zip.GetArchivePath()); + pCallback->SetTotal(pHeader->m_uComprSize); + } + + // must be written as not converted + pHeader->WriteLocal(&m_storage); + if (m_pCryptograph) + m_pCryptograph->InitEncode(m_pszPassword, *pHeader, m_storage); + + + char* buf = (char*)m_pBuffer; + + ZIP_SIZE_TYPE uToRead; + DWORD uSizeRead; + int iAborted = 0; + bool bBreak = false; + if (uTotalToMove) + { + DWORD bufSize = m_pBuffer.GetSize(); + do + { + uToRead = uTotalToMove > bufSize ? bufSize : uTotalToMove; + uSizeRead = (UINT)zip.m_storage.Read(buf, (UINT)uToRead, false); + if (!uSizeRead) + break; + uTotalToMove -= uSizeRead; + if (uTotalToMove == 0) + bBreak = true; + + if (m_pCryptograph) + m_pCryptograph->Encode(m_pBuffer, uSizeRead); + + m_storage.Write(buf, uSizeRead, false); + if (pCallback && !pCallback->RequestCallback(uSizeRead)) + { + if (uTotalToMove != 0) + { + if (!bSegm && !bReplace) + { + m_centralDir.RemoveLastFile(); + iAborted = CZipException::abortedSafely; + } + else + iAborted = CZipException::abortedAction; + } + else + iAborted = CZipException::abortedSafely; + break; + + } + } + while (!bBreak); + + if (pCallback) + { + if (!iAborted && !pCallback->RequestLastCallback()) + iAborted = CZipException::abortedSafely; + + if (iAborted) + { + // when no exception, CallbackEnd() called later + pCallback->CallbackEnd(); + CZipException::Throw(iAborted); // throw to distinguish from other return codes + } + } + } + + m_centralDir.m_pOpenedFile = NULL; + // copying from a not segmented to a segmented archive so add the data descriptor + + // we want write the additional data only if everything is all right, but we don't want to flush the storage before + // (and we want to flush the storage before throwing an exception, if something is wrong) + if (uTotalToMove == 0) + { + if (m_pCryptograph) + m_pCryptograph->FinishEncode(*pHeader, m_storage); + // it will be written only if needed + pHeader->WriteDataDescriptor(&m_storage); + } + + m_storage.Flush(); + if (uTotalToMove > 0) + ThrowError(CZipException::badZipFile); + + if (pCallback) + pCallback->CallbackEnd(); + + ClearCryptograph(); + return true; +} + +bool CZipArchive::GetFromArchive( CZipArchive& zip, CZipIndexesArray &aIndexes, bool bKeepSystComp) +{ + aIndexes.Sort(true); + ZIP_INDEX_TYPE uFiles = (ZIP_INDEX_TYPE)aIndexes.GetSize(); + InitBuffer(); + try + { + for (ZIP_INDEX_TYPE i = 0; i < uFiles; i++) + { + ZIP_INDEX_TYPE uFileIndex = aIndexes[(ZIP_ARRAY_SIZE_TYPE)i]; + if (!GetFromArchive(zip, uFileIndex, NULL, ZIP_FILE_INDEX_UNSPECIFIED, bKeepSystComp, GetCallback(CZipActionCallback::cbGet))) + { + ReleaseBuffer(); + return false; + } + } + } + catch (...) + { + ReleaseBuffer(); + throw; + } + ReleaseBuffer(); + if (m_bAutoFlush) + Flush(); + return true; +} +bool CZipArchive::RenameFile(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewName) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_storage.IsSegmented()) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot rename files in a segmented archive.\n"); + return false; + } + + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot rename a file if there is a file opened.\n"); + return false; + } + CZipFileHeader* pHeader = (*this)[uIndex]; + if (pHeader == NULL) + return false; + + CZipString szNewName(lpszNewName); + if (pHeader->IsDirectory()) + CZipPathComponent::AppendSeparator(szNewName); + else + CZipPathComponent::RemoveSeparators(szNewName); + CZipString szPreviousFileName = pHeader->GetFileName(); + if (szPreviousFileName.Collate(szNewName) == 0) + return true; + + // don't copy the comment code page, it already could have been set using it's own code page (set CD CP, change comment, change CD CP) + pHeader->m_stringSettings.m_bStoreNameInExtraData = m_stringSettings.m_bStoreNameInExtraData; + pHeader->m_stringSettings.m_uNameCodePage = m_stringSettings.m_uNameCodePage; + pHeader->SetFileName(szNewName); + + m_centralDir.RemoveFromDisk(); // does m_storage.Flush(); + // read local data - it may differ from central data + char localInfo[4]; + m_storage.Seek(pHeader->m_uOffset + 26); + m_storage.m_pFile->Read(localInfo, 4); // read at once + WORD uFileNameLen, uExtraFieldSize; + CBytesWriter::ReadBytes(uFileNameLen, localInfo); + // skip endian issues - the variable will not be used, but written back as it is + memcpy(&uExtraFieldSize, localInfo + 2, 2); + + // filename buffer already cleared (GetFileName), the conversion will take place + pHeader->PrepareFileName(); + ASSERT(pHeader->m_pszFileNameBuffer.IsAllocated()); + WORD uNewFileNameLen = (WORD)pHeader->m_pszFileNameBuffer.GetSize(); + int iDelta = uNewFileNameLen - uFileNameLen; + int iOffset = 0; + CZipAutoBuffer buf, *pBuf; + + if (iDelta != 0) + { + // we need to make more or less space + InitBuffer(); + ZIP_SIZE_TYPE uStartOffset = pHeader->m_uOffset + 30 + uFileNameLen; + ZIP_SIZE_TYPE uFileLen = (ZIP_SIZE_TYPE)m_storage.m_pFile->GetLength(); + ZIP_SIZE_TYPE uEndOffset = uFileLen - m_storage.m_uBytesBeforeZip; + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbRename); + if (pCallback) + { + // do it right and sent the notification + pCallback->Init(szPreviousFileName, GetArchivePath()); + pCallback->SetTotal(uEndOffset - uStartOffset); + } + bool bForward = iDelta > 0; + if (bForward) + m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + iDelta)); // ensure the seek is correct + + MovePackedFiles(uStartOffset, uEndOffset, abs(iDelta), pCallback, bForward); + if (pCallback) + pCallback->CallbackEnd(); + + if (!bForward) + m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + iDelta)); // delta < 0; shrink the file + + ReleaseBuffer(); + + ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)GetCount(); + for (ZIP_INDEX_TYPE i = (ZIP_INDEX_TYPE)(uIndex + 1); i < uSize; i++) + m_centralDir[i]->m_uOffset += iDelta; + buf.Allocate(4 + uNewFileNameLen); + CBytesWriter::WriteBytes(buf, uNewFileNameLen); + // the variable was not used - we write it back as it was (no endian issues) + // to write everything at once + memcpy((char*)buf + 2, &uExtraFieldSize, 2); + memcpy((char*)buf + 4, pHeader->m_pszFileNameBuffer, uNewFileNameLen); + pBuf = &buf; + iOffset = -4; + } + else + pBuf = &pHeader->m_pszFileNameBuffer; + + m_storage.Seek(pHeader->m_uOffset + 30 + iOffset); + m_storage.m_pFile->Write(*pBuf, pBuf->GetSize()); + m_centralDir.RebuildFindFastArray(); + if (m_bAutoFlush) + Flush(); + + return true; +} + +bool CZipArchive::UpdateReplaceIndex(ZIP_INDEX_TYPE& uReplaceIndex) +{ + if (uReplaceIndex == ZIP_FILE_INDEX_UNSPECIFIED) + return true; + + if (GetSegmMode() != 0) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot replace files in a segmented archive.\n"); + return false; + } + + if (!m_centralDir.IsValidIndex(uReplaceIndex)) + { + ZIPTRACE("%s(%i) : Not valid replace index.\n"); + return false; + } + if (uReplaceIndex == GetCount() - 1) // replacing last file in the archive + { + RemoveLast(true); + uReplaceIndex = ZIP_FILE_INDEX_UNSPECIFIED; + } + return true; +} + +void CZipArchive::MakeSpaceForReplace(ZIP_INDEX_TYPE uReplaceIndex, ZIP_SIZE_TYPE uTotal, LPCTSTR lpszFileName) +{ + ASSERT(uReplaceIndex < GetCount() - 1); + // we can't use the offset from the central directory here, because the header is already replaced + ZIP_SIZE_TYPE uReplaceStart = (ZIP_SIZE_TYPE)m_storage.m_pFile->GetPosition() - m_storage.m_uBytesBeforeZip; + + // find the next offset (files in the central directory may not necessarily be ordered by offset) + ZIP_SIZE_TYPE uReplaceEnd = ZIP_SIZE_TYPE(-1); + ZIP_INDEX_TYPE i; + for (i = 0; i < (ZIP_INDEX_TYPE)m_centralDir.GetCount(); i++) + if (i != uReplaceIndex) + { + ZIP_SIZE_TYPE uOffset = m_centralDir[i]->m_uOffset; + if (uOffset > uReplaceStart && uOffset < uReplaceEnd) + uReplaceEnd = uOffset; + } + + ZIP_SIZE_TYPE uReplaceTotal = uReplaceEnd - uReplaceStart; + if (uTotal == uReplaceTotal) + return; + + bool bForward = uTotal > uReplaceTotal; + ZIP_SIZE_TYPE uDelta; + if (bForward) + uDelta = uTotal - uReplaceTotal; + else + uDelta = uReplaceTotal - uTotal; + + + // InitBuffer(); don't - the calling functions will + CZipActionCallback* pCallback = GetCallback(CZipActionCallback::cbMoveData); + ZIP_SIZE_TYPE uFileLen = (ZIP_SIZE_TYPE)m_storage.m_pFile->GetLength(); + ZIP_SIZE_TYPE uUpperLimit = uFileLen - m_storage.m_uBytesBeforeZip; // will be added in m_storage.Seek + if (pCallback) + { + pCallback->Init(lpszFileName, GetArchivePath()); + pCallback->SetTotal(uUpperLimit - uReplaceEnd); + } + + if (bForward) + m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen + uDelta)); // ensure the seek is correct + + MovePackedFiles(uReplaceEnd, uUpperLimit, uDelta, pCallback, bForward); + + if (!bForward) + m_storage.m_pFile->SetLength((ZIP_FILE_USIZE)(uFileLen - uDelta)); + + m_storage.Seek(uReplaceStart); + ZIP_INDEX_TYPE uSize = GetCount(); + for (i = (ZIP_INDEX_TYPE)(uReplaceIndex + 1); i < uSize; i++) + { + ZIP_SIZE_TYPE uOffset = m_centralDir[i]->m_uOffset; + m_centralDir[i]->m_uOffset = bForward ? uOffset + uDelta : uOffset - uDelta; + } + if (pCallback) + pCallback->CallbackEnd(); +} + +void CZipArchive::MovePackedFiles(ZIP_SIZE_TYPE uStartOffset, ZIP_SIZE_TYPE uEndOffset, ZIP_SIZE_TYPE uMoveBy, + CZipActionCallback* pCallback, bool bForward, bool bLastCall) +{ + ASSERT(m_pBuffer.GetSize() > 0); + + ZIP_SIZE_TYPE uTotalToMove = uEndOffset - uStartOffset; + ZIP_SIZE_TYPE uPack = uTotalToMove > m_pBuffer.GetSize() ? m_pBuffer.GetSize() : uTotalToMove; + char* buf = (char*)m_pBuffer; + + + UINT uSizeRead; + bool bBreak = false; + bool bAborted = false; + do + { + if (uEndOffset - uStartOffset < uPack) + { + uPack = uEndOffset - uStartOffset; + if (!uPack) + break; + bBreak = true; + + } + ZIP_SIZE_TYPE uPosition = bForward ? uEndOffset - uPack : uStartOffset; + + m_storage.Seek(uPosition); + uSizeRead = m_storage.m_pFile->Read(buf, (UINT)uPack); + if (!uSizeRead) + break; + + if (bForward) + uPosition += uMoveBy; + else + uPosition -= uMoveBy; + m_storage.Seek(uPosition); + m_storage.m_pFile->Write(buf, uSizeRead); + if (bForward) + uEndOffset -= uSizeRead; + else + uStartOffset += uSizeRead; + if (pCallback && !pCallback->RequestCallback(uSizeRead)) + { + bAborted = true; + break; + } + } + while (!bBreak); + + if (pCallback) + { + if (!bAborted && bLastCall && !pCallback->RequestLastCallback()) + bAborted = true; + // do not call here - it will be called in the calling method + //pCallback->CallbackEnd(); + if (bAborted) + { + // call here before throwing the the aborted exception + pCallback->CallbackEnd(); + ThrowError(CZipException::abortedAction); + } + } + + if (uEndOffset != uStartOffset) + ThrowError(CZipException::internalError); + +} + + +bool CZipArchive::RemoveCentralDirectoryFromArchive() +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_storage.IsSegmented()) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot remove the central directory from a segmented archive.\n"); + return false; + } + m_centralDir.RemoveFromDisk(); + return true; +} + +bool CZipArchive::OverwriteLocalHeader(ZIP_INDEX_TYPE uIndex) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + + if (m_storage.IsSegmented()) + { + ZIPTRACE("%s(%i) : ZipArchive Library cannot overwrite local header in a segmented archive.\n"); + return false; + } + + CZipFileHeader* pHeader = GetFileInfo(uIndex); + m_storage.Seek(pHeader->m_uOffset); + pHeader->WriteLocal(&m_storage); + return true; +} + +bool CZipArchive::ReadLocalHeader(ZIP_INDEX_TYPE uIndex) +{ + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return false; + } + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : A file is already opened.\n"); + return false; + } + ReadLocalHeaderInternal(uIndex); + return true; +} + +void CZipArchive::SetSegmCallback(CZipSegmCallback* pCallback, int callbackType) +{ + if ((callbackType & scSpan) != 0) + m_storage.m_pSpanChangeVolumeFunc = pCallback; + if ((callbackType & scSplit) != 0) + m_storage.m_pSplitChangeVolumeFunc = pCallback; +} diff --git a/harbour/contrib/hbziparch/ZipArchive.h b/harbour/contrib/hbziparch/ZipArchive.h new file mode 100644 index 0000000000..c33fc8dfb8 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipArchive.h @@ -0,0 +1,3303 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// +// Check the site http://www.artpol-software.com for the updated version of the library. +// +// The following information files are distributed along with this library: +// License.txt - licensing information +// Appnote.txt - details on the zip format +// ( also available at ftp://ftp.pkware.com/appnote.zip) +// + + + +/** +* \file ZipArchive.h +* Includes the CZipArchive class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPARCHIVE_DOT_H) +#define ZIPARCHIVE_ZIPARCHIVE_DOT_H + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (push) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class + #pragma warning( disable : 4275 ) // non dll-interface class used as base for dll-interface +#endif + +#include "_features.h" +#include "ZipException.h" +#include "ZipAutoBuffer.h" +#include "ZipCentralDir.h" +#include "ZipStorage.h" +#include "ZipPathComponent.h" +#include "ZipString.h" +#include "ZipExport.h" +#include "ZipCryptograph.h" +#include "FileFilter.h" +#include "DirEnumerator.h" +#include "ZipCompressor.h" +#include "ZipCallbackProvider.h" + +#define ZIP_AUTODETECT_VOLUME_SIZE ZIP_SIZE_TYPE(-1) + +/** + The structure used as a parameter in CZipArchive::AddNewFile(CZipAddNewFileInfo& ). + Use one of the provided constructors and then adjust the member variables as needed. + + \see + 0610231446|simple +*/ +struct ZIP_API CZipAddNewFileInfo +{ + /** + Initializes a new instance of the CZipAddNewFileInfo class. + + \param lpszFilePath + Sets #m_szFilePath. + + \param bFullPath + Sets #m_bFullPath. + */ + CZipAddNewFileInfo(LPCTSTR lpszFilePath, bool bFullPath = true) + : m_szFilePath(lpszFilePath),m_bFullPath(bFullPath) + { + m_pFile = NULL; + Defaults(); + } + + /** + Initializes a new instance of the CZipAddNewFileInfo class. + + \param lpszFilePath + Sets #m_szFilePath. + + \param lpszFileNameInZip + Sets #m_szFileNameInZip. + */ + CZipAddNewFileInfo(LPCTSTR lpszFilePath, LPCTSTR lpszFileNameInZip) + : m_szFilePath(lpszFilePath), m_szFileNameInZip(lpszFileNameInZip) + { + m_pFile = NULL; + Defaults(); + } + + /** + Initializes a new instance of the CZipAddNewFileInfo class. + + \param pFile + Sets #m_pFile. + + \param lpszFileNameInZip + Sets #m_szFileNameInZip. + */ + CZipAddNewFileInfo(CZipAbstractFile* pFile, LPCTSTR lpszFileNameInZip) + : m_pFile(pFile), m_szFileNameInZip(lpszFileNameInZip) + { + Defaults(); + } + + /** + Initialize this field to set the source data for compression to be taken from + the \c CZipAbstractFile object (such as \c CZipMemFile) instead of from a physical file. + + \note + - You have to leave #m_szFilePath empty if you set #m_pFile to not \c NULL. + - The time of a file in zip will be set to the current time, and the attributes to the default + file attributes (depending on the system). + - You cannot add directories this way. + */ + CZipAbstractFile* m_pFile; + + /** + The full path to the file to be added. If it is empty, you need to initialize #m_pFile. + If #m_bFullPath is \c true and the path contains a drive letter, the drive letter is removed unless + CZipArchive::m_bRemoveDriveLetter is set to \c false. + */ + CZipString m_szFilePath; + + /** + The file name that will be stored in the archive. If the file is a directory, + there will be a path separator automatically appended. The CZipArchive::SetRootPath + method has no effect on this parameter. + */ + CZipString m_szFileNameInZip; + + /** + It has only the meaning when CZipAddNewFileInfo::m_szFileNameInZip is not specified and + CZipAddNewFileInfo::m_szFilePath is not empty. + + - If set to \c true, instructs to store the full path of the file inside the archive, + even if CZipArchive::m_szRootPath is set. + - If set to \c false only a filename without a path is stored in the archive. + In this case, if CZipArchive::m_szRootPath is set previously with + CZipArchive::SetRootPath, and if the beginning of #m_szFilePath equals + CZipArchive::m_szRootPath, then the filename is set to the not matched part + of #m_szFilePath (you could say to #m_szFilePath minus CZipArchive::m_szRootPath). + */ + bool m_bFullPath; + + /** + The level of compression. You can use values from 0 to 9 and -1 (meaning the default compression) + or one of the CZipCompressor::CompressionLevel values. + */ + int m_iComprLevel; + + /** + The smartness level of the file adding process. Can be one or combined CZipArchive::Smartness + values (you can use the logical \c OR). + */ + int m_iSmartLevel; + + /** + The index of an existing file in the archive to be replaced by the file being added. + See 0610231944|replace for more information. + The meaning of its values is as follows: + + - >= 0 : the index of the file to be replaced. + - \c ZIP_FILE_INDEX_UNSPECIFIED : do not replace any file and add the new file at + the end of the archive (default). Use this value in segmented archives. + + \note + - If you use an invalid index, the action will fail. + - If you specify the last file in the archive to be replaced, it'll be removed + and the usual action will be taken. + + \see CZipArchive::SetAdvanced + \see CZipArchive::WillBeDuplicated + */ + ZIP_INDEX_TYPE m_uReplaceIndex; + + /** + The size of the buffer used while file operations. + */ + unsigned long m_nBufSize; + + /** + Sets default values for #m_iSmartLevel, #m_uReplaceIndex, #m_nBufSize and #m_iComprLevel. + Examine the source code for the current values. + */ + void Defaults(); +}; + + + +/// +/// Represents a zip archive file. +/// +class ZIP_API CZipArchive +{ +public: + static const char m_gszCopyright[]; + static const char m_gszVersion[]; + + CZipArchive(); + + virtual ~CZipArchive(); + + /** + Sets a password for the file to be opened or created. + Use this method before opening or adding a file, but after opening the archive. + The password is cleared during opening the archive. For the encryption to work, + encryption method must be set to other value than CZipCryptograph::encNone. + + \param lpszPassword + The password. Set it to \c NULL or an empty string to clear the password. + + \return + \c false if the password cannot be changed at this time; \c true otherwise. + + \see + 0610201627 + \see + SetEncryptionMethod + \see + WillEncryptNextFile + */ + bool SetPassword(LPCTSTR lpszPassword = NULL); + + /** + Gets the current archive password or an empty string if there is no password set. + \return + The current password. + \see + SetPassword + */ + CZipString GetPassword()const ; + + /** + Returns the value indicating whether the next file will be encrypted or not. To encrypt a file, + a password must be set with the #SetPassword method and an encryption method must be set + to a value different from CZipCryptograph::encNone. + \return + \c true, if the next file added to the archive will be encrypted; \c false otherwise. + \see + 0610201627 + \see + SetEncryptionMethod + \see + GetEncryptionMethod + \see + SetPassword + \see + GetPassword + */ + bool WillEncryptNextFile() const + { + return m_pszPassword.GetSize() != 0 && m_iEncryptionMethod != CZipCryptograph::encNone; + } + + /** + Sets the encryption method when encrypting files. + You can encrypt different files using different methods. + You need to set the password with the #SetPassword method for the encryption to work. + It is important to set the encryption method only when compressing. When decompressing, + the encryption method will be detected automatically. + + \param iEncryptionMethod + One of the CZipCryptograph::EncryptionMethod values. + + \return + \c false if selected encryption method is not supported or a + file is opened for compression; \c true otherwise. + + \see + 0610201627 + \see + SetPassword + \see + CZipCryptograph::EncryptionMethod + \see + GetEncryptionMethod + \see + WillEncryptNextFile + */ + bool SetEncryptionMethod(int iEncryptionMethod = CZipCryptograph::encStandard); + + /** + Gets the current encryption method. + + \return + One of CZipCryptograph::EncryptionMethod values. + + \see + SetEncryptionMethod + \see + WillEncryptNextFile + */ + int GetEncryptionMethod() const + { + return m_iEncryptionMethod; + } + + /** + Encrypts an existing file with a given index using the current encryption method. + + \param uIndex + The index of the file to encrypt. + + \return + \c false, if the file could not be encrypted; \c true otherwise. + + \note + - The method will not encrypt a file, if it already is encrypted. + - Calls the CZipActionCallback::cbEncryptPrepare, CZipActionCallback::cbMultiEncrypt, + CZipActionCallback::cbEncryptMoveData and CZipActionCallback::cbEncrypt callbacks. + - Throws exceptions. + + \see + 0610201627|existing + \see + SetEncryptionMethod + \see + SetPassword + \see + WillEncryptNextFile + \see + EncryptFiles + \see + EncryptAllFiles + + */ + bool EncryptFile(ZIP_INDEX_TYPE uIndex) + { + CZipIndexesArray aIndexes; + aIndexes.Add(uIndex); + return EncryptFilesInternal(&aIndexes); + } + + /** + Encrypts existing files with given indexes using the current encryption method. + + \param aIndexes + The indexes of files to encrypt. + + \return + \c false, if the files could not be encrypted; \c true otherwise. + + \note + - The method will not encrypt files that are already encrypted. + - Calls the CZipActionCallback::cbEncryptPrepare, CZipActionCallback::cbMultiEncrypt, + CZipActionCallback::cbEncryptMoveData and CZipActionCallback::cbEncrypt callbacks. + - Throws exceptions. + + \see + 0610201627|existing + \see + SetEncryptionMethod + \see + SetPassword + \see + WillEncryptNextFile + \see + EncryptFile + \see + EncryptAllFiles + + */ + bool EncryptFiles(CZipIndexesArray &aIndexes) + { + return EncryptFilesInternal(&aIndexes); + } + + /** + Encrypts all existing files in the archive using the current encryption method. + + \return + \c false, if the files could not be encrypted; \c true otherwise. + + \note + - The method will not encrypt files that are already encrypted. + - Calls the CZipActionCallback::cbEncryptPrepare, CZipActionCallback::cbMultiEncrypt, + CZipActionCallback::cbEncryptMoveData and CZipActionCallback::cbEncrypt callbacks. + - Throws exceptions. + + \see + 0610201627|existing + \see + SetEncryptionMethod + \see + SetPassword + \see + WillEncryptNextFile + \see + EncryptFile + \see + EncryptFiles + + */ + bool EncryptAllFiles() + { + return EncryptFilesInternal(NULL); + } + + /** + Sets the compression method used when compressing file. If affects the files that are + added to the archive after calling this method. + + \param uCompressionMethod + The compression method to use. Valid values are CZipCompressor::methodDeflate and CZipCompressor::methodBzip2. + To store files (without compression), use the CZipCompressor::levelStore compression level + when adding files to the archive. + + \return + \c true, if the compression method is supported by the ZipArchive Library and was successfully set; + \c false otherwise. + + \note + The compression method used for extraction is automatically determined from the information + written in the archive. + + \see + 0610231446|methods + \see + CZipCompressor::IsCompressionSupported + \see + GetCompressionMethod + \see + GetCurrentCompressor + + */ + bool SetCompressionMethod(WORD uCompressionMethod = CZipCompressor::methodDeflate); + + /** + Returns the current compression method used when adding files to the archive. + + \return + The current compression method. Is one of the CZipCompressor::CompressionMethod values. + + \see + SetCompressionMethod + */ + WORD GetCompressionMethod() const + { + return m_uCompressionMethod; + } + + /** + Sets the compression options for an appropriate compressor. The library automatically detects to + which compressor the options apply by examining the return value from the CZipCompressor::COptions::GetType() method. + If a file is currently opened for compression or decompression, the options will have no effect on the current file + processing. A sample that illustrates setting options can be found at 0610231446|options. + + \param pOptions + The options to set. The \c NULL value has no effect. + The object is no longer needed and can be safely released after this method returns. + + \see + 0610231446|options + \see + GetCurrentCompressor + \see + CZipCompressor::GetOptions + \see + SetAdvanced + */ + void SetCompressionOptions(CZipCompressor::COptions* pOptions) + { + if (m_iFileOpened) + { + ZIPTRACE("%s(%i) : The options will have no effect on the current file processing.\n"); + } + m_compressorsOptions.Set(pOptions); + } + + /** + Sets the internal buffer sizes. No buffer size can be set smaller than 1024. + Use this method before opening the archive. The optimal size for + the write buffer for a segmented archive is the size of the volume. + + \param iWriteBuffer + The write buffer size. See also CZipStorage::m_iWriteBufferSize. + + \param iGeneralBuffer + A helper buffer used in moving data, deleting, getting (#GetFromArchive) + files, renaming and replacing. This buffer is not used for + compression and decompression. For these purposes, use the CZipCompressor::COptions::m_iBufferSize option. + + \param iSearchBuffer + A buffer used in searching for the central directory. See also CZipStorage::m_iLocateBufferSize. + + \see + GetAdvanced + \see + SetCompressionOptions + */ + void SetAdvanced(int iWriteBuffer = 65536, int iGeneralBuffer = 65536, int iSearchBuffer = 32768); + + + /** + Retrieves buffer sizes as set with the SetAdvanced() method. + + \param piWriteBuffer + + \param piGeneralBuffer + + \param piSearchBuffer + + \see + SetAdvanced + */ + void GetAdvanced(int* piWriteBuffer = NULL, int* piGeneralBuffer = NULL, int* piSearchBuffer= NULL) + { + if (piWriteBuffer) + *piWriteBuffer = m_storage.m_iWriteBufferSize; + if (piGeneralBuffer) + *piGeneralBuffer = m_iBufferSize; + if (piSearchBuffer) + *piSearchBuffer = m_storage.m_iLocateBufferSize; + } + + + /** + Registers the callback object to receive specified notifications. + + \param pCallback + The callback object to receive notifications. + Set it to \c NULL to stop receiving the selected notifications. + + \param iWhich + The callback type to register for (or unregister from). Can be one or more of the CZipActionCallback::CallbackType values. + + \see + 0610231200 + \see + CZipActionCallback + \see + CZipActionCallback::CallbackType + \see + GetCallback + + */ + void SetCallback(CZipActionCallback* pCallback = NULL, int iWhich = CZipActionCallback::cbAll) + { + m_callbacks.Set(pCallback, iWhich); + } + + /** + Gets the callback object registered for a given notification. + \param iWhich + The callback type. Can be one or more of CZipActionCallback::CallbackType values. + \return + The callback object set previously with #SetCallback. + \see + 0610231200 + \see + SetCallback + \see + CZipActionCallback + \see + CZipActionCallback::CallbackType + */ + CZipActionCallback* GetCallback(CZipActionCallback::CallbackType iWhich) + { + return m_callbacks.Get(iWhich); + } + + /** + The type of the callback object used during changing volumes in a segmented archive. + + \see + CZipArchive::SetSegmCallback + */ + enum SegmCallbackType + { + scSpan = 0x01, ///< The callback object will be set for operations on spanned archives only. + scSplit = 0x02, ///< The callback object will be set for operations on split archives only. + scAll = scSpan | scSplit ///< The callback object will be set for operations spanned and split archives. + }; + + /** + Sets the callback object used during operations on a segmented archive to change volumes in spanned and split archives. + Set it before opening the archive. If you open a spanned archive and don't set the callback object, + the exception CZipException::noCallback will be thrown. Setting the callback object is not required for + a split archive. + + Callback object's method CZipSegmCallback::Callback is called when the next volume is processed in a segmented archive. + Calling CZipArchive methods from inside this method may result in an unexpected behavior. + + \param pCallback + The address of the callback object. Set it to \c NULL to clear the callback. + + \param callbackType + The type of the callback to set. It can be one of the #SegmCallbackType values. + + \see + 0610051553 + \see + CZipSegmCallback + */ + void SetSegmCallback(CZipSegmCallback* pCallback = NULL, int callbackType = scSpan); + + + /** + Archive open modes used in the CZipArchive::Open(LPCTSTR, int, ZIP_SIZE_TYPE) + and CZipArchive::Open(CZipAbstractFile&, int ) methods. + */ + enum OpenMode + { + zipOpen, ///< Opens an existing archive. + zipOpenReadOnly, ///< Opens an existing archive as a read only file. This mode is intended to use in a self extract code, when opening an archive on a storage without the write access (e.g. CD-ROMS) or when sharing the central directory (see OpenFrom()). If you try to modify the archive in this mode, an exception will be thrown. + zipCreate, ///< Creates a new archive. + zipCreateSegm, ///< Creates a segmented archive. + zipCreateAppend ///< Creates a new archive, but allows appending the archive to an existing file (which can be for example a self-extracting stub). + }; + + /** + Opens or creates a zip archive. + + The archive creation mode depends on the \a iMode and \a uVolumesSize values: + - If \a iMode == #zipCreateSegm and \a uVolumeSize is \c ZIP_AUTODETECT_VOLUME_SIZE then a spanned archive is created. + - If \a iMode == #zipCreateSegm and \a uVolumeSize > 0 then a split archive is created. + - If \a iMode == #zipOpen or \a iMode == #zipOpenReadOnly and the existing archive is a segmented archive + then CZipStorage::spannedArchive mode is assumed if the archive is on a removable device + or CZipStorage::splitArchive otherwise. If you want to open a split archive on a removable device, + set \a uVolumeSize to a value different from 0 (under Linux, the device is always assumed to be removable due to lack of + implementation of the ZipPlatform::IsDriveRemovable method). + - If \a iMode == #zipCreate or a \a iMode == #zipCreateAppend then \a uVolumeSize doesn't matter. + + \param szPathName + The path to the archive. + + \param iMode + Can be one of the #OpenMode values. + + \param uVolumeSize + The volume size in a split archive. The size of the volume may be from 1 to 4,294,967,295. + The bigger this value is - the faster is creation and extraction of segmented archives, + because there are no volume changes. + + \return + \c true, if the archive was opened successfully; \c false, if the archive was already opened before. + + \note + Throws exceptions. + + \see + 0610231446 + \see + 0610241003 + \see + 0610051553 + \see + Open(CZipAbstractFile&, int); + \see + GetSegmMode + */ + bool Open(LPCTSTR szPathName, int iMode = zipOpen, ZIP_SIZE_TYPE uVolumeSize = 0); + + + /** + Opens or creates an archive in memory. The CZipAbstractFile object is not closed + after closing the archive, so that it is possible to work with it afterwards. + + \param af + \c CZipAbstractFile object to store the archive data. + + \param iMode + The open mode. The following values are valid: #zipOpen, #zipOpenReadOnly, #zipCreate, #zipCreateAppend. + If you use #zipCreate, the contents of the memory file are cleared. Use #zipCreateAppend, if you want to + append the archive at the end of the data contained in the memory file. + + \return + \c true, if the archive was opened successfully; \c false, if the archive was already opened before or an + invalid open mode was specified. + + \note + Throws exceptions. + + \see + 0610231924 + \see + Open(LPCTSTR, int, ZIP_SIZE_TYPE); + */ + bool Open(CZipAbstractFile& af, int iMode = zipOpen); + + /** + Opens the archive from the already opened archive. Both archives will share the same central directory. + The \a zip archive must be opened in read-only mode and the newly opened archive will open as read-only as well. + + \param zip + The archive that provides the reference to the central directory. It must be a read-only archive and it cannot be in memory. + + \return + \c true, if the new archive was successfully opened; \c false otherwise. + + \note + If you use this method in a multithreaded environment, + make sure that \c ZIP_ARCHIVE_USE_LOCKING is defined in the \e _features.h file. Also make sure, that \a zip stays open until + this method returns. + \note + Throws exceptions. + + \see + 0610241003|thread + \see + zipOpenReadOnly + + */ + bool OpenFrom(CZipArchive& zip); + + /** + Sets the path fragment to be removed from the beginning of the full path when adding or extracting a file. + + Use it, if you don't want to use the full path (by setting the \a bFullPath parameter in #AddNewFile or #ExtractFile to \c true) + and you don't want to remove the whole path neither (be setting the same parameter to \c false), but you want to remove only a specific beginning. + Use it after opening the archive and before calling the #AddNewFile or #ExtractFile methods. + + \param szPath + The string that you want to be removed from the beginning of the path of the file + in the archive. Set it to \c NULL stop removing the path beginning. + + \note + Set the case-sensitivity with the #SetCaseSensitivity method. + + \see + AddNewFile + \see + ExtractFile + \see + GetRootPath + + */ + void SetRootPath(LPCTSTR szPath = NULL); + + + /** + Gets the value set previously with the SetRootPath() method. + + \return + The current value of the #m_szRootPath field. + + \see + SetRootPath + */ + CZipString GetRootPath()const + { + return m_szRootPath; + } + + /** + The levels of smartness of the adding files action (CZipArchive::AddNewFile). + \note If you use #zipsmCheckForEff, you should use + #zipsmNotCompSmall as well, because the small file will be surely larger + after compression, so that you can add it not compressed straight away. The compression level + is always ignored for a directory and set to 0. + */ + enum Smartness + { + zipsmLazy = 0x0000, ///< All the smartness options turned off. + zipsmCPassDir = 0x0001, ///< Clears the password for directories. + zipsmCPFile0 = 0x0002, ///< Clears the password for files of 0 size. + + /** + Does not compress files smaller than 5 bytes - they are always stored larger than uncompressed. + */ + zipsmNotCompSmall = 0x0004, + + /** + Checks whether the compressed file is larger than uncompressed and if so, remove it and store + without the compression. In a segmented archive, a temporary file is used for that: + if the file compression is efficient, the data is not compressed again, but moved from + the temporary file to the archive. You can use the #SetTempPath method to set the path where the + file will be created or you can let the library figure it out (see #SetTempPath). + If the the library could not find enough free space for the temporary file, + the compression goes the usual way. + */ + zipsmCheckForEff = 0x0008, + + /** + Combine it with #zipsmCheckForEff or use #zipsmCheckForEffInMem, the temporary file + will be created in memory then. This flag is effective also when replacing files + (see the note at CZipAddNewFileInfo::m_uReplaceIndex). + */ + zipsmMemoryFlag = 0x0010, + + /** + The same as #zipsmCheckForEff, but the temporary file is created created in memory instead. + It has the meaning only in a segmented archive, not segmented archives don't need a temporary file. + */ + zipsmCheckForEffInMem = zipsmMemoryFlag | zipsmCheckForEff, + zipsmSmartPass = zipsmCPassDir | zipsmCPFile0, ///< The password policy (a combination of #zipsmCPassDir and #zipsmCPFile0). + zipsmSmartAdd = zipsmNotCompSmall | zipsmCheckForEff, ///< Smart adding (a combination of #zipsmNotCompSmall and #zipsmCheckForEff). + zipsmSafeSmart = zipsmSmartPass | zipsmNotCompSmall, ///< Safe smart (smartest without checking for efficiency). + zipsmSmartest = zipsmSmartPass | zipsmSmartAdd, ///< Smartness at its best. + zipsmInternal01 = 0xf000 ///< Intended for the internal use only. + }; + + + /** + Adds a new file to the opened archive. + + \param info + See CZipAddNewFileInfo for more information. + + \return + If \c false then the file was not added (in this case, you can still try to add other files); \c true otherwise. + + \note + - If you abort the operation from a callback object, while adding a file in a not segmented archive, the added data will be removed from the archive. + - Throws exceptions. When an exception is thrown, you may need to call #CloseNewFile with \a bAfterException set to \c true, to make the archive reusable. + + \see + 0610231446 + \see + 0610231200 + \see + 0610231924 + \see + AddNewFile(LPCTSTR, LPCTSTR, int, int, unsigned long) + \see + AddNewFile(LPCTSTR, int, bool, int, unsigned long) + \see + AddNewFile(CZipMemFile&, LPCTSTR, int, int, unsigned long) + \see + AddNewFiles(LPCTSTR, ZipArchiveLib::CFileFilter&, bool, int, bool, int, unsigned long) + \see + AddNewFiles(LPCTSTR, LPCTSTR, bool, int, bool, int, unsigned long) + \see + SetCallback + */ + bool AddNewFile(CZipAddNewFileInfo& info); + + + /** + Adds a new file to the opened archive. + See the #AddNewFile(CZipAddNewFileInfo& ) method. + The parameters are equivalent to CZipAddNewFileInfo member variables. + + */ + bool AddNewFile(LPCTSTR lpszFilePath, int iComprLevel = -1, bool bFullPath = true, + int iSmartLevel = zipsmSafeSmart, unsigned long nBufSize = 65536); + + + /** + Adds a new file to the opened archive. + See the #AddNewFile(CZipAddNewFileInfo& ) method. + The parameters are equivalent to CZipAddNewFileInfo member variables. + */ + bool AddNewFile(LPCTSTR lpszFilePath, + LPCTSTR lpszFileNameInZip, + int iComprLevel = -1, + int iSmartLevel = zipsmSafeSmart, + unsigned long nBufSize = 65536); + + /** + Adds a new file to the opened archive. + See the #AddNewFile(CZipAddNewFileInfo& ) method. + The parameters are equivalent to CZipAddNewFileInfo member variables. + */ + bool AddNewFile(CZipMemFile& mf, + LPCTSTR lpszFileNameInZip, + int iComprLevel = -1, + int iSmartLevel = zipsmSafeSmart, + unsigned long nBufSize = 65536); + + + /** + Adds new files to the opened archive from the specified directory using a filter. + + \param lpszPath + The root directory containing the files to add. + + \param filter + A filter that determines which files should be added. + + \param bRecursive + \c true, if the files from the subfolders of \a lpszPath should also be added; \c false otherwise. + + \param iComprLevel + The level of compression. You can use values from 0 to 9 and -1 (meaning the default compression) + or one of the CZipCompressor::CompressionLevel values. + + \param bSkipInitialPath + \c true, if the \a lpszPath directory should be trimmed out of the paths stored in the archive; + \c false otherwise. + + \param iSmartLevel + The smartness level of the file adding process. Can be one or combined #Smartness + values (you can use the logical \c OR). + + \param nBufSize + The size of the buffer used while file operations. + + \return + If \c false then some files were probably not added (in this case, you can still try to add other files); \c true otherwise. + + \note + Throws exceptions. + + \see + 0610231446|filters + \see + ZipArchiveLib::CFileFilter + \see + ZipArchiveLib::CNameFileFilter + \see + ZipArchiveLib::CGroupFileFilter + \see + AddNewFiles(LPCTSTR, LPCTSTR, bool, int, bool, int, unsigned long) + \see + AddNewFile(CZipAddNewFileInfo&) + \see + AddNewFile(LPCTSTR, LPCTSTR, int, int, unsigned long) + \see + AddNewFile(LPCTSTR, int, bool, int, unsigned long) + \see + AddNewFile(CZipMemFile&, LPCTSTR, int, int, unsigned long) + + */ + bool AddNewFiles(LPCTSTR lpszPath, + ZipArchiveLib::CFileFilter& filter, + bool bRecursive = true, + int iComprLevel = -1, + bool bSkipInitialPath = true, + int iSmartLevel = zipsmSafeSmart, + unsigned long nBufSize = 65536); + + /** + Adds new files to the opened archive from the specified directory using a filename mask. + + \param lpszPath + The root directory containing the files to add. + + \param lpszFileMask + The filename mask to filter the files. Only files that has a filename matching this mask will + be added to the archive. This method internally uses ZipArchiveLib::CNameFileFilter. + + \param bRecursive + \c true, if the files from the subfolders of \a lpszPath should also be added; \c false otherwise. + + \param iComprLevel + The level of compression. You can use values from 0 to 9 and -1 (meaning the default compression) + or one of the CZipCompressor::CompressionLevel values. + + \param bSkipInitialPath + \c true, if the \a lpszPath directory should be trimmed out of the paths stored in the archive; + \c false otherwise. + + \param iSmartLevel + The smartness level of the file adding process. Can be one or combined #Smartness + values (you can use the logical \c OR). + + \param nBufSize + The size of the buffer used while file operations. + + \return + If \c false then some files were probably not added (in this case, you can still try to add other files); \c true otherwise. + + \note + Throws exceptions. + + \see + name: 0610242025|wildcards + \see + AddNewFiles(LPCTSTR, ZipArchiveLib::CFileFilter&, bool, int, bool, int, unsigned long) + \see + AddNewFile(CZipAddNewFileInfo&) + \see + AddNewFile(LPCTSTR, LPCTSTR, int, int, unsigned long) + \see + AddNewFile(LPCTSTR, int, bool, int, unsigned long) + \see + AddNewFile(CZipMemFile&, LPCTSTR, int, int, unsigned long) + */ + bool AddNewFiles(LPCTSTR lpszPath, + LPCTSTR lpszFileMask = _T("*.*"), + bool bRecursive = true, + int iComprLevel = -1, + bool bSkipInitialPath = true, + int iSmartLevel = zipsmSafeSmart, + unsigned long nBufSize = 65536) + { + ZipArchiveLib::CNameFileFilter filter(lpszFileMask); + return AddNewFiles(lpszPath, filter, bRecursive, iComprLevel, + bSkipInitialPath, iSmartLevel, nBufSize); + } + + /** + Adds a new file to the opened archive. The archive cannot be + an existing (at the moment of opening the archive) segmented archive, + because modifying such an archive is not possible with this version. + + \param header + The structure that provides additional information about the added file and serves as a template for + the properties of the new file. The following fields are used: + \li CZipFileHeader::m_uModDate and CZipFileHeader::m_uModTime - the modification time. Use CZipFileHeader::SetTime to set them. + If \a lpszFilePath is not \c NULL these fields are overwritten and updated automatically. + \li CZipFileHeader::m_uExternalAttr - the attributes of the file. Use #SetFileHeaderAttr to set them. + If \a lpszFilePath is not \c NULL this field is overwritten and updated automatically. + \li \c CZipFileHeader::m_pszFileName - the filename (may be with a path) to be stored inside the archive + to represent this file. Use CZipFileHeader::SetFileName to set it. + \li CZipFileHeader::m_uLocalComprSize - predicted compressed size. Set it when using the Zip64 functionality and not using + encryption or segmentation - you may set it to the size of the file that you want to compress. + This is for prediction if the Zip64 extensions are needed, but you should not worry too much about setting + this value, The ZipArchive Library will fix the headers if necessary - it just may save some processing. + \li \c CZipFileHeader::m_pszComment - the file comment. Use CZipFileHeader::SetComment to set it. + \li CZipFileHeader::m_aLocalExtraData - the local extra fields. + \li CZipFileHeader::m_aCentralExtraData - the central extra fields. + + Other fields are ignored - they are updated automatically. + If the method returns \c true, \link #SetSystemCompatibility + system compatibility \endlink for this object is set to the correct value. + Additionally if \a lpszFilePath was not \c NULL, the attributes and + the time fields are filled with information retrieved from + the file pointed by \a lpszFilePath. + + \param iLevel + The level of compression. You can use values from 0 to 9 and -1 (meaning the default compression) + or one of the CZipCompressor::CompressionLevel values. + + \param lpszFilePath + The path to the file to retrieve the date stamp and attributes from. + These values are stored inside the archive. + + \return + \c false in the following cases: + \li The \a lpszFilePath is not \c NULL and the file attributes and data was not correctly retrieved. + \li A file is already opened for extraction or compression. + \li The archive is an existing segmented archive. + \li The maximum file count inside the archive has already been reached + (65,535 for a standard archive and \c 0xFFFFFFFFFFFFFFFF for an archive in the Zip64 format). + + \c true otherwise. + + \note + Throws exceptions. + + \see + 0610231446|advanced + \see + 0610242300 + \see + WriteNewFile + \see + CloseNewFile + */ + bool OpenNewFile(CZipFileHeader& header, int iLevel = CZipCompressor::levelDefault, LPCTSTR lpszFilePath = NULL) + { + return OpenNewFile(header, iLevel, lpszFilePath, ZIP_FILE_INDEX_UNSPECIFIED); + } + + /** + Compresses the contents of the buffer and write it to a new file. + + \param pBuf + The buffer containing the data to be compressed and written. + + \param uSize + The number of bytes to be written from \a pBuf. + + \return + \c false, if the new file hasn't been opened yet; \c true otherwise. + + \note + Throws exceptions. + + \see + 0610231446|advanced + \see + OpenNewFile + \see + CloseNewFile + */ + bool WriteNewFile(const void *pBuf, DWORD uSize); + + /** + Closes the new file in the archive. + \return + \c false, if there is no new file opened; \c true otherwise. + + \param bAfterException + If \c true, the new file will be closed without writing anything. Set it to \c true + after an exception was thrown. Use it also this way if an exception other than + CZipException::abortedSafely was thrown from one of the #AddNewFile methods. + + \note + Throws exceptions. + + \see + 0610231446|advanced + \see + OpenNewFile + \see + WriteNewFile + */ + bool CloseNewFile(bool bAfterException = false); + + /** + Acquires a file with the given index from another archive. + The compressed data of the file from another archive is copied to the current archive + without decompression. + + \param zip + The opened archive to get the file from (must not be a segmented archive). + + \param uIndex + A zero-based index of the file to get from the \a zip archive. + + \param lpszNewFileName + The new filename to replace the old one from the \a zip archive. Can be \c NULL to leave the filename the same. + + \param uReplaceIndex + The same as CZipAddNewFileInfo::m_uReplaceIndex. Can be \c ZIP_FILE_INDEX_UNSPECIFIED. + + \param bKeepSystComp + If \c false, then the system compatibility of the file from the \a zip archive + is converted to the current archive system compatibility, if they differ. Otherwise + the source system compatibility is copied. + + \return + \c false, if the operation could not be performed (either of archives is closed, + a file inside either of archives is opened, \a zip archive is segmented or the current + archive is an existing segmented archive. + + \note + This method will encrypt data, if an encryption method and a password are set and the file is not already encrypted. + + \note + Throws exceptions. When an exception is thrown, you may need to call #CloseNewFile with + \a bAfterException set to \c true, to make the archive reusable. + + \note + It is safe to abort the action (by returning \c false from the CZipActionCallback::Callback) + in a not segmented archive and when no replacing is taking place. The file that is not + entirely added is removed from the archive then. + + \see + 0610231446|get + \see + 0610231200 + \see + GetFromArchive(CZipArchive&, CZipIndexesArray&, bool) + \see + GetFromArchive(CZipArchive&, CZipStringArray&, bool) + \see + SetCallback + \see + SetAdvanced + \see + SetEncryptionMethod + \see + SetPassword + */ + bool GetFromArchive(CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewFileName = NULL, ZIP_INDEX_TYPE uReplaceIndex = ZIP_FILE_INDEX_UNSPECIFIED, bool bKeepSystComp = false) + { + InitBuffer(); + bool bRet; + try + { + bRet = GetFromArchive(zip, uIndex, lpszNewFileName, uReplaceIndex, bKeepSystComp, GetCallback(CZipActionCallback::cbGet)); + } + catch(...) + { + ReleaseBuffer(); + throw; + } + ReleaseBuffer(); + if (bRet && m_bAutoFlush) + Flush(); + + return bRet; + } + + /** + Acquires files with the given indexes from another archive. + The compressed data of the file from another archive is copied to the current archive + without decompression. + + \param zip + The opened archive to get the file from (must not be a segmented archive). + + \param aIndexes + An array of zero-based indexes of the files to acquire from the \a zip archive. + + \param bKeepSystComp + If \c false, then the system compatibility of the file from the \a zip archive + is converted to the current archive system compatibility, if they differ. Otherwise + the source system compatibility is copied. + + \return + \c false, if the operation could not be performed (either of archives is closed, + a file inside either of archives is opened, \a zip archive is segmented or the current + archive is an existing segmented archive. + + \note + This method will encrypt data, if an encryption method and a password are set and the file is not already encrypted. + + \note + Throws exceptions. When an exception is thrown, you may need to call #CloseNewFile with + \a bAfterException set to \c true, to make the archive reusable. + + \note + It is safe to abort the action (by returning \c false from the CZipActionCallback::Callback) + in a not segmented archive and when no replacing is taking place. The file that is not + entirely added is removed from the archive then. + + \see + 0610231446|get + \see + 0610231200 + \see + GetFromArchive(CZipArchive&, ZIP_INDEX_TYPE, LPCTSTR, ZIP_INDEX_TYPE, bool) + \see + GetFromArchive(CZipArchive&, CZipStringArray&, bool) + \see + SetCallback + \see + SetAdvanced + \see + SetEncryptionMethod + \see + SetPassword + */ + bool GetFromArchive(CZipArchive& zip, CZipIndexesArray &aIndexes, bool bKeepSystComp = false); + + /** + Acquires files with the given names from another archive. + The compressed data of the file from another archive is copied to the current archive + without decompression. + + \param zip + The opened archive to get the file from (must not be a segmented archive). + + \param aNames + An array of filenames to acquire from the \a zip archive. + + \param bKeepSystComp + If \c false, then the system compatibility of the file from the \a zip archive + is converted to the current archive system compatibility, if they differ. Otherwise + the source system compatibility is copied. + + \return + \c false, if the operation could not be performed (either of archives is closed, + a file inside either of archives is opened, \a zip archive is segmented or the current + archive is an existing segmented archive. + + \note + This method will encrypt data, if an encryption method and a password are set and the file is not already encrypted. + + \note + Throws exceptions. When an exception is thrown, you may need to call #CloseNewFile with + \a bAfterException set to \c true, to make the archive reusable. + + \note + It is safe to abort the action (by returning \c false from the CZipActionCallback::Callback) + in a not segmented archive and when no replacing is taking place. The file that is not + entirely added is removed from the archive then. + + \note + This method calls #GetIndexes on the \a zip archive. + + \see + 0610231446|get + \see + 0610231200 + \see + GetFromArchive(CZipArchive&, ZIP_INDEX_TYPE, LPCTSTR, ZIP_INDEX_TYPE, bool) + \see + GetFromArchive(CZipArchive&, CZipIndexesArray&, bool) + \see + SetCallback + \see + SetAdvanced + \see + SetEncryptionMethod + \see + SetPassword + */ + + bool GetFromArchive(CZipArchive& zip, CZipStringArray &aNames, bool bKeepSystComp = false) + { + CZipIndexesArray indexes; + zip.GetIndexes(aNames, indexes); + return GetFromArchive(zip, indexes, bKeepSystComp); + } + + /** + Gets indexes of the files with names stored in \a aNames and puts them into \a aIndexes. + If a filename was not found, \c ZIP_FILE_INDEX_NOT_FOUND is inserted at the appropriate + position in \a aIndexes. + + \param aNames + An array of filenames inside the archive. + \param aIndexes + An array of indexes to be found. + + \note + Use the #SetCaseSensitivity method to set case-sensitivity. + + \see + 0610242025|findfast + \see + EnableFindFast + */ + void GetIndexes(const CZipStringArray &aNames, CZipIndexesArray& aIndexes); + + /** + Extracts a file from the archive. + The argument \a lpszNewName may point to a full path and is influenced by \a bFullPath. + If \a lpszNewName contains a drive specification then the drive part is removed + unless #m_bRemoveDriveLetter is set to \c false. + + \param uIndex + The index of the file to extract. + + \param lpszPath + The directory to extract the file to. May not be \c NULL. + + \param bFullPath + In this paragraph the source path means: + \li The full filename stored in the archive, if \a lpszNewName is \c NULL + \li \a lpszNewName, if it is not \c NULL + + The meaning of \a bFullPath is following: + \li If it is \c true, then the method extracts using the full source path, even if #m_szRootPath is set. + In this case the resulting file path is \a lpszPath plus the source path. + \li If it is \c false, then the destination file path is \a lpszPath plus + the filename only extracted from the source path. + In this case, if #m_szRootPath is set (with #SetRootPath), then before adding the source path + to \a lpszPath, from the source path is removed the part that matches #m_szRootPath + (matching is performed starting from the beginning of both strings). + + + \param lpszNewName + The new name of the file after extraction. + If \c NULL, the original filename stored in the archive is used. + May include a path information, but if \a bFullPath is \c false, + only the filename is extracted from this value. + + \param pSeekPair + If not NULL, the file will be extracted starting from the seek position described by this value. + + \param nBufSize + The size of the buffer used while file operations. + + \return + \c true if successful; \c false otherwise. + + \note + - To extract files which filenames that match a specified pattern, use the #FindMatches method. + - Throws exceptions. + + \see + 0610241003 + \see + 0610231200 + \see + 0711101739 + \see + ExtractFile(ZIP_INDEX_TYPE, CZipMemFile&, bool, CZipCompressor::COffsetsPair*, DWORD) + \see + FindMatches + \see + SetCallback + */ + bool ExtractFile(ZIP_INDEX_TYPE uIndex, + LPCTSTR lpszPath, + bool bFullPath = true, + LPCTSTR lpszNewName = NULL, + DWORD nBufSize = 65536); + + /** + The same as #ExtractFile(ZIP_INDEX_TYPE, LPCTSTR, bool, LPCTSTR, CZipCompressor::COffsetsPair*, DWORD ) + but instead to a physical file, this method extracts data into a \c CZipMemFile object. + + \param uIndex + The index of the file to extract. + + \param mf + The memory file to receive the decompressed data. + + \param bRewind + If \c true, the memory file pointer is positioned at the beginning of the compressed data after compression. + The rewind operation is performed even if extraction was aborted, but rewinding will not take + place, if other exception than CZipException::abortedAction or CZipException::abortedSafely was thrown in the meantime. + \param pSeekPair + If not NULL, the file will be extracted starting from the seek position described by this value. + \param nBufSize + The size of the buffer used while file operations. + + \note + - Writing of the decompressed data starts at the current position of the memory file. + Keep this in mind, when you pass a \c CZipMemFile object that already contains data + (or has a buffer attached) - its contents may be overwritten. + - If you try to extract a directory, the method will return \c false. + + \see + 0610231924 + \see + 0711101739 + \see + ExtractFile(ZIP_INDEX_TYPE, LPCTSTR, bool, LPCTSTR, CZipCompressor::COffsetsPair*, DWORD ) + */ + bool ExtractFile(ZIP_INDEX_TYPE uIndex, + CZipMemFile& mf, + bool bRewind = true, + DWORD nBufSize = 65536); + + /** + Opens the file with the given index in the archive for extracting. + Not successful opening of the file doesn't lock the whole archive, so + you can try to open another one (after catching an exception, if it was + thrown) + \param uIndex + The index of the file to open. + + \return + \c true, if successful; \c false otherwise. This method will also return \c false, if the compression method + of the file is not supported by the ZipArchive Library. + + \throws CZipException + with the CZipException::badPassword code, if the file is encrypted + and the password was not set. + + \see + 0610241003|advanced + \see + ReadFile + \see + CloseFile + */ + bool OpenFile(ZIP_INDEX_TYPE uIndex); + + /** + Reads data from the currently opened file and decompresses it to \a pBuf. + \param pBuf + The buffer to receive the decompressed data. + + \param uSize + The size of \a pBuf. + + \return + The number of bytes read. + + \see + 0610241003|advanced + \see + OpenFile + \see + CloseFile + + \note Throws exceptions. + */ + DWORD ReadFile(void *pBuf, DWORD uSize); + + + /** + Closes the file opened for extraction in the archive and copy its date and + attributes to the file pointed by \a lpszFilePath. + + \param lpszFilePath + The path of the file to have the date and attributes information updated. + Make sure you have the read access to this file. + + \param bAfterException + Set it to \c true, when you call this method after an exception was + thrown, to allow further operations on the archive. + + \return + One of the following values: + - \c 1 : The operation was successful. + - \c 0 : There is no file opened. + - \c -1 : Some bytes were left to uncompress - probably due to a bad password or a corrupted archive. + - \c -2 : Setting extracted file date and attributes was not successful. + + \see + 0610241003|advanced + \see + OpenFile + \see + ReadFile + \see + CloseFile(CZipFile&) + + \note Throws exceptions. + */ + int CloseFile(LPCTSTR lpszFilePath = NULL, bool bAfterException = false); + + /** + Closes \a file and then calls the CloseFile(LPCTSTR, bool) method using the path of \a file as an argument. + Don't call this method, if an exception was thrown before, call the #CloseFile(LPCTSTR, bool) method instead. + + \param file + A \c CZipFile object of the extracted file. It must be opened. + + \return + The same values as the #CloseFile(LPCTSTR, bool) method. + + \note Throws exceptions. + + \see + 0610241003|advanced + \see + OpenFile + \see + ReadFile + \see + CloseFile(LPCTSTR, bool) + */ + int CloseFile(CZipFile &file); + + /** + Tests the file with the given index for the integrity. + The method throws exceptions but performs all the necessary cleanup + before, so that the next file can be tested after catching the exception. + + \param uIndex + The index of the file to test. + + \param uBufSize + The size of the buffer used during extraction. + + \return + \c false, if the incorrect action has been taken (when #OpenFile or #GetFileInfo returned \c false or \a uBufSize is 0); \c true otherwise. + If the file didn't passed the test or there was a disk I/O error or the supplied password was incorrect, an exception is thrown. + + \note + Throws exceptions. + + \see + 0610241003 + \see + SetCallback + */ + bool TestFile(ZIP_INDEX_TYPE uIndex, DWORD uBufSize = 65536); + + /** + Deletes the file with the given index from the archive. + If you plan to delete more than one file, use the #RemoveFiles(CZipIndexesArray&) or + #RemoveFiles(const CZipStringArray&) method. These methods are optimized for deleting multiple files. + + \param uIndex + A zero-based index of the file to delete. + \return + \c false, if the file could not be removed; \c true otherwise. + + \note + Throws exceptions. + + \see + 0610231944|delete + \see + RemoveFiles(CZipIndexesArray&) + \see + RemoveFiles(const CZipStringArray&) + \see + SetCallback + \see + FindMatches + */ + bool RemoveFile(ZIP_INDEX_TYPE uIndex); + + /** + Deletes files from the archive. + Sorts \a aIndexes in the ascending order. + + \param aIndexes + An array of zero-based indexes of the files to delete. + + \return + \c false, if files could not be removed; \c true otherwise. + + \note + - To remove files which filenames match a specified pattern, use the #FindMatches method before to find the indexes. + - Throws exceptions. + + + \see + 0610231944|delete + \see + RemoveFile + \see + RemoveFiles(const CZipStringArray& ) + \see + SetCallback + \see + FindMatches + */ + bool RemoveFiles(CZipIndexesArray& aIndexes); + + + /** + Delete files from the archive. + + \param aNames + An array of filenames to delete; + \return + \c false, if files could not be removed; \c true otherwise. + + \note + - Use the #SetCaseSensitivity method to set case-sensitivity. + - This method uses Find Fast (see 0610242025|findfast for more information). + - Throws exceptions. + + \see + 0610231944|delete + \see + RemoveFile + \see + RemoveFiles(CZipIndexesArray&) + \see + SetCallback + \see + EnableFindFast + */ + bool RemoveFiles(const CZipStringArray& aNames); + + /** + Shifts data inside the archive to make an empty space at the beginning of the archive. + Into this empty space, you can copy for example a self-extracting stub. To perform shifting, + the archive must be opened and no file must be opened for compression or extraction. This method + will not work with segmented archives or archives, for which #GetBytesBeforeZip method returns value + different from \c 0. + + \param uOffset + The number of bytes to shift the archive data by. + + \return + \c true, if data was shifted successfully; \c false otherwise. + + \note + - Calls the CZipActionCallback::cbMoveData callback. + - Throws exceptions. + + \see + 0610242241|convert + \see + PrependData(CZipAbstractFile&, LPCTSTR) + \see + PrependData(LPCTSTR, LPCTSTR) + */ + bool ShiftData(ZIP_SIZE_TYPE uOffset); + + /** + Inserts data contained in the file pointed by the \a lpszFilePath path before the archive data. + You can use this method for example to convert the archive into a self-extracting archive (store + a self-extracting stub inside \a lpszFilePath file). + To perform prepending, the archive must be opened and no file must be opened for compression or extraction. This method + will not work with segmented archives or archives, for which #GetBytesBeforeZip method returns value + different from \c 0. + + \param lpszFilePath + The path of the file to prepend to the archive. + + \param lpszNewExt + If it is not \c NULL, then the extension of the archive is changed to this value after prepending data. + Under linux additionally, this method sets executable permission for the owner after prepeding. If renaming is performed, + then the archive is closed before it. If this value is \c NULL, the no renaming is performed and the archive stays opened. + + \return + \c true, if data from \a lpszFilePath file was prepended (and optionally renamed) successfully; \c false otherwise. + + \note + - Calls the CZipActionCallback::cbMoveData callback. + - Throws exceptions. + + \see + 0610242241|convert + \see + ShiftData + \see + PrependData(CZipAbstractFile&, LPCTSTR) + */ + bool PrependData(LPCTSTR lpszFilePath, LPCTSTR lpszNewExt = +#ifdef ZIP_ARCHIVE_WIN + _T("exe") +#else + _T("") +#endif + ); + + /** + Inserts data contained in the \a file before the archive data. You can use this method for example to convert + the archive into a self-extracting archive (store a self-extracting stub inside \a file). + To perform prepending, the archive must be opened and no file must be opened for compression or extraction. This method + will not work with segmented archives or archives, for which #GetBytesBeforeZip method returns value + different from \c 0. + + \param file + The file containing data to insert before the archive data. The file should be opened. + + \param lpszNewExt + If it is not \c NULL, then the extension of the archive is changed to this value after prepending data. + Under linux additionally, this method sets executable permission for the owner after prepeding. If renaming is performed, + then the archive is closed before it. If this value is \c NULL, the no renaming is performed and the archive stays opened + + \return + \c true, if data from \a file was prepended successfully; \c false otherwise. + + \note + - Calls the CZipActionCallback::cbMoveData callback. + - Throws exceptions. + + \see + 0610242241|convert + \see + ShiftData + \see + PrependData(LPCTSTR, LPCTSTR) + */ + bool PrependData(CZipAbstractFile& file, LPCTSTR lpszNewExt = NULL); + + /** + Sets the global comment in the archive. + + \param lpszComment + The comment to set. + + \return + \c false, if the archive is closed or it is an existing segmented archive; + \c true otherwise. + + \note + Throws exceptions. + \see + 0610231944|comment + \see + GetGlobalComment + */ + bool SetGlobalComment(LPCTSTR lpszComment); + + + /** + Gets the global comment for the archive. + + \return + The global comment or an empty string if the archive is closed. + + \see + 0610231944|comment + \see + SetGlobalComment + */ + CZipString GetGlobalComment()const ; + + + /** + Sets the comment for the file with the given index. + + \param uIndex + A zero-based index of the file. + + \param lpszComment + The comment to set. + + \return + \c false, if the comment change is impossible; \c true otherwise. + + \note + Throws exceptions. + + \see + 0610231944|comment + \see + GetFileComment + */ + bool SetFileComment(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszComment); + + /** + Gets the comment for the file with the given index. + + \param uIndex + A zero-based index of the file. + + \return + The file comment or an empty string, if the archive is closed. + + \see + 0610231944|comment + \see + SetFileComment + */ + CZipString GetFileComment(ZIP_INDEX_TYPE uIndex) const + { + const CZipFileHeader* info = GetFileInfo(uIndex); + return info == NULL ? CZipString(_T("")) : info->GetComment(); + } + + /** + Gets the path of the currently opened archive segment. + \return + The current segments' path or an empty string, if the archive is closed. + + \see + 0610051553 + */ + CZipString GetArchivePath()const; + + /** + Gets the archive volume number currently being processed. The first volume has the number 1. + + This method is useful while working with a segmented archive in creation to find out + how many parts were already created. To find out how many parts are in an existing segmented archive, + use the #GetCentralDirInfo method. + + \return + A one-based number of the current volume or 0, if there is no current volume (the archive is closed). + + \see + 0610051553 + */ + ZIP_VOLUME_TYPE GetCurrentVolume() const ; + + /** + Gets the segmentation mode of the current archive. + + \return + One of the following values: + - \c -2 : An existing split archive. + - \c -1 : An existing spanned archive. + - \c 0 : No archive segmentation or one-volume only. + - \c 1 : A spanned archive in creation. + - \c 2 : A split archive in creation. + + \see + 0610051553 + */ + int GetSegmMode()const + { + return m_storage.m_iSegmMode * m_storage.IsSegmented(); + } + + /** + Case-sensitivity values used as the \a iCaseSensitive argument in the FindFile() method. + */ + enum FFCaseSens + { + /** + Uses the default case-sensitivity as set with the #SetCaseSensitivity method. + If the Find Fast array was built before with a different case-sensitivity, + it is rebuilt again, if it hasn't been built so far, it is built now with the + default case-sensitivity. + */ + ffDefault, + + /** + Performs a case-sensitive search. If the CZipArchive is non-case-sensitive, + a less effective search is performed. It does not rebuild the Find Fast array, + but if the array hasn't been built yet, it is built now as \b non-case-sensitive + (you can use \c SetCaseSensitivity(true) and then #ffDefault to build it as case-sensitive). + */ + ffCaseSens, + + /** + Performs a non-case-sensitive search. If the CZipArchive is case-sensitive, + a less effective search is performed. It does not rebuild the Find Fast array, + but if the array hasn't been built yet, it is build now as \b case-sensitive + (you can use \c SetCaseSensitivity(false) and then #ffDefault to build it as non-case-sensitive). + */ + ffNoCaseSens + }; + + /** + Finds a file in the archive. + This method enables the Find Fast feature, if it is not enabled already. + + \param lpszFileName + The name of the file to be found in the archive. If the file in the archive is stored with the + path information, you must specify it here or set \a bFileNameOnly to \c true. + Use the same path separators as they are defined for your system as default + (\e "\" for Windows and \e "/" for Unix/Linux). + + \param iCaseSensitive + It can be one of the #FFCaseSens values. + + \param bFileNameOnly + If \c true, the method tries to find a filename without a path (a less effective search is performed). + If you wish to find a directory name, do not end it with a path separator. + The path separator is required, if you set \a bFileNameOnly to \c false. + + \note + Use the #SetCaseSensitivity method to set the global case-sensitivity. + + \return + The index of the file, if the file was found; \c ZIP_FILE_INDEX_NOT_FOUND if the file was not found. + + \see + 0610242025|findfast + \see + EnableFindFast + */ + ZIP_INDEX_TYPE FindFile(LPCTSTR lpszFileName, int iCaseSensitive = ffDefault, bool bFileNameOnly = false); + + /** + Gets the information about the file with the given index. + The data is copied to \a fhInfo. This may not be + optimal for querying large number of file. To avoid copying data, see the + #GetFileInfo(ZIP_INDEX_TYPE) method. + + \param fhInfo + The object to receive data. + + \param uIndex + A zero-based index of the file to get the information about. + + \return + \c true if successful; \c false otherwise. + \see + 0610242128|file + \see + GetFileInfo(ZIP_INDEX_TYPE) + \see + GetFileInfo(ZIP_INDEX_TYPE) const + \see + operator[](ZIP_INDEX_TYPE) + \see + operator[](ZIP_INDEX_TYPE) const + */ + bool GetFileInfo(CZipFileHeader& fhInfo, ZIP_INDEX_TYPE uIndex) const; + + /** + Gets the information about the file with the given index. + This method provides a direct access to the file data. You should normally not modify + the returned object apart from the reasons given in 0610242128|file. + + \param uIndex + A zero-based index of the file to get the information about. + + \return + A CZipFileHeader object that directly points to a central directory entry in memory; + \c NULL if the archive is closed or there is no such index in the archive. + + \see + 0610242128|file + \see + GetFileInfo(CZipFileHeader&, ZIP_INDEX_TYPE) const + \see + GetFileInfo(ZIP_INDEX_TYPE) const + \see + operator[](ZIP_INDEX_TYPE) + \see + operator[](ZIP_INDEX_TYPE) const + + */ + CZipFileHeader* GetFileInfo(ZIP_INDEX_TYPE uIndex); + + /** + Gets the information about the file with the given index. + This method provides a direct access to the file data. This method does not allow + modification of the returned object. + + \param uIndex + A zero-based index of the file to get the information about. + + \return + A CZipFileHeader object that directly points to a central directory entry in memory; + \c NULL if the archive is closed or there is no such index in the archive. + + \see + 0610242128|file + \see + GetFileInfo(CZipFileHeader&, ZIP_INDEX_TYPE) const + \see + GetFileInfo(ZIP_INDEX_TYPE) + \see + operator[](ZIP_INDEX_TYPE) + \see + operator[](ZIP_INDEX_TYPE) const + + */ + const CZipFileHeader* GetFileInfo(ZIP_INDEX_TYPE uIndex) const; + + /** + Gets the information about the file with the given index. + This method provides a direct access to the file data. You should normally not modify + the returned object apart from the reasons given in 0610242128|file. + + \param uIndex + A zero-based index of the file to get the information about. + + \return + A CZipFileHeader object that directly points to a central directory entry in memory; + \c NULL if the archive is closed or there is no such index in the archive. + + \see + 0610242128|file + \see + GetFileInfo(CZipFileHeader&, ZIP_INDEX_TYPE) const + \see + GetFileInfo(ZIP_INDEX_TYPE) + \see + GetFileInfo(ZIP_INDEX_TYPE) const + \see + operator[](ZIP_INDEX_TYPE) const + + */ + CZipFileHeader* operator[](ZIP_INDEX_TYPE uIndex) + { + return GetFileInfo(uIndex); + } + + /** + Gets the information about the file with the given index. + This method provides a direct access to the file data. This method does not allow + modification of the returned object. + + \param uIndex + A zero-based index of the file to get the information about. + + \return + A CZipFileHeader object that directly points to a central directory entry in memory; + \c NULL if the archive is closed or there is no such index in the archive. + + \see + 0610242128|file + \see + GetFileInfo(CZipFileHeader&, ZIP_INDEX_TYPE) const + \see + GetFileInfo(ZIP_INDEX_TYPE) + \see + GetFileInfo(ZIP_INDEX_TYPE) const + \see + operator[](ZIP_INDEX_TYPE) + */ + const CZipFileHeader* operator[](ZIP_INDEX_TYPE uIndex) const + { + return GetFileInfo(uIndex); + } + + + /** + Gets the number of files in the archive. + + \param bOnlyFiles + If \c true, directories are not included in the total count; otherwise all entries are included. + + \return + The number of files in the archive. + + \see + 0610242128|file + */ + ZIP_INDEX_TYPE GetCount(bool bOnlyFiles) + { + if (IsClosed()) + return 0; + + ZIP_INDEX_TYPE iTotalCount = GetCount(); + if (bOnlyFiles) + { + ZIP_INDEX_TYPE iCount = 0; + for (ZIP_INDEX_TYPE i = 0; i < iTotalCount; i++) + { + if (!m_centralDir[i]->IsDirectory()) + iCount++; + } + return iCount; + } + else + return iTotalCount; + } + + /** + Gets the number of files in the archive. + + \return + The number of files in the archive. + Note that under some compilation configuration this maybe an unsigned value and a signed value under other compilations. + */ + ZIP_INDEX_TYPE GetCount() const + { + return (ZIP_INDEX_TYPE) m_centralDir.GetCount(); + } + + + /** + Calculates the actual size (in bytes) currently occupied by the archive. + + \return + The sum of the sizes: the number of bytes already written to the file, the number of bytes in the write buffer and the whole size of the central directory. + If the archive or a volume is closed, the return value is \c 0. + + \see + 0610242128|archive + */ + ZIP_SIZE_TYPE GetOccupiedSpace() const + { + if (IsClosed(true) || IsClosed(false)) + { + ZIPTRACE("%s(%i) : ZipArchive or the current volume file is closed.\n"); + return 0; + } + return m_storage.GetOccupiedSpace() + m_centralDir.GetSize(true); + } + + /** + The values used in the CZipArchive::Close() method. + */ + enum CloseAfterException + { + /** + Normal closing. Use it, when no exception was thrown while processing the archive. + */ + afNoException, + + /** + Use when an exception was thrown. + The #Close method doesn't write any data but performs necessary cleaning to reuse the + CZipArchive object for another archive processing. + */ + afAfterException, + + /** + Use when an exception was thrown. + The #Close method writes the central directory structure to the archive, + so that the archive should be usable. + */ + afWriteDir + }; + + /** + Closes the archive. + + \param iAfterException + One of the #CloseAfterException values. + + \param bUpdateTimeStamp + If \c true, the method sets the modification date of the zip file to the date of the newest file in the archive. + In a segmented archive, only the last segment file will have the time stamp updated. + You can use this option even without performing any additional processing on the archive, just open and close the archive. + + \note + Throws exceptions. Does not throw any exceptions, if \a iAfterException is set to the #afAfterException value. + + \see + 0610222049 + \see + IsClosed + */ + void Close(int iAfterException = afNoException, bool bUpdateTimeStamp = false); + + + /** + Tests if the whole archive or the current volume is closed. + + \param bArchive
+ If \c true, test for the whole archive. If \c false, test for the current volume only. + + \return + \c true if a file closed; \c false otherwise. + + \see + Close + */ + bool IsClosed(bool bArchive = true)const + { + return m_storage.IsClosed(bArchive); + } + + /** + Writes the central directory to the archive and flushes the internal buffers to the disk. + After that the archive is finalized on the disk, but you can still modify it, if it is not a segmented archive. + + \note + - This method cannot be used on existing segmented archives - they are not modifiable. + - If you have an archive with a huge central directory, it'll influence the performance calling this function without a reason. + - Throws exceptions. + + \see + 0610231446|flush + \see + FlushBuffers + \see + SetAutoFlush + \see + GetAutoFlush + \see + GetSegmMode + */ + void Flush(); + + /** + Writes internal buffers to the storage file and flushes the file buffers to the disk. + + \see + 0610231446|flush + \see + Flush + */ + void FlushBuffers() + { + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive should be opened first.\n"); + return; + } + + m_storage.FlushBuffers(); + } + + + /** + Sets the CZipArchive object to call the Flush() method after each operation that modifies the archive (apart from changing central extra fields). + It is useful when you want to prevent the loss of data in case of the program crash - the zip file will then be finalized on the disk. + Use it after opening the archive. + + \note + - You can set auto-flush only for non-segmented archives. + - If you have an archive with a huge central directory, enabling auto-flush will influence the performance. + + \see + 0610231446|flush + \see + Flush + \see + GetAutoFlush + */ + void SetAutoFlush(bool bAutoFlush = true); + + + /** + Gets the current auto-flush value. + + \return + The current auto-flush value. + + \see + 0610231446|flush + \see + SetAutoFlush + \see + Flush + + */ + bool GetAutoFlush()const {return m_bAutoFlush;} + + /** + Sets the system compatibility of the archive. Use it after opening the archive, + but before adding a new file or using the #SetFileHeaderAttr method. + If the filename code page is standard for the current system compatibility, + the ZipArchive Library will change the filename code page to be default for the + new system compatibility (see 0610051525 for more information). + + \param iSystemComp + The new system compatibility to use. It can be one of the ZipCompatibility::ZipPlatforms values. + \return + \c false, if the value \a iSystemComp is not supported + or it is not possible to set the value at this moment; \c true otherwise. + + \see + 0610231446|compatibility + \see + GetSystemCompatibility + \see + CZipFileHeader::GetSystemCompatibility + \see + ZipCompatibility::ZipPlatforms + \see + ZipPlatform::GetSystemID + */ + bool SetSystemCompatibility(int iSystemComp); + + /** + Gets the system compatibility of the current archive. + \return + One of the ZipCompatibility::ZipPlatforms values. + + \see + 0610231446|compatibility + \see + SetSystemCompatibility + \see + CZipFileHeader::SetSystemCompatibility + \see + ZipCompatibility::ZipPlatforms + \see + ZipPlatform::GetSystemID + */ + int GetSystemCompatibility() const {return m_iArchiveSystCompatib;} + + + + /** + Sets the attributes for the CZipFileHeader object to be used + in the OpenNewFile(CZipFileHeader&, int, LPCTSTR) method. + + This special procedure is required, because the attributes value depends + on the system compatibility of the archive. + + \param header + The object to have the attributes set. + + \param uAttr + The attributes to set. + + \throws CZipException + with the CZipException::platfNotSupp code, if the system compatibility + is not supported by the ZipArchive Library. + + \see + 0610231446|advanced + \see + SetSystemCompatibility + */ + void SetFileHeaderAttr(CZipFileHeader& header, DWORD uAttr)const; + + /** + Gets the underlying archive storage object. + + \return + The pointer to CZipStorage. + + \see + CZipStorage + */ + CZipStorage* GetStorage(){return &m_storage;} + + /** + Sets the current settings that control storing of filenames and comments in the archive. + + \param settings + The settings to set. + + \see + 0610051525 + \see + SetStringStoreSettings(UINT, bool, UINT) + \see + SetStringStoreSettings(UINT, bool) + \see + ResetStringStoreSettings + \see + GetStringStoreSettings + */ + void SetStringStoreSettings(const CZipStringStoreSettings& settings) + { + m_stringSettings = settings; + } + + /** + Sets the current settings that control storing of filenames and comments in the archive. + + \param uFileNameCodePage + The code page for filenames. + + \param bStoreNameInExtraData + If \c true, the encoded filenames are stored in central extra fields. + + \param uCommentCodePage + The code page for comments. + + \see + 0610051525 + \see + SetStringStoreSettings(const CZipStringStoreSettings&) + \see + SetStringStoreSettings(UINT, bool) + \see + ResetStringStoreSettings + \see + GetStringStoreSettings + */ + void SetStringStoreSettings(UINT uFileNameCodePage, bool bStoreNameInExtraData, UINT uCommentCodePage) + { + m_stringSettings.Set(uFileNameCodePage, bStoreNameInExtraData, uCommentCodePage); + } + + /** + Sets the current settings that control storing of filenames and comments in the archive. + The code page for comments stays the same when calling this method. + + \param uFileNameCodePage + The code page for filenames. + + \param bStoreNameInExtraData + If \c true, the encoded filenames are stored in central extra fields. + + \see + 0610051525 + \see + SetStringStoreSettings(const CZipStringStoreSettings&) + \see + SetStringStoreSettings(UINT, bool, UINT) + \see + ResetStringStoreSettings + \see + GetStringStoreSettings + */ + void SetStringStoreSettings(UINT uFileNameCodePage, bool bStoreNameInExtraData = false) + { + SetStringStoreSettings(uFileNameCodePage, bStoreNameInExtraData, m_stringSettings.m_uCommentCodePage); + } + + /** + Sets the current settings that control storing of filenames and comments in the archive to their default values considering the + current system compatibility of the archive (see GetSystemCompatibility()). + + \see + 0610051525 + \see + SetStringStoreSettings(const CZipStringStoreSettings&) + \see + SetStringStoreSettings(UINT, bool, UINT) + \see + SetStringStoreSettings(UINT, bool) + \see + GetStringStoreSettings + */ + void ResetStringStoreSettings() + { + m_stringSettings.Reset(m_iArchiveSystCompatib); + } + + /** + Gets the current settings that control storing of filenames and comments in the archive. + + \return + The current string store settings. + + \see + 0610051525 + \see + SetStringStoreSettings(const CZipStringStoreSettings&) + \see + SetStringStoreSettings(UINT, bool, UINT) + \see + SetStringStoreSettings(UINT, bool) + \see + ResetStringStoreSettings + \see + CZipFileHeader::GetStringStoreSettings + */ + CZipStringStoreSettings& GetStringStoreSettings() + { + return m_stringSettings; + } + + /** + Enables or disables fast searching for files inside the archive using filenames. + + \see + 0610242025|findfast + \see + FindFile + \see + GetIndexes + \see + GetFindFastIndex + */ + void EnableFindFast(bool bEnable = true); + + + /** + Allows to retrieve the order of sorted files after you enabled the Find Fast feature with the EnableFindFast() method. + + \param iFindFastIndex + The index of the file in the sorted array. + + \return + The index of the file in the central directory. You can use the return value + in other methods that require the file index (such as #GetFileInfo). + This method returns \c -1, if you have not called + #EnableFindFast before or the archive is closed or the \a iFindFastIndex + is out of range. + + \see + 0610242025|findfast + \see + EnableFindFast + */ + ZIP_INDEX_TYPE GetFindFastIndex(ZIP_INDEX_TYPE iFindFastIndex) const + { + if (IsClosed()) + { + ZIPTRACE("CZipArchive::GetFindFastIndex: ZipArchive should be opened first.\n"); + return ZIP_FILE_INDEX_UNSPECIFIED; + } + + return m_centralDir.GetFindFastIndex(iFindFastIndex); + } + + + /** + Sets the temporary path used when compressing files and there is a need for a temporary archive. + Temporary files are used when replacing or when compressing a segmented archive with the #zipsmCheckForEff flag. + If the path is not set or it does not exists or there is not enough free space in it, + then the ZipArchive Library first tries the the following folders + in the given order for sufficient free space: + \li system default temporary directory, + \li the current directory. + + If all above fails, no temporary file is created and the compression goes the usual way. + + \param lpszPath + The path used for storing temporary files. Set it to \c NULL, to clear the temporary path and let the + ZipArchive Library figure it out (see above). + + \param bForce + If \a lpszPath is not \c NULL and this parameter set to \c true + the directory is created, if it doesn't exist. Otherwise the the ZipArchive Library + tries to figure out the location for temporary files by itself (see above). + + \see + GetTempPath + \see + AddNewFile + \see + Smartness + */ + void SetTempPath(LPCTSTR lpszPath = NULL, bool bForce = true); + + /** + Gets the current temporary path used when compressing files. + + \return + The current temporary path. + + \see + SetTempPath + */ + CZipString GetTempPath()const + { + return m_szTempPath; + } + + /** + The values used in the PredictFileNameInZip() method. + */ + enum Predict + { + + prDir, ///< If \a lpszFilePath is a directory, appends a separator. + prFile, ///< Treats \a lpszFilePath as a common file. + prAuto ///< Treats \a lpszFilePath as a directory only if it has a path separator appended. + }; + + /** + Predicts the filename as it would be stored in the archive, when given parameters would be used with + one of the AddNewFile() methods. The method takes into account the root path set with the #SetRootPath method. + You can use this method to eliminate duplicates before adding a list of files. + + \param lpszFilePath + The file path, the same as CZipAddNewFileInfo::m_szFilePath. + \param bFullPath + The same as CZipAddNewFileInfo::m_bFullPath. + \param iWhat + One of the #Predict values to interpret \a lpszFilePath correctly. + \return + The filename as it would be stored in the archive. + */ + CZipString PredictFileNameInZip(LPCTSTR lpszFilePath, bool bFullPath, int iWhat = prAuto)const ; + + /** + Calculates the maximum number of bytes that the file represented by #CZipFileHeader would occupy in the current archive. + + You need to set the following members in the structure: + \li File attributes (use the #SetFileHeaderAttr method). It is for determining whether the file is a directory or not. + You can use ZipPlatform::GetFileAttr. + \li The filename as it would appear in the archive (use CZipFileHeader::SetFileName). You can use #PredictFileNameInZip. + \li The compressed size of the file (use CZipFileHeader::m_uLocalComprSize). You can use an uncompressed file size + here for the maximum value estimate. + + Additionally you may set: + - A file comment (use the CZipFileHeader::SetComment method). + - Extra fields (use CZipFileHeader::m_aLocalExtraData and CZipFileHeader::m_aCentralExtraData). + + \param fh + A template object pre-filled with data. + + \return + The maximum number of bytes the file would occupy in the archive. + + \note + - The method takes into account if the current archive is a segmented archive. + - If the archive has a password set, the method will assume that the file would be stored encrypted in the archive (extra bytes may be added then depending on the encryption method). + - The method calls CZipFileHeader::PrepareData + - Zip64 only: The method takes into account the current file pointer position in the archive to determine the need for the Zip64 extensions + and updates CZipFileHeader::m_uVolumeStart and CZipFileHeader::m_uOffset. + - The method does not take into account a situation when a file would be compressed, but mostly stored blocks would be emitted by the Huffman compression engine. + In this case extra 5 bytes are added per a single stored block. You should remove the file and store it instead when it happens (see #zipsmCheckForEff). + + \see + PredictMaximumFileSizeInArchive(LPCTSTR, bool) const + */ + ZIP_SIZE_TYPE PredictMaximumFileSizeInArchive(CZipFileHeader& fh) const; + + /** + Calls the PredictMaximumFileSizeInArchive(CZipFileHeader&) const method. + Before calling, fills the #CZipFileHeader structure with the filename as it + would appear in the archive and sets the proper file size (unless \a lpszFilePath is a directory). + + \param lpszFilePath + A path to the file for which you want to predict the maximum size it would occupy. + + \param bFullPath + The same as CZipAddNewFileInfo::m_bFullPath. + + \return + The maximum number of bytes the file would occupy in the archive. + + \see + PredictMaximumFileSizeInArchive(CZipFileHeader&) const + */ + ZIP_SIZE_TYPE PredictMaximumFileSizeInArchive(LPCTSTR lpszFilePath, bool bFullPath) const; + + + /** + Checks if the filename of the given file will be duplicated in the archive, if added to the archive with the given parameters. + + \param lpszFilePath + The file path. You normally use it in one of the #AddNewFile methods. + + \param bFullPath + The same as CZipAddNewFileInfo::m_bFullPath. + + \param bFileNameOnly + If \c true, the method assumes that the filename is duplicated if only the name part (no path) + is the same (\a bFullPath is ignored), otherwise the whole filename with a path is taken into account. + + \param iWhat + One of the #Predict values to interpret \a lpszFilePath correctly. + + \return + The zero-based index of the file in the archive which filename would be duplicated, + or \c ZIP_FILE_INDEX_NOT_FOUND, if the filename would be unique. + */ + ZIP_INDEX_TYPE WillBeDuplicated(LPCTSTR lpszFilePath, bool bFullPath, bool bFileNameOnly = false, int iWhat = prAuto); + + /** + Predicts the full resulting filename with path after extraction. + The parameters (except for the first) are in the form you'd pass + to the #ExtractFile(ZIP_INDEX_TYPE , LPCTSTR , bool , LPCTSTR , CZipCompressor::COffsetsPair*, DWORD ) method. + The method takes into account the root path set with the #SetRootPath method. + + \param lpszFileNameInZip + The filename of the file inside the archive (may be \c NULL if \a lpszNewName is not \c NULL). + + \param lpszPath + + \param bFullPath + + \param lpszNewName + + \return + The predicted resulting file path. + */ + CZipString PredictExtractedFileName(LPCTSTR lpszFileNameInZip, LPCTSTR lpszPath, bool bFullPath, LPCTSTR lpszNewName = NULL)const ; + + +/** + Removes the root path from \a zpc. + + \param zpc + The path to have the common beginning removed from. + + \see + SetRootPath +*/ + CZipString TrimRootPath(CZipPathComponent& zpc) const ; + + /** + Removes \a lpszBeginning from the beginning of \a szPath. Both argument are + considered to be paths - they must match up to the path separator. + + \param lpszBeginning + The beginning to remove. + + \param szPath + The path to have the beginning removed. + + \param pCompareFunction + The compare function used (see #m_pZipCompare). + + \return + \c true, if the path beginning was removed; \c false otherwise. + */ + static bool RemovePathBeginning(LPCTSTR lpszBeginning, CZipString& szPath, ZIPSTRINGCOMPARE pCompareFunction); + + /** + Sets the default archive case-sensitivity. The default CZipArchive case-sensitivity depends + on the system and is set as follows: + \li on Windows: \c false + \li on Linux: \c true + + Calling this method affects the following methods: + + - #FindFile + - #GetIndexes + - #FindMatches + - #EnableFindFast + - #TrimRootPath + - #RemoveFiles(const CZipStringArray&) + + \param bCaseSensitive + The case-sensitivity to be used. + + \note + Set it before using one of the mentioned methods or leave it as it was set by default. + */ + void SetCaseSensitivity(bool bCaseSensitive) + { + m_bCaseSensitive = bCaseSensitive; + m_pZipCompare = GetCZipStrCompFunc(bCaseSensitive); + } + + /* + Gets the current case sensitivity. + + \return + \c true, if the archive is case-sensitive; \c false otherwise. + + \see + SetCaseSensitivity + */ + bool GetCaseSensitivity() const + { + return m_bCaseSensitive; + } + + /** + Gets the central directory information. + \param info + The object to retrieve information data. + + \see + GetCentralDirSize + */ + void GetCentralDirInfo(CZipCentralDir::CInfo& info)const; + + + /** + Gets the central directory size. + + \param bWhole + If \c true, the return value includes the size of file headers. + + \return + The size of the central directory. + + \see + GetCentralDirInfo + */ + ZIP_SIZE_TYPE GetCentralDirSize(bool bWhole = true) const + { + if (IsClosed()) + { + ZIPTRACE("%s(%i) : ZipArchive is closed.\n"); + return 0; + } + return m_centralDir.GetSize(bWhole); + } + + /** + Gets a value indicating whether the archive can be modified or not. + An archive can be read-only when it is an existing segmented archive + or it was opened with the #zipOpenReadOnly flag. + + \return + \c true if the archive is read-only; \c false otherwise. + */ + bool IsReadOnly(){return m_storage.IsReadOnly();} const + + /** + Sets the number of non-archive bytes that are present before the actual archive in the archive file. + The library usually tries to automatically calculate this value, but this may not be possible + under some conditions. + + \param uCount + The number of bytes before the actual archive. + + \see + GetBytesBeforeZip + */ + void SetBytesBeforeZip(ZIP_SIZE_TYPE uCount = 0) + { + if (!IsClosed()) + { + ZIPTRACE("%s(%i) : Set it before opening the archive.\n"); + return; + } + m_storage.m_uBytesBeforeZip = uCount; + } + + /** + Gets the number of non-archive bytes that are present before the actual archive in the archive file. + + \return + The number of bytes before the actual archive. + \see + SetBytesBeforeZip + */ + ZIP_SIZE_TYPE GetBytesBeforeZip() const + { + return m_storage.m_uBytesBeforeZip; + } + + /** + Values describing various archive consistency checks that the library performs. + Instruct the library to skip selected checks using the #SetIgnoredConsistencyChecks method. + */ + enum ConsistencyCheck + { + checkNone, ///< If used in the the #SetIgnoredConsistencyChecks method, checks for all inconsistencies in an archive. + checkCRC = 0x0001, ///< Check CRC after decompression. Use it when working with Java TM Archives (jar). The CRC check is performed using CRC written in a central header when closing a file after extraction. + checkLocalMethod = 0x0002, ///< Check if the compression method written in a local header matches the compression method written in a central header. + checkLocalSizes = 0x0004, ///< Check if sizes of compressed and uncompressed data written in a local header match their counterparts in a central header. The compressed size in the local header is always ignored, if it is 0. + checkLocalCRC = 0x0008, ///< Check if the CRC written in a local header matches the CRC written in a central header. + checkLocalFlag = 0x0010, ///< Check if the general purpose flag value written in a local header matches its counterpart written in a central header. + checkLocalAll = checkLocalMethod | checkLocalSizes | checkLocalCRC | checkLocalFlag, ///< Check for inconsistencies between central and local headers at all. These checks are performed when opening a file for extraction. + checkDataDescriptor = 0x0100, ///< Check if values written in extra data descriptor match values written in central header. This check is performed when closing a file after extraction, only if a file has a data descriptor (see CZipFileHeader::IsDataDescriptor()). Ignored by default (it is consistent with behavior of popular archivers). + checkAll = checkCRC | checkLocalAll | checkDataDescriptor, ///< Logical sum of all possible checks. + checkIgnoredByDefault = checkDataDescriptor, ///< Checks that are ignored by default by the ZipArchive Library + }; + + /** + Set the consistency checks to ignore while processing an archive. Allows opening archives which are not entirely + consistent, but nevertheless the compressed data is correct. The level is reset to #checkIgnoredByDefault when + opening or creating an archive. + \param iLevel + The consistency check. Can be one or more (OR-ed together) of #ConsistencyCheck values. + + \see + ConsistencyCheck + \see + GetIgnoredConsistencyChecks + */ + void SetIgnoredConsistencyChecks(int iLevel = checkIgnoredByDefault) + { + if (IsClosed()) + { + ZIPTRACE("%s(%i) : Set it after opening the archive.\n"); + return; + } + m_centralDir.m_iIgnoredChecks = iLevel; + } + + /** + Return the currently ignored consitency checks. Can be one or more of #ConsistencyCheck values. + + \see + SetIgnoredConsistencyChecks + */ + int GetIgnoredConsistencyChecks() const + { + return m_centralDir.m_iIgnoredChecks; + } + + /** + Forces reading all headers from the central directory, even if the number of files reported by the archive is different. + By default, the ZipArchive Library reads only the number of headers declared by the archive. Call this method before opening an archive. + + \note This method is useful when dealing with archives created with + external software that put more files inside an archive that it is permitted by the zip format. Such a situation + can take place with archives created with e.g. BOMArchiveHelper (Mac OS X utility), when the number of files exceeds 65,535. + + \see + GetExhaustiveRead + */ + void SetExhaustiveRead(bool bExhaustiveRead) + { + if (!IsClosed()) + { + ZIPTRACE("%s(%i) : Set it before opening the archive.\n"); + return; + } + m_bExhaustiveRead = bExhaustiveRead; + } + + /** + Returns the value indicating whether the exhaustive read function is active or not. + + \return + \c true, if the exhaustive read function is active; \c false otherwise. + + \see + SetExhaustiveRead + */ + bool GetExhaustiveRead() const + { + return m_bExhaustiveRead; + } + + /** + Finds indexes of the files, which filenames match the specified pattern. The indexes are stored in the \a ar array. + The indexes can be used then e.g. in deleting or extracting files. + + \param lpszPattern + The pattern to match. The case-sensitivity of the pattern + is set to the global archive case-sensitivity (set with the #SetCaseSensitivity method). + + \param ar + The array which will contain the resulting indexes. The contents of \a ar are not cleared, but the + indexes are appended to it. + + \param bFullPath + \li If \c true, the method matches the filename with path (if present) of the file. + If the file is a directory, end it with a path separator or use a pattern that will recognize it. + \li If \c false, the method matches only the name of the file. If the file is a directory, + do not end it with a path separator. + + \see + 0610242025|match + \see + SetCaseSensitivity + \see + ZipArchiveLib::CWildcard + + */ + void FindMatches(LPCTSTR lpszPattern, CZipIndexesArray& ar, bool bFullPath = true); + + + /** + Renames the file with the given index in the archive. + + \param uIndex + A zero-based index of the file to rename. + + \param lpszNewName + The new name for the file. + + \return + \c true, if the file was renamed; \c false otherwise. + + \note + Throws exceptions. + \see + 0610231944|rename + */ + bool RenameFile(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewName); + + /** + Removes the central directory from the archive. + You may then modify central extra fields and write the central directory back to the archive afterwards (use the #Close method). + + \return + \c true, if the central directory was successfully removed; \c false otherwise. + + \see + 0610242300|central + */ + bool RemoveCentralDirectoryFromArchive(); + + /** + Reads the local header information of the file with the given index. + + \param uIndex + The index of the file for which to update the local information. + + \return + \c true, if the information was successfully updated; \c false otherwise. + + \note + Throws exceptions. + + \see + 0610231944|time + \see + OverwriteLocalHeader + */ + bool ReadLocalHeader(ZIP_INDEX_TYPE uIndex); + + /** + Writes the local header information of the file with the given index back to the archive. + + \param uIndex + The index of the file for which to write the local information. + + \return + \c true, if the information was successfully written; \c false otherwise. + + \note + Throws exceptions. + + \see + 0610231944|time + \see + ReadLocalHeader + */ + bool OverwriteLocalHeader(ZIP_INDEX_TYPE uIndex); + + /** + Retrieves the current compressor. The type of the compressor depends on the compression method + used for compressing or decompressing data. + + \see + SetCompressionMethod + */ + const CZipCompressor* GetCurrentCompressor() const + { + return m_pCompressor; + } + + /** + If \c true, the drive letter is removed from the filename stored inside the archive when adding + a new file to the archive or extracting an existing one. + It affects #AddNewFile, #ExtractFile, #PredictFileNameInZip, #PredictExtractedFileName, + #WillBeDuplicated methods. The default value is \c true. + */ + bool m_bRemoveDriveLetter; + +protected: + + /** + Reads the local header information of the file with the given index. + + \param uIndex + The index of the file for which to update the local information. + + \note + Throws exceptions. + */ + void ReadLocalHeaderInternal(ZIP_INDEX_TYPE uIndex) + { + // update sizes of local filename and extra field - they may differ from the ones in the central directory + m_centralDir.OpenFile(uIndex); + // skip checking the data descriptor, we are not there yet + m_centralDir.CloseFile(true); + } + + /** + See the description of #EncryptFiles. + + \param pIndexes + + \return + \c false, if the files could not be encrypted; \c true otherwise. + + \note + Throws exceptions. + + \see + EncryptFiles + */ + bool EncryptFilesInternal(CZipIndexesArray* pIndexes); + + + /** + The value set with #SetExhaustiveRead. + */ + bool m_bExhaustiveRead; + + /** + See the description of #OpenNewFile(CZipFileHeader&, int, LPCTSTR) + + \param header + \param iLevel + \param lpszFilePath + \param uReplaceIndex + For internal use only. + \see + OpenNewFile(CZipFileHeader&, int, LPCTSTR) + */ + bool OpenNewFile(CZipFileHeader & header, int iLevel, LPCTSTR lpszFilePath, ZIP_INDEX_TYPE uReplaceIndex); + + /** + See CZipCallbackProvider. + */ + ZipArchiveLib::CZipCallbackProvider m_callbacks; + + + /** + Writes the central directory notifying a callback object if available. + */ + void WriteCentralDirectory(bool bFlush = true); + + /** + The value set with #SetCaseSensitivity. + */ + bool m_bCaseSensitive; + + + /** + A pointer to a method used to compare strings. + Can point to \c Compare, \c CompareNoCase, \c Collate or \c CollateNoCase method. + */ + ZIPSTRINGCOMPARE m_pZipCompare; + + + /** + Physical layer of the archive. + \see + CZipStorage + */ + CZipStorage m_storage; + + /** + A central directory object. + \see + CZipCentralDir + */ + CZipCentralDir m_centralDir; + + /** + The open mode of the current file inside archive. + */ + enum OpenFileType + { + extract = -1, ///< A file is opened for extraction. + nothing, ///< There is no file inside the archive opened. + compress ///< A new file is opened for compression. + }; + + /** + Takes one of the CZipArchive::OpenFileType enum values. + */ + int m_iFileOpened; + + /** + The value set with SetAutoFlush(). + */ + bool m_bAutoFlush; + + /** + The value set with SetRootPath(). + */ + CZipString m_szRootPath; + + /** + The value set with SetTempPath(). + */ + CZipString m_szTempPath; + + + /** + Opens the archive in the given mode. + Called by #Open(LPCTSTR, int, ZIP_SIZE_TYPE) and #Open(CZipAbstractFile&, int). + \param iMode + The mode. + \note + Throws exceptions. + */ + void OpenInternal(int iMode); + + /** + Initializes the archive during opening. + + \param iArchiveSystCompatib + The system's compatibility of the archive. + + \param pSource + If not \c NULL, then it specifies the central directory for sharing. + + \note + Throws exceptions. + */ + void InitOnOpen(int iArchiveSystCompatib, CZipCentralDir* pSource = NULL); + + /** + The value set with #SetSystemCompatibility. + */ + int m_iArchiveSystCompatib; + + /** + The value set with #SetPassword. + */ + CZipAutoBuffer m_pszPassword; + + /** + Gets the file currently opened for compression or decompression. + \return + The currently opened file or \c NULL, if there is no file opened. + */ + CZipFileHeader* CurrentFile(); + + /** + Releases the current cryptograph. + */ + void ClearCryptograph() + { + if (m_pCryptograph) + { + delete m_pCryptograph; + m_pCryptograph = NULL; + } + } + + /** + Creates a new cryptograph. You can override this method and implement your own cryptograph. + + \param iEncryptionMethod + The requested encryption method. + + \see + CZipCryptograph::EncryptionMethod + */ + virtual void CreateCryptograph(int iEncryptionMethod) + { + if (m_pCryptograph != NULL) + if (m_pCryptograph->CanHandle(iEncryptionMethod)) + return; + + ClearCryptograph(); + m_pCryptograph = CZipCryptograph::CreateCryptograph(iEncryptionMethod); + } + + /** + The current cryptograph. + */ + CZipCryptograph* m_pCryptograph; + + /** + Releases the current compressor. + */ + void ClearCompressor() + { + if (m_pCompressor) + { + delete m_pCompressor; + m_pCompressor = NULL; + } + } + + /** + Creates a new compressor. You can override this method and implement your own compressor. + + \param uMethod + The requested data compression method. + + \see + CZipCompressor::CompressionMethod + */ + virtual void CreateCompressor(WORD uMethod) + { + if (m_pCompressor == NULL || !m_pCompressor->CanProcess(uMethod)) + { + ClearCompressor(); + m_pCompressor = CZipCompressor::CreateCompressor(uMethod, &m_storage); + } + m_pCompressor->UpdateOptions(m_compressorsOptions); + } + + /** + The current compressor. + */ + CZipCompressor* m_pCompressor; + + /** + The value set with #SetEncryptionMethod. + */ + int m_iEncryptionMethod; + + /** + The value set with #SetCompressionMethod. + */ + WORD m_uCompressionMethod; + + + /** + A helper buffer used during various IO operations. + + \see + m_iBufferSize + \see + SetAdvanced + */ + CZipAutoBuffer m_pBuffer; + + /** + The size of the #m_pBuffer buffer. Set it before opening the archive. + It is usually set with the #SetAdvanced method + (specify this value as the second argument). + + \see + SetAdvanced + */ + DWORD m_iBufferSize; + + /** + The value set with the SetStringStoreSettings() method. + */ + CZipStringStoreSettings m_stringSettings; + +private: + CZipCompressor::COptionsMap m_compressorsOptions; + void Initialize(); + void MakeSpaceForReplace(ZIP_INDEX_TYPE iReplaceIndex, ZIP_SIZE_TYPE uTotal, LPCTSTR lpszFileName); + + void MovePackedFiles(ZIP_SIZE_TYPE uStartOffset, ZIP_SIZE_TYPE uEndOffset, ZIP_SIZE_TYPE uMoveBy, CZipActionCallback* pCallback, bool bForward = false, bool bLastCall = true); + + bool RemoveLast(bool bRemoveAnyway = false); + + bool GetFromArchive(CZipArchive& zip, ZIP_INDEX_TYPE uIndex, LPCTSTR lpszNewFileName, ZIP_INDEX_TYPE iReplaceIndex, bool bKeepSystComp, CZipActionCallback* pCallback); + + bool UpdateReplaceIndex(ZIP_INDEX_TYPE& iReplaceIndex); + + void ThrowError(int err); + + void InitBuffer() + { + m_pBuffer.Allocate(m_iBufferSize); + } + void ReleaseBuffer() + { + m_pBuffer.Release(); + } +}; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + +#endif // !defined(ZIPARCHIVE_ZIPARCHIVE_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipAutoBuffer.cpp b/harbour/contrib/hbziparch/ZipAutoBuffer.cpp new file mode 100644 index 0000000000..8925212269 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipAutoBuffer.cpp @@ -0,0 +1,95 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipAutoBuffer.h" +#include + +CZipAutoBuffer::CZipAutoBuffer() +{ + m_iSize = 0; + m_pBuffer = NULL; +} + +CZipAutoBuffer::CZipAutoBuffer(DWORD iSize, bool bZeroMemory) +{ + m_iSize = 0; + m_pBuffer = NULL; + Allocate(iSize, bZeroMemory); +} + +CZipAutoBuffer::~CZipAutoBuffer() +{ + Release(); +} + + +void CZipAutoBuffer::Release() +{ + if (m_pBuffer) + { + delete [] m_pBuffer; + m_iSize = 0; + m_pBuffer = NULL; + } +} + +char* CZipAutoBuffer::Allocate(DWORD iSize, bool bZeroMemory) +{ + if (iSize != m_iSize) + Release(); + else + { + if (bZeroMemory) + memset(m_pBuffer, 0, iSize); // zerowanie bufora + return m_pBuffer; + } + + if (iSize > 0) + { + m_pBuffer = new char [iSize]; + if (bZeroMemory) + memset(m_pBuffer, 0, iSize); // zerowanie bufora + m_iSize = iSize; + } + else + m_pBuffer = NULL; + + return m_pBuffer; +} + + +CZipAutoBuffer::CZipAutoBuffer(const CZipAutoBuffer& buffer) +{ + m_pBuffer = NULL; + m_iSize = 0; + + if (buffer.m_pBuffer) + { + Allocate(buffer.m_iSize); + memcpy(m_pBuffer, buffer.m_pBuffer, buffer.m_iSize); + } +} +CZipAutoBuffer& CZipAutoBuffer::operator=(const CZipAutoBuffer& buffer) +{ + if (this == &buffer) + return *this; + Release(); + if (buffer.m_pBuffer) + { + Allocate(buffer.m_iSize); + memcpy(m_pBuffer, buffer.m_pBuffer, buffer.m_iSize); + } + return *this; +} diff --git a/harbour/contrib/hbziparch/ZipAutoBuffer.h b/harbour/contrib/hbziparch/ZipAutoBuffer.h new file mode 100644 index 0000000000..678ad391a4 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipAutoBuffer.h @@ -0,0 +1,67 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipAutoBuffer.h +* Includes the CZipAutoBuffer class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPAUTOBUFFER_DOT_H) +#define ZIPARCHIVE_ZIPAUTOBUFFER_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "ZipExport.h" +/** + A smart buffer freeing its contents on destruction. +*/ +class ZIP_API CZipAutoBuffer +{ +public: + operator char*() + { + return m_pBuffer; + } +#if !defined (__BORLANDC__) || (__BORLANDC__ > 0x560) // The actual version may be different. + operator const char*() const + { + return m_pBuffer; + } +#endif + const char* GetBuffer() const {return m_pBuffer;} + char* Allocate(DWORD iSize, bool bZeroMemory = false); + void Release(); + DWORD GetSize() const + { + return m_iSize; + } + bool IsAllocated() const + { + return (m_pBuffer != NULL); + } + CZipAutoBuffer(DWORD iSize, bool bZeroMemory = false); + CZipAutoBuffer(); + CZipAutoBuffer(const CZipAutoBuffer& buffer); + virtual ~CZipAutoBuffer(); + CZipAutoBuffer& operator=(const CZipAutoBuffer& buffer); +protected: + char* m_pBuffer; + DWORD m_iSize; +}; + +#endif // !defined(ZIPARCHIVE_ZIPAUTOBUFFER_DOT_H) + diff --git a/harbour/contrib/hbziparch/ZipBaseException.h b/harbour/contrib/hbziparch/ZipBaseException.h new file mode 100644 index 0000000000..44d97a52b0 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipBaseException.h @@ -0,0 +1,30 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipBaseException.h +* Contains a type definition of the base exception class. +* +*/ + +#ifndef ZIPARCHIVE_ZIPBASEEXCEPTION_DOT_H +#define ZIPARCHIVE_ZIPBASEEXCEPTION_DOT_H + + #ifdef ZIP_ARCHIVE_STL + typedef std::exception CZipBaseException; + #else + typedef CException CZipBaseException; +#endif + +#endif //ZIPARCHIVE_ZIPBASEEXCEPTION_DOT_H diff --git a/harbour/contrib/hbziparch/ZipCallback.h b/harbour/contrib/hbziparch/ZipCallback.h new file mode 100644 index 0000000000..36fccbc41e --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCallback.h @@ -0,0 +1,730 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipCallback.h +* Includes the CZipCallback and the derived classes. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPCALLBACK_DOT_H) +#define ZIPARCHIVE_ZIPCALLBACK_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #if defined ZIP_HAS_DLL + #pragma warning (push) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class + #endif +#endif + +#include "ZipString.h" +#include "ZipExport.h" + +/* + When processing split archives, this value is passes as the argument to the CZipCallback::Callback method + to notify that the current volume is the last one. +*/ +#define ZIP_SPLIT_LAST_VOLUME (ZIP_SIZE_TYPE)(-1) + +/** + A base class for callback objects that are notified when various actions take place. + You need to derive your own class and overload the #Callback method to use it. + Do not derive from CZipCallback directly but derive from: + \li CZipSegmCallback, when you create a segmented archive - you will be notified + when there the next volume is processed in a segmented archive. + \li CZipActionCallback, for other notifications. + + \see + 0610051553|span + \see + 0610231200 + \see + CZipSegmCallback + \see + CZipActionCallback +*/ +struct ZIP_API CZipCallback +{ + /** + The method called as a callback. + + Return \c false from inside the method to abort the current operation. If it is a segmented archive callback object, + a CZipException with CZipException::aborted code will be thrown, otherwise the code will be CZipException::abortedAction or CZipException::abortedSafely. + The following actions can be safely aborted (without corrupting the archive): + - counting bytes before deleting files + - testing + - saving the central directory in a not segmented archive + (saved data is removed in case of break and you can save it again). + + If the archive is segmented and if saving is aborted, the archive + will not be damaged, but saved part of the central directory will be not removed + and the new central directory will have to be saved after it. + + \param uProgress + The value depends on the type of the operation. + + \return + \c false to abort the current operation; \c true to continue it. + + \note + Override this method in the derived class. If you define this method inside the class declaration, consider inlining + it to make the action progress faster. + + \see + CZipSegmCallback + */ + virtual bool Callback(ZIP_SIZE_TYPE uProgress) = 0; + + + /** + Stored the filename of an external file, if the action (adding, extracting or segmentation) uses such a file. + */ + CZipString m_szExternalFile; + virtual ~CZipCallback(){} +}; + +/** + When you derive from CZipSegmCallback, you can use the derived class as a callback object for: + - the disk change notification in a spanned archive, + - notification about the next part being processed in a split archive. + + You need to override the CZipActionCallback::Callback method. + The value of the \a uProgress parameter in the callback method has the following meaning: + - the minimum number of free bytes required on the disk when writing a spanned archive + - it is set to \c 0 when reading a spanned archive + - when writing or reading a split archive it is set to \c 0 apart for the last volume when it is set to \c ZIP_SPLIT_LAST_VOLUME + + Return \c false from the callback function to abort the operation: the proper exception will be thrown. + + \see + 0610051553|span + \see + CZipActionCallback::Callback + \see + CZipArchive::SetSegmCallback +*/ +struct ZIP_API CZipSegmCallback : public CZipCallback +{ + /** + Values indicating the reason for calling the callback. + */ + enum SegmCodes + { + scVolumeNeededForRead, ///< The next volume is needed when reading a segmented archive. The number of the volume is stored in #m_uVolumeNeeded. + scVolumeNeededForWrite, ///< The next volume is needed when writing a segmented archive. The number of the volume is stored in #m_uVolumeNeeded. + scFileNameDuplicated, ///< The file used for writing a new volume already exists. + scCannotSetVolLabel, ///< The disk label could not be set. The disk may be write-protected. Called only for spanned archives. + scFileCreationFailure, ///< The archive file could not be created. The disk may be write-protected. + scFileNotFound, ///< The given volume file was not found when reading a split archive. The number of the volume is stored in #m_uVolumeNeeded. Called only for split archives. + }; + + ZIP_VOLUME_TYPE m_uVolumeNeeded; ///< The number of the volume needed when reading or writing a segmented archive. Volumes are numbered starting from 1. + + int m_iCode; ///< The reason for calling the callback. Can be one of the #SegmCodes values. +}; + +/** + When you derive from CZipActionCallback, you can use the new class as a callback object when adding, extracting, deleting, testing files + or saving the central directory. + You need to override the CZipActionCallback::Callback method. + The value of the \a uProgress parameter in the callback method is the amount of data just processed. + + \see + 0610231200 + \see + CZipActionCallback::Callback + \see + CZipArchive::SetCallback +*/ +struct ZIP_API CZipActionCallback : public CZipCallback +{ + friend class CZipArchive; + friend class CZipCentralDir; + + /** + Values used for specifying a callback type in the CZipArchive::SetCallback method. + You can assign several values to the same callback object (use the logical \c OR). + \see + 0610231200 + \see + CZipArchive::SetCallback + \see + CZipActionCallback + */ + enum CallbackType + { + /** + Not used. + You can use it for your own purposes. + */ + cbNothing = 0x0000, + + /** + Compressing a file. + The callback called when adding a file with one of the CZipArchive::AddNewFile methods. + */ + cbAdd = 0x0001, + + /** + Moving a file from a temporary archive. + The callback called while adding a file (only on a segmented archive) when the smartness level contains + CZipArchive::zipsmCheckForEff or CZipArchive::zipsmCheckForEffInMem + and if the just compressed file is being moved from a temporary place (file or memory) to the archive. + */ + cbAddTmp = 0x0002, + + /** + Storing a file. + The callback called while adding a file and if its compressing has proven to be inefficient + and it is now being stored (instead of compressed) in the archive. The smartness level must + contain CZipArchive::zipsmCheckForEff or CZipArchive::zipsmCheckForEffInMem. The archive can be + segmented or not. + */ + cbAddStore = 0x0004, + + /** + Extracting a file. + The callback called when extracting a file with one of the CZipArchive::ExtractFile methods. + */ + cbExtract = 0x0008, + + /** + Counting data to process before deleting. + The callback called before the actual deletion takes place and the map of holes and continuous + areas is being created. It is safe to abort the operation (by returning \c false from + the callback method). + */ + cbDeleteCnt = 0x0010, + + /** + Deleting files. + The callback called when moving data while deleting file(s) with the CZipArchive::RemoveFile + method or one of the CZipArchive::RemoveFiles methods. + */ + cbDelete = 0x0020, + + /** + Testing a file. + The callback called when testing a file with the CZipArchive::TestFile method. + */ + cbTest = 0x0040, + + /** + Saving the central directory. + The callback called when saving the central directory with the CZipCentralDir::Write method + (usually on close or flush). It is safe to abort the operation on a segmented archive - + the saved part of the central directory will be removed from disk. + */ + cbSave = 0x0080, + + /** + Getting a file from another archive. + The callback called when using one of the CZipArchive::GetFromArchive methods. + */ + cbGet = 0x0100, + + /** + Renaming a file. + The callback called when during renaming a file there is a need to make less or more space + for the new filename. + */ + cbRename = 0x0200, + + /** + Moving data. + The callback called when moving data inside the archive. It happens while replacing files to make less or more space + for the new file or while shifting data with the CZipArchive::ShiftData() method. + */ + cbMoveData = 0x0400, + + /** + The callback called when counting files and bytes to process when performing multiple actions. + When this callback is called, CZipActionCallback::m_uTotalToProcess is + not set (because it is not known and that's why the counting is performed), + but it allows to abort the counting process. + */ + cbCalculateForMulti= 0x0800, + + /** + The callback called when adding multiple files with one of the CZipArchive::AddNewFiles + methods. This callback also registers for #cbAdd. + + \see + 0610231200|multi + */ + cbMultiAdd = 0x1000 | cbAdd, + + + /** + The callback called when preparing existing files for encryption. + + \see + 0610201627|existing + */ + cbEncryptPrepare= 0x2000, + + /** + The callback called in order to report the progress of making space inside the archive before the actual encryption takes place. + + \see + 0610201627|existing + */ + cbEncryptMoveData= 0x4000, + + /** + The callback called for every file being encrypted. + + \see + 0610201627|existing + */ + cbEncrypt = 0x8000, + + + /** + The callback called when encrypting existing files in the archive. This callback also registers for #cbEncryptMoveData and #cbEncrypt. + + \see + 0610201627|existing + \see + 0610231200|multi + */ + cbMultiEncrypt = 0x10000 | cbEncryptMoveData | cbEncrypt, + + /** + Reserved. + You can declare your own callback types above this value. Do not use the numeric value, + but the symbol name - the value may change in the future releases of the library. + */ + cbNextValue = 0x20000, + + /** + All sub-actions. + Represents the sub-actions callbacks - they are called as a part of bigger actions + (#cbAddTmp | #cbAddStore | #cbDeleteCnt | #cbMoveData | #cbCalculateForMulti | #cbEncryptPrepare | #cbEncryptMoveData). + */ + cbSubActions = cbAddTmp | cbAddStore | cbDeleteCnt | cbMoveData | cbCalculateForMulti | cbEncryptPrepare | cbEncryptMoveData, + + /** + Main callbacks. + Represents the main action callbacks (#cbAdd | #cbExtract | #cbDelete | #cbTest | #cbSave | #cbGet | #cbRename | #cbEncrypt). + */ + cbActions = cbAdd | cbExtract | cbDelete | cbTest | cbSave | cbGet | cbRename | cbEncrypt, + + /** + Multiple action callbacks. + Represents the multiple action callbacks. + */ + + cbMultiActions = cbMultiAdd | cbMultiEncrypt, + + /** + All values. + Use this value to call one callback object for all callback types. + */ + cbAll = cbActions | cbSubActions | cbMultiActions + }; + + + /** + A structure that provides global information in case of using multiple actions callbacks. + + \see + 0610231200|multi + \see + cbMultiActions + */ + struct ZIP_API CMultiActionsInfo + { + friend struct CZipActionCallback; + + ZIP_SIZE_TYPE m_uTotalBytesToProcess; ///< The total number of bytes to process. + ZIP_SIZE_TYPE m_uTotalFilesToProcess; ///< The total number of files to process. + ZIP_SIZE_TYPE m_uBytesProcessed; ///< The total number of bytes processed so far. + ZIP_SIZE_TYPE m_uFilesProcessed; ///< The total number of files processed so far. + + /** + Returns the number of files left to process. + \return + The number of files left to process. + */ + ZIP_SIZE_TYPE LeftFilesToProcess() const {return m_uTotalFilesToProcess - m_uFilesProcessed;} + + /** + Returns the number of bytes left to process. + \return + The number of bytes left to process. + */ + ZIP_SIZE_TYPE LeftBytesToProcess() const {return m_uTotalBytesToProcess - m_uBytesProcessed;} + private: + void Init(ZIP_SIZE_TYPE uTotalItemsToProcess, ZIP_SIZE_TYPE uTotalBytesToProcess, int iReactType) + { + m_uTotalFilesToProcess = uTotalItemsToProcess; + m_uTotalBytesToProcess = uTotalBytesToProcess; + m_uBytesProcessed = m_uFilesProcessed = 0; + m_iReactType = iReactType; + m_bActive = false; + } + void OnCallbackInit(int iType) + { + // this assumes, that the callback type will stay unchanged + // between Init() and CallbackEnd() + m_bActive = iType == m_iReactType; + } + + void OnCallCallback(ZIP_SIZE_TYPE uProgress) + { + if (m_bActive) + m_uBytesProcessed += uProgress; + } + bool OnNextFile() + { + if (m_bActive) + { + m_uFilesProcessed++; + return true; + } + else + return false; + } + bool m_bActive; + int m_iReactType; + }; + + CZipActionCallback() + { + m_uTotalToProcess = 0; + m_uProcessed = 0; + m_pMultiActionsInfo = NULL; + } + + /** + Called when the multiple actions operation is about to begin. Initializes CMultiActionsInfo object. + + \param uTotalFilesToProcess + The number of files to process. + + \param uTotalBytesToProcess + The number of bytes to process. + + \param iReactType + The type of the callback that will cause increasing of values in CMultiActionsInfo. + Can be one of #CallbackType values. + + \see + 0610231200|multi + \see + GetMultiActionsInfo + + \note + When overriding this method, call the base method from your code. + */ + virtual void MultiActionsInit(ZIP_SIZE_TYPE uTotalFilesToProcess, ZIP_SIZE_TYPE uTotalBytesToProcess, int iReactType) + { + InitMultiActionsInfo(); + m_pMultiActionsInfo->Init(uTotalFilesToProcess, uTotalBytesToProcess, iReactType); + } + + /** + Called to initialize the callback object. + Sets the filenames and resets #m_uTotalToProcess and #m_uProcessed variables to \c 0. + #m_iType variable is already set to the proper value. Called at the beginning of the operation. + + \param lpszFileInZip + The file that is being processed in the archive. + + \param lpszExternalFile + The external file being processed. This is set to \c NULL, if the operation takes place in memory. + */ + virtual void Init(LPCTSTR lpszFileInZip = NULL, LPCTSTR lpszExternalFile = NULL) + { + m_szFileInZip = lpszFileInZip; + m_szExternalFile = lpszExternalFile; + m_uTotalToProcess = 0; // not yet known + m_uProcessed = 0; // nothing yet done + CacheStepSize(); + ResetProgressStage(); + if (m_pMultiActionsInfo) + // the type is known now + m_pMultiActionsInfo->OnCallbackInit(m_iType); + } + + /** + Called after calculating the total amount of data to process. + + \param uTotalToDo + Total amount of data to process. The method initializes #m_uTotalToProcess with this value. + */ + virtual void SetTotal(ZIP_SIZE_TYPE uTotalToDo) + { + m_uTotalToProcess = uTotalToDo; +// m_uProcessed = 0; // already done in CZipCallbackProvider::Get + } + + /** + Called when a next action begins in multiple actions processing. + This method calls #Callback method with \a uProgress parameter set to \c 0. + + \return + The value returned from the #Callback method. + + \see + 0610231200|multi + + \note + When overriding this method, call the base method from your code. + */ + virtual bool MultiActionsNext() + { + if (m_pMultiActionsInfo && m_pMultiActionsInfo->OnNextFile()) + return Callback(0); + else + return true; + } + + /** + Called after the operation finishes. + It is not called in case of an exception, but + it is called before throwing CZipException::abortedAction or CZipException::abortedSafely. + */ + virtual void CallbackEnd() + { + //ASSERT(m_uProcessed == m_uTotalToProcess); + }; + + /** + Called at the end of the multiple actions operation. + Releases multiple actions information (CMultiActionsInfo). + Override this method, if you want this information to be persisted after + operation finishes. In that case, CMultiActionsInfo will be released + on destruction. + + \see + 0610231200|multi + */ + virtual void MultiActionsEnd() + { + ReleaseMultiActionsInfo(); + } + + /** + Gets the amount of data left to process. + + \return + The amount of data left to process. + */ + ZIP_SIZE_TYPE LeftToProcess() const {return m_uTotalToProcess - m_uProcessed;} + + /** + The total amount of data to process. This value is set when the #SetTotal method is called. + + Depending on the action it is set then to: + - Adding a file : the size the external file being added (or if the type of the callback is CZipActionCallback::cbAddTmp, + the size of the compressed data: CZipFileHeader::m_uComprSize). + - Extracting a file : the size of the uncompressed data (CZipFileHeader::m_uUncomprSize). + - Testing a file : the same as above. + - Deleting a file : the number of bytes to move - the size of all files to remain above the first + file to delete (calculated from offsets in CZipFileHeader::m_uOffset). + - Saving the central directory : the number of files in the archive. + */ + ZIP_SIZE_TYPE m_uTotalToProcess; + ZIP_SIZE_TYPE m_uProcessed; ///< The total amount of data processed so far. + CZipString m_szFileInZip; ///< The name of the file that is being processed in the archive. + + /** + The type of the callback. It is set to one of the #CallbackType values when the action begins. + It's useful, if you have more than one callback assigned to the same callback object. + */ + int m_iType; + + /** + Returns the current CMultiActionsInfo object in multiple actions operation or \c NULL, if + the current operation is not one of CZipActionCallback::cbMultiActions actions. + + \return + The current CMultiActionsInfo object. + + \see + 0610231200|multi + */ + CMultiActionsInfo* GetMultiActionsInfo() + { + return m_pMultiActionsInfo; + } + + /** + Sets the type of the callback, that will cause the current CMultiActionsInfo object to update its progress. + + \param iType + The type of the callback. It can be one of the #CallbackType values. + */ + void SetReactType(int iType) + { + m_pMultiActionsInfo->m_iReactType = iType; + } + + /** + Specifies how often the Callback() method is called. The Callback() method is called every \b n-th callback request, + where \b n is the value returned from the GetStepSize() method. + Override this method to adjust the frequency of calling the callback. + + \return + The value that determines the frequency of calling the Callback() method. + By default, it returns \c 256 for #cbSave, #cbDeleteCnt, #cbCalculateForMulti and #cbEncryptPrepare and \c 1 + for other callback types. + + \note + This method is called in the Init() method and the returned value is cached for further processing. + This means that when you override this method, even with some time-consuming operations, it will not affect + the in-action performance. + + \note + Do not use a too low value, because it may increase significantly the time needed to process a huge number of files. + */ + virtual int GetStepSize() + { + return m_iType == cbSave || m_iType == cbDeleteCnt || m_iType == cbCalculateForMulti || m_iType == cbEncryptPrepare ? 256 : 1; + } + + ~CZipActionCallback() + { + ReleaseMultiActionsInfo(); + } + + /** + Called by processing classes when data processing progressed. + + \param uProgress + The amount of data processed. + + \return + The value returned from #Callback, if the method was called; \c true otherwise. + + */ + bool RequestCallback(ZIP_SIZE_TYPE uProgress = 1) + { + if (!uProgress) + return true; + if (m_iCachedStepSize == 1) + return CallCallback(uProgress); + else + { + m_uAccumulatedProgress += uProgress; + if (m_iCurrentStep >= m_iCachedStepSize) + { + bool ret = CallCallback(m_uAccumulatedProgress); + ResetProgressStage(); + return ret; + } + else + { + m_iCurrentStep++; + return true; + } + } + } + + /** + Called by processing classes when data processing has finished to + allow calling the Callback() method for the amount of processed data for + which the Callback() has not been called. This usually happens, + when GetStepSize() does not return 1. + + \param uProgress + The amount of data processed. + + \return + The value returned from the #Callback method, if the method was called; \c true otherwise. + + */ + bool RequestLastCallback(ZIP_SIZE_TYPE uProgress = 0) + { + bool ret; + if (m_uAccumulatedProgress == 0 && uProgress == 0) + ret = true; + else + ret = CallCallback(m_uAccumulatedProgress + uProgress); + ResetProgressStage(); + return ret; + } + +protected: + /** + + Calls the Callback() method internally, increases CZipActionCallback::m_uProcessed and lets the CZipActionCallback + increase its values, if needed. + + \param uProgress + The amount of data processed. + + \return + The return value from the Callback() method. + */ + virtual bool CallCallback(ZIP_SIZE_TYPE uProgress) + { + m_uProcessed += uProgress; + if (m_pMultiActionsInfo) + m_pMultiActionsInfo->OnCallCallback(uProgress); + return Callback(uProgress); + } + + /** + Caches the value returned from the GetStepSize() method. Called in the Init()method. + */ + void CacheStepSize() + { + m_iCachedStepSize = GetStepSize(); + if (m_iCachedStepSize == 0) + m_iCachedStepSize = 1; + } + + /** + Initializes the values that depend on the frequency of calling the Callback() method. + Called with every call to the Callback() method. + + \see + GetStepSize + */ + void ResetProgressStage() + { + m_iCurrentStep = 1; + m_uAccumulatedProgress = 0; + } +private: + CMultiActionsInfo* m_pMultiActionsInfo; + void InitMultiActionsInfo() + { + ReleaseMultiActionsInfo(); + m_pMultiActionsInfo = new CMultiActionsInfo(); + } + void ReleaseMultiActionsInfo() + { + if (m_pMultiActionsInfo != NULL) + { + delete m_pMultiActionsInfo; + m_pMultiActionsInfo = NULL; + } + } + + int m_iCachedStepSize; ///< The cached step value for the time of processing. + int m_iCurrentStep; + ZIP_SIZE_TYPE m_uAccumulatedProgress; +}; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + + +#endif diff --git a/harbour/contrib/hbziparch/ZipCallbackProvider.h b/harbour/contrib/hbziparch/ZipCallbackProvider.h new file mode 100644 index 0000000000..5d4bfddd41 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCallbackProvider.h @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipCallbackProvider.h +* Includes the ZipArchiveLib::CZipCallbackProvider class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPCALLBACKPROVIDER_DOT_H) +#define ZIPARCHIVE_ZIPCALLBACKPROVIDER_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #if defined ZIP_HAS_DLL + #pragma warning (push) + #pragma warning( disable : 4275 ) // non dll-interface used as base for dll-interface class + #endif +#endif + +#include "ZipCallback.h" +#include "ZipExport.h" +#include "ZipCollections.h" + +namespace ZipArchiveLib +{ + +/** + The storage for callback objects. A structure for the internal use only. + \see + CZipArchive::SetCallback + CZipArchive::GetCallback +*/ +class ZIP_API CZipCallbackProvider : public CZipMap +{ +public: + void Set(CZipActionCallback* pCallback, int iWhich) + { + CZipActionCallback::CallbackType cbs[] = {CZipActionCallback::cbAdd, CZipActionCallback::cbAddTmp, CZipActionCallback::cbAddStore, CZipActionCallback::cbExtract, CZipActionCallback::cbDeleteCnt, CZipActionCallback::cbDelete, CZipActionCallback::cbTest, CZipActionCallback::cbSave, CZipActionCallback::cbGet, CZipActionCallback::cbRename, CZipActionCallback::cbMoveData, CZipActionCallback::cbCalculateForMulti, CZipActionCallback::cbMultiAdd, CZipActionCallback::cbEncryptPrepare, CZipActionCallback::cbEncryptMoveData, CZipActionCallback::cbEncrypt, CZipActionCallback::cbMultiEncrypt}; + int iCount = sizeof(cbs)/sizeof(CZipActionCallback::CallbackType); + for (int i = 0; i < iCount; i++) + { + CZipActionCallback::CallbackType iCallback = cbs[i]; + if (iWhich & iCallback) + SetInternal(pCallback, iCallback); + } + } + + CZipActionCallback* Get(CZipActionCallback::CallbackType iType) + { + CZipActionCallback* pCallback = NULL; + if (Lookup(iType, pCallback)) + { + pCallback->m_iType = iType; + return pCallback; + } + else + return NULL; + } +protected: + void SetInternal(CZipActionCallback* pCallback, CZipActionCallback::CallbackType iType) + { + if (pCallback) + { + SetAt(iType, pCallback); + } + else + RemoveKey(iType); + } +}; + +} // namespace + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + + +#endif // !defined(ZIPARCHIVE_ZIPCALLBACKPROVIDER_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipCentralDir.cpp b/harbour/contrib/hbziparch/ZipCentralDir.cpp new file mode 100644 index 0000000000..f1611cb5c3 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCentralDir.cpp @@ -0,0 +1,955 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +#include "ZipCentralDir.h" +#include "ZipArchive.h" +#include "ZipFileMapping.h" +#include "ZipPlatform.h" +#include "BytesWriter.h" + + +#define CENTRAL_DIR_END_SIZE 22 + + +using namespace ZipArchiveLib; + +char CZipCentralDir::m_gszSignature[] = {0x50, 0x4b, 0x05, 0x06}; +char CZipCentralDir::m_gszSignature64Locator[] = {0x50, 0x4b, 0x06, 0x07}; + + + +CZipCentralDir::CZipCentralDir() +{ + m_pInfo = NULL; + m_pHeaders = NULL; + m_pFindArray = NULL; + m_pStorage = NULL; + m_pOpenedFile = NULL; + m_iIgnoredChecks = 0; + m_pCallbacks = NULL; +} + +void CZipCentralDir::Init(CZipStorage* pStorage, ZipArchiveLib::CZipCallbackProvider* pCallbacks, CZipStringStoreSettings* pStringSettings, CZipCentralDir* pSource) +{ + m_pStorage = pStorage; + m_pCallbacks = pCallbacks; + m_pStringSettings = pStringSettings; + m_pOpenedFile = NULL; + m_iIgnoredChecks = CZipArchive::checkIgnoredByDefault; + // just in case + DestroySharedData(); + if (pSource != NULL) + { +#ifdef ZIP_ARCHIVE_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 + // points to the same object now + UnlockAccess(); +#endif + + m_pStorage->UpdateSegmMode(m_pInfo->m_uLastVolume); + m_pStorage->m_uBytesBeforeZip = pSource->m_pStorage->m_uBytesBeforeZip; + + } + else + CreateSharedData(); +} + +CZipCentralDir::~CZipCentralDir() +{ + DestroySharedData(); +} + +void CZipCentralDir::Read(bool bExhaustiveRead) +{ + 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) + ThrowError(CZipException::cdirNotFound); + + m_pStorage->m_pFile->Seek((ZIP_FILE_USIZE)(m_pInfo->m_uEndOffset + 4)); + CZipAutoBuffer buf(CENTRAL_DIR_END_SIZE); + + // 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); + + WORD uCommentSize; + CBytesWriter::ReadBytes(m_pInfo->m_uLastVolume, buf, 2); + CBytesWriter::ReadBytes(m_pInfo->m_uVolumeWithCD, buf + 2, 2); + CBytesWriter::ReadBytes(m_pInfo->m_uVolumeEntriesNo,buf + 4, 2); + CBytesWriter::ReadBytes(m_pInfo->m_uEntriesNumber,buf + 6, 2); + CBytesWriter::ReadBytes(m_pInfo->m_uSize, buf + 8, 4); + CBytesWriter::ReadBytes(m_pInfo->m_uOffset, buf + 12, 4); + CBytesWriter::ReadBytes(uCommentSize, buf + 16); + buf.Release(); + + 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); + } + + 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); + // 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); + + m_pStorage->UpdateSegmMode(m_pInfo->m_uLastVolume); + + if (!m_pStorage->IsSegmented() && !m_pInfo->CheckIfOK_1()) + ThrowError(CZipException::badZipFile); + + if (m_pStorage->m_uBytesBeforeZip == 0 && m_pInfo->m_uLastVolume == 0) + m_pStorage->m_uBytesBeforeZip = m_pInfo->CalculateBytesBeforeZip(); + + if (!m_pInfo->CheckIfOK_2()) + ThrowError(CZipException::badZipFile); + + m_pInfo->m_bInArchive = true; + m_pStorage->ChangeVolume(m_pInfo->m_uVolumeWithCD); + + if (!m_pInfo->m_uSize) + return; + + ReadHeaders(bExhaustiveRead); +} + + +void CZipCentralDir::ThrowError(int err) const +{ + CZipException::Throw(err, m_pStorage->m_pFile->GetFilePath()); +} + + +void CZipCentralDir::ReadHeaders(bool bExhaustiveRead) +{ + m_pStorage->Seek(m_pInfo->m_uOffset); + RemoveHeaders(); //just in case + for (ZIP_INDEX_TYPE i = 0; i < m_pInfo->m_uEntriesNumber; i++) + { + CZipFileHeader* pHeader = new CZipFileHeader; + m_pHeaders->Add(pHeader); + + if (!pHeader->Read(*this, true)) + ThrowError(CZipException::badZipFile); + } + + if (bExhaustiveRead) + { + ZIP_FILE_USIZE uPosition = m_pStorage->m_pFile->GetPosition(); + // different offset, or different parts + if (uPosition != m_pInfo->m_uEndOffset || m_pStorage->IsSegmented() && 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; + m_pHeaders->Add(pHeader); + if (!pHeader->Read(*this, 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 + m_pHeaders->Sort(CompareHeaders); + RebuildFindFastArray(); +} + +void CZipCentralDir::Close() +{ + m_pOpenedFile = NULL; + DestroySharedData(); + // do not reference it anymore + m_pInfo = NULL; + m_pHeaders = NULL; + m_pFindArray = NULL; +} + +bool CZipCentralDir::IsValidIndex(ZIP_INDEX_TYPE uIndex)const +{ + return uIndex < (ZIP_INDEX_TYPE)m_pHeaders->GetSize() && uIndex != ZIP_FILE_INDEX_UNSPECIFIED; +} + +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)) + ThrowError(CZipException::badZipFile); + m_pOpenedFile = pOpenedFile; +} + + +void CZipCentralDir::CloseFile(bool skipCheckingDataDescriptor) +{ + if (!m_pOpenedFile) + return; + if (!skipCheckingDataDescriptor && IsConsistencyCheckOn(CZipArchive::checkDataDescriptor) + && !m_pOpenedFile->CheckDataDescriptor(m_pStorage)) + ThrowError(CZipException::badZipFile); + m_pOpenedFile = NULL; +} + +// add new header using the argument as a template +CZipFileHeader* CZipCentralDir::AddNewFile(const CZipFileHeader & header, ZIP_INDEX_TYPE uReplaceIndex, int iLevel, bool bRichHeaderTemplateCopy) +{ + // copy some of the template data + m_pOpenedFile = NULL; + ZIP_INDEX_TYPE uIndex; + CZipFileHeader* pHeader = new CZipFileHeader(); + try + { + pHeader->m_uMethod = header.m_uMethod; + pHeader->m_uModDate = header.m_uModDate; + pHeader->m_uModTime = header.m_uModTime; + + + 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_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; + + // current settings + pHeader->m_stringSettings = *m_pStringSettings; + + // 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 + RemoveFromDisk(); + + bool bReplace = IsValidIndex(uReplaceIndex); + + pHeader->PrepareData(iLevel, m_pStorage->IsSegmented() != 0); + + 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; + } + // 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) + { + CZipFileHeader* pfh = (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)uReplaceIndex]; + m_pStorage->Seek(pfh->m_uOffset); + RemoveFile(pfh, uReplaceIndex, false); + m_pHeaders->InsertAt((ZIP_ARRAY_SIZE_TYPE)uReplaceIndex, pHeader); + m_pOpenedFile = pHeader; + uIndex = uReplaceIndex; + } + else + { + uIndex = (ZIP_INDEX_TYPE)m_pHeaders->Add(pHeader); + m_pOpenedFile = pHeader; + m_pStorage->m_pFile->SeekToEnd(); + } + } + catch(...) + { + // otherwise it is added to the collection and will be auto-deleted + if (pHeader != NULL && m_pOpenedFile == NULL) + delete pHeader; + throw; + } + + if (m_pInfo->m_bFindFastEnabled) + InsertFindFastElement(pHeader, uIndex); // GetCount > 0, because we have just added a header + + 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) +{ + if (!IsValidIndex(uIndex)) + { + ASSERT(FALSE); + return false; + } + CZipFileHeader* pHeader = (*this)[uIndex]; + pHeader->m_stringSettings.m_uCommentCodePage = m_pStringSettings->m_uCommentCodePage; + pHeader->SetComment(lpszComment); + RemoveFromDisk(); + return true; +} + +void CZipCentralDir::RemoveFromDisk() +{ + if (m_pInfo->m_bInArchive) + { + ASSERT(!m_pStorage->IsSegmented()); // you can't add files to an existing segmented archive or to delete them from it + m_pStorage->m_pFile->SetLength((ZIP_FILE_USIZE)(m_pStorage->m_uBytesBeforeZip + m_pInfo->m_uOffset)); + m_pInfo->m_bInArchive = false; + } + else + m_pStorage->Flush(); // if remove from disk is requested, then the archive modification will follow, so flush the buffers +} + + +void CZipCentralDir::CloseNewFile() +{ + m_pOpenedFile->OnNewFileClose(m_pStorage); + m_pOpenedFile = NULL; +} + +void CZipCentralDir::Write() +{ + if (m_pInfo->m_bInArchive) + return; + + m_pInfo->m_uEntriesNumber = (ZIP_INDEX_TYPE)m_pHeaders->GetSize(); + + if (!m_pStorage->IsSegmented()) + { + m_pStorage->Flush(); + m_pStorage->m_pFile->SeekToEnd(); + } +// else +// we are at the end already + + m_pInfo->m_uSize = 0; + bool bDontAllowVolumeChange = false; + + if (m_pStorage->IsSegmented()) + { + // segmentation signature at the beginning (4 bytes) + the size of the data descr. for each file + ZIP_SIZE_TYPE uSize = GetSize(true); + // if there is a segmented archive in creation and it is only one-volume, + // (current volume number is 0 so far, no bytes has been written so we know they are + // all in the buffer) make sure that it will be after writing central dir + // and make it a not segmented archive + if (m_pStorage->GetCurrentVolume() == 0) + { + // calculate the size of data descriptors already in the buffer or on the disk + // (they will be removed in the not segmented archive). + ZIP_SIZE_TYPE uToGrow = uSize - 4; + for (ZIP_INDEX_TYPE i = 0; i < m_pInfo->m_uEntriesNumber; i++) + { + CZipFileHeader* pHeader = (*this)[i]; + if (pHeader->NeedsDataDescriptor()) + { + if (!pHeader->IsEncrypted()) + uToGrow -= 4; // remove the signature only + } + else + uToGrow -= pHeader->GetDataDescriptorSize(true); + } + + ZIP_SIZE_TYPE uVolumeFree = m_pStorage->VolumeLeft(); + + if (uVolumeFree >= uToGrow) + // lets make sure it will be one-volume archive + { + // can the operation be done only in the buffer? + if (!m_pStorage->m_uBytesWritten && // no bytes on the disk yet + (m_pStorage->GetFreeInBuffer() >= uToGrow)) // is the buffer big enough? + { + RemoveDataDescr(true); + bDontAllowVolumeChange = true; // if a volume change occurs somehow, we'll throw an error later + } + else + { + m_pStorage->Flush(); + if (RemoveDataDescr(false)) + bDontAllowVolumeChange = true; // if a volume change occurs somehow, we'll throw an error later + } + } + } + + // make sure that in a segmented archive, the whole central directory will fit on the single volume + if (!bDontAllowVolumeChange) + m_pStorage->AssureFree(uSize); + } + + try + { + WriteHeaders(bDontAllowVolumeChange || !m_pStorage->IsSegmented()); + + WriteCentralEnd(); + + if (bDontAllowVolumeChange) + { + if (m_pStorage->GetCurrentVolume() != 0) + ThrowError(CZipException::badZipFile); + } + } + catch (...) + { + if (bDontAllowVolumeChange) + { + m_pStorage->FinalizeSegm(); + m_pInfo->m_uLastVolume = 0; + } + throw; + } + m_pInfo->m_bInArchive = true; +} + +void CZipCentralDir::WriteHeaders(bool bOneDisk) +{ + CZipActionCallback* pCallback = m_pCallbacks->Get(CZipActionCallback::cbSave); + m_pInfo->m_uVolumeEntriesNo = 0; + 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; + + if (pCallback) + { + pCallback->Init(); + pCallback->SetTotal(m_pInfo->m_uEntriesNumber); + } + + int iAborted = 0; + if (m_pInfo->m_uEntriesNumber > 0) + { + 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); + + if (m_pStorage->GetCurrentVolume() != uDisk) + { + m_pInfo->m_uVolumeEntriesNo = 1; + uDisk = m_pStorage->GetCurrentVolume(); + // update the information about the offset and starting volume if the + // first header was written in the new volume + if (i == 0) + { + m_pInfo->m_uOffset = 0; + m_pInfo->m_uVolumeWithCD = uDisk; + } + } + else + m_pInfo->m_uVolumeEntriesNo++; + + if (pCallback) + { + bool ret, last; + if (i == uLast) + { + ret = pCallback->RequestLastCallback(1); + last = true; + } + else + { + ret = pCallback->RequestCallback(); + last = false; + } + + if (ret) + { + if (last) + break; + } + else + { + if (bOneDisk) + { + ASSERT(!m_pStorage->IsSegmented()); + // if segmented, would need to m_pStorage->Flush(), but the headers can span multiple volumes + m_pStorage->EmptyWriteBuffer(); + // remove saved part from the volume + m_pStorage->m_pFile->SetLength((ZIP_FILE_USIZE)(m_pStorage->m_uBytesBeforeZip + m_pInfo->m_uOffset)); + // We can now abort safely + iAborted = CZipException::abortedSafely; + } + else + iAborted = CZipException::abortedAction; + break; + } + } + else if (i == uLast) + break; + + i++; + } + } + + if (pCallback) + { + pCallback->CallbackEnd(); + if (iAborted) + ThrowError(iAborted); + } +} + + +void CZipCentralDir::WriteCentralEnd() +{ + ZIP_SIZE_TYPE uSize = CENTRAL_DIR_END_SIZE + m_pInfo->m_pszComment.GetSize(); + + CZipAutoBuffer buf((DWORD)uSize); + char* pBuf = buf; + ZIP_VOLUME_TYPE uDisk = m_pStorage->GetCurrentVolume(); + if (m_pStorage->IsSegmented() != 0) + { + // update the volume number + m_pStorage->AssureFree(uSize); + m_pInfo->m_uLastVolume = m_pStorage->GetCurrentVolume(); + } + if (m_pInfo->m_uLastVolume != uDisk) + m_pInfo->m_uVolumeEntriesNo = 0; + + + WORD uCommentSize = (WORD)m_pInfo->m_pszComment.GetSize(); + memcpy(pBuf, m_gszSignature, 4); + CBytesWriter::WriteBytes(pBuf + 4, CBytesWriter::WriteSafeU16(m_pInfo->m_uLastVolume)); + CBytesWriter::WriteBytes(pBuf + 6, CBytesWriter::WriteSafeU16(m_pInfo->m_uVolumeWithCD)); + CBytesWriter::WriteBytes(pBuf + 8, CBytesWriter::WriteSafeU16(m_pInfo->m_uVolumeEntriesNo)); + CBytesWriter::WriteBytes(pBuf + 10, CBytesWriter::WriteSafeU16(m_pInfo->m_uEntriesNumber)); + CBytesWriter::WriteBytes(pBuf + 12, CBytesWriter::WriteSafeU32(m_pInfo->m_uSize)); + CBytesWriter::WriteBytes(pBuf + 16, CBytesWriter::WriteSafeU32(m_pInfo->m_uOffset)); + CBytesWriter::WriteBytes(pBuf + 20, uCommentSize); + memcpy(pBuf + 22, m_pInfo->m_pszComment, uCommentSize); + if (uSize > (DWORD)(-1)) + CZipException::Throw(CZipException::internalError); + m_pStorage->Write(buf, (DWORD)uSize, true); +} + +void CZipCentralDir::RemoveAll() +{ + ClearFindFastArray(); + RemoveHeaders(); +} + + +void CZipCentralDir::RemoveFile(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex, bool bShift) +{ + if (uIndex == ZIP_FILE_INDEX_UNSPECIFIED) + { + // we need to know the index to remove + ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize(); + for (ZIP_INDEX_TYPE i = 0; i < uCount; i++) + if (pHeader == (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i]) + { + uIndex = i; + break; + } + } + ASSERT(uIndex != ZIP_FILE_INDEX_UNSPECIFIED || pHeader); + if (!pHeader) + pHeader = (*m_pHeaders)[(ZIP_ARRAY_SIZE_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--; + } + } + } + + if (uIndex != ZIP_FILE_INDEX_UNSPECIFIED) + { + delete pHeader; + m_pHeaders->RemoveAt((ZIP_ARRAY_SIZE_TYPE)uIndex); + } +} + + +void CZipCentralDir::RemoveLastFile(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex) +{ + if (uIndex == ZIP_FILE_INDEX_UNSPECIFIED) + { + if (m_pHeaders->GetSize() == 0) + return; + uIndex = (ZIP_VOLUME_TYPE)(m_pHeaders->GetSize() - 1); + } + if (!pHeader) + pHeader = (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)uIndex]; + ZIP_SIZE_TYPE uNewSize = pHeader->m_uOffset + m_pStorage->m_uBytesBeforeZip; + // then remove + RemoveFile(pHeader, uIndex); + + m_pStorage->Flush(); + m_pStorage->m_pFile->SetLength((ZIP_FILE_USIZE)uNewSize); + m_pInfo->m_bInArchive = false; // it is true when AutoFlush is set to true +} + + +ZIP_SIZE_TYPE CZipCentralDir::GetSize(bool bWhole) const +{ + ZIP_SIZE_TYPE uTotal = CENTRAL_DIR_END_SIZE + m_pInfo->m_pszComment.GetSize(); + ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize(); + if (bWhole) + { + for (ZIP_INDEX_TYPE i = 0; i < uCount; i++) + { + const CZipFileHeader* pHeader = (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i]; + uTotal += pHeader->GetSize(); + } + } + + + return uTotal; +} + +bool CZipCentralDir::RemoveDataDescr(bool bFromBuffer) +{ + // this will not work if there are bytes before zip + CZipFileMapping fm; + char* pFile; + ZIP_SIZE_TYPE uSize; + if (bFromBuffer) + { + uSize = m_pStorage->m_uBytesInWriteBuffer; + pFile = m_pStorage->m_pWriteBuffer; + } + else + { + uSize = (ZIP_SIZE_TYPE)m_pStorage->m_pFile->GetLength(); + // we cannot use CZipMemFile in multi-volume archive + // so it must be CZipFile + if (!fm.CreateMapping(static_cast(m_pStorage->m_pFile))) + return false; + pFile = fm.GetMappedMemory(); + } + + ZIP_SIZE_TYPE uOffsetToChange = 4; + ZIP_SIZE_TYPE uPosInBuffer = 0; + WORD uExtraHeaderLen; + ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize(); + for (ZIP_INDEX_TYPE i = 0; i < uCount; i++) + { + CZipFileHeader* pHeader = (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i]; + char* pSour = pFile + pHeader->m_uOffset; + + if (pHeader->NeedsDataDescriptor()) + uExtraHeaderLen = (WORD)(pHeader->IsEncrypted() ? 0 : 4); + else + { + uExtraHeaderLen = pHeader->GetDataDescriptorSize(true); + // removing data descriptor + 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); + } + + 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); + + uPosInBuffer += uToCopy; + pHeader->m_uOffset -= uOffsetToChange; + uOffsetToChange += uExtraHeaderLen; + } + + if (bFromBuffer) + m_pStorage->m_uBytesInWriteBuffer = (DWORD)uPosInBuffer; + else + { + m_pStorage->m_uBytesWritten = uPosInBuffer; + fm.RemoveMapping(); + m_pStorage->m_pFile->SetLength((ZIP_FILE_USIZE)uPosInBuffer); + } + return true; +} + +void CZipCentralDir::RemoveHeaders() +{ + ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize(); + for (ZIP_INDEX_TYPE i = 0; i < uCount; i++) + delete (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i]; + m_pHeaders->RemoveAll(); +} + +void CZipCentralDir::BuildFindFastArray( bool bCaseSensitive ) +{ + ClearFindFastArray(); + m_pInfo->m_bCaseSensitive = bCaseSensitive; + // for later + m_pInfo->m_pCompare = GetCZipStrCompFunc(bCaseSensitive); + ZIP_INDEX_TYPE uCount = (ZIP_INDEX_TYPE)m_pHeaders->GetSize(); + + for (ZIP_INDEX_TYPE i = 0; i < uCount; i++) + m_pFindArray->Add(new CZipFindFast((*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)i], i)); + + m_pFindArray->Sort(bCaseSensitive ? CompareFindFastCollate : CompareFindFastCollateNoCase); +} + +void CZipCentralDir::EnableFindFast(bool bEnable, bool bCaseSensitive) +{ + if (m_pInfo->m_bFindFastEnabled == bEnable) + return; + m_pInfo->m_bFindFastEnabled = bEnable; + if (bEnable) + BuildFindFastArray(bCaseSensitive); + else + m_pFindArray->RemoveAll(); +} + +ZIP_INDEX_TYPE CZipCentralDir::FindFile(LPCTSTR lpszFileName, bool bCaseSensitive, bool bSporadically, bool bFileNameOnly) +{ + if (!m_pInfo->m_bFindFastEnabled) + EnableFindFast(true, bSporadically ? !bCaseSensitive : bCaseSensitive); + ZIP_INDEX_TYPE uResult = ZIP_FILE_INDEX_NOT_FOUND; + if (bFileNameOnly) + { + // a non-effective search (treat an array as unsorted) + + // set the proper compare function + ZIPSTRINGCOMPARE pCompare = bCaseSensitive == m_pInfo->m_bCaseSensitive ? m_pInfo->m_pCompare : GetCZipStrCompFunc(bCaseSensitive); + + ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)m_pFindArray->GetSize(); + for (ZIP_INDEX_TYPE i = 0; i < uSize; i++) + { + CZipString sz = (*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)i]->m_pHeader->GetFileName(); + CZipPathComponent::RemoveSeparators(sz); // to find a dir + CZipPathComponent zpc(sz); + sz = zpc.GetFileName(); + if ((sz.*pCompare)(lpszFileName) == 0) + { + uResult = i; + break; + } + } + } + else if (bCaseSensitive == m_pInfo->m_bCaseSensitive) + uResult = FindFileNameIndex(lpszFileName); + else + { + if (bSporadically) + { + // a non-effective search (treat an array as unsorted) + // do not use m_pInfo->m_pCompare, as it may be shared + ZIPSTRINGCOMPARE pCompare = GetCZipStrCompFunc(bCaseSensitive); + ZIP_INDEX_TYPE uSize = (ZIP_INDEX_TYPE)m_pFindArray->GetSize(); + for (ZIP_INDEX_TYPE i = 0; i < uSize; i++) + if (((*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)i]->m_pHeader->GetFileName().*pCompare)(lpszFileName) == 0) + { + uResult = i; + break; + } + } + else + { + BuildFindFastArray(bCaseSensitive); + uResult = FindFileNameIndex(lpszFileName); + } + } + return uResult == ZIP_FILE_INDEX_NOT_FOUND ? ZIP_FILE_INDEX_NOT_FOUND : (*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)uResult]->m_uIndex; +} + +ZIP_INDEX_TYPE CZipCentralDir::InsertFindFastElement(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex) +{ + CZipString fileName = pHeader->GetFileName(); + ZIP_ARRAY_SIZE_TYPE uSize = m_pFindArray->GetSize(); + + // Our initial binary search range encompasses the entire array of filenames: + ZIP_ARRAY_SIZE_TYPE start = 0; + ZIP_ARRAY_SIZE_TYPE end = uSize; + + // Keep halving our search range until we find the right place + // to insert the new element: + while ( start < end ) + { + // Find the midpoint of the search range: + ZIP_ARRAY_SIZE_TYPE midpoint = ( start + end ) / 2; + + // Compare the filename with the filename at the midpoint of the current search range: + int result = CompareElement(fileName, (ZIP_INDEX_TYPE)midpoint); + + // If our filename is larger, it must fall in the first half of the search range: + if ( result > 0 ) + { + end = midpoint; + } + + // If it's smaller, it must fall in the last half: + else if ( result < 0 ) + { + start = midpoint + 1; + } + + // If they're equal, we can go ahead and insert here: + else + { + start = midpoint; + break; + } + } + m_pFindArray->InsertAt(start, new CZipFindFast(pHeader, uIndex == ZIP_FILE_INDEX_UNSPECIFIED ? (ZIP_INDEX_TYPE)uSize : uIndex /* just in case */)); + return (ZIP_INDEX_TYPE)start; +} + +ZIP_INDEX_TYPE CZipCentralDir::FindFileNameIndex(LPCTSTR lpszFileName) const +{ + ZIP_ARRAY_SIZE_TYPE start = 0; + + ZIP_ARRAY_SIZE_TYPE end = m_pFindArray->GetSize(); + if (end == 0) + return ZIP_FILE_INDEX_NOT_FOUND; + else + end--; + + // Keep halving our search range until we find the given element: + while ( start <= end ) + { + // Find the midpoint of the search range: + ZIP_ARRAY_SIZE_TYPE midpoint = ( start + end ) / 2; + + // Compare the given filename with the filename at the midpoint of the search range: + int result = CompareElement(lpszFileName, (ZIP_INDEX_TYPE)midpoint); + + // If our filename is smaller, it must fall in the first half of the search range: + if ( result > 0 ) + { + if (midpoint == 0) + return ZIP_FILE_INDEX_NOT_FOUND; + end = midpoint - 1; + } + + // If it's larger, it must fall in the last half: + else if ( result < 0 ) + { + start = midpoint + 1; + } + + // If they're equal, return the result: + else + { + return (ZIP_INDEX_TYPE)midpoint; + } + } + + // Signal failure: + return ZIP_FILE_INDEX_NOT_FOUND; +} + + +void CZipCentralDir::CreateSharedData() +{ + m_pInfo = new CInfo(); + m_pInfo->Init(); + m_pHeaders = new CZipArray(); + m_pFindArray = new CZipArray(); +} + +void CZipCentralDir::DestroySharedData() +{ + if (!m_pInfo) + return; +#ifdef ZIP_ARCHIVE_USE_LOCKING + LockAccess(); + try + { +#endif + m_pInfo->m_iReference--; + if (m_pInfo->m_iReference <= 0) // <= is just in case instead of == + { + + if (m_pHeaders != NULL) + { + RemoveHeaders(); + delete m_pHeaders; + m_pHeaders = NULL; + } + + if (m_pFindArray != NULL) + { + ClearFindFastArray(); + delete m_pFindArray; + m_pFindArray = NULL; + } +#ifdef ZIP_ARCHIVE_USE_LOCKING + UnlockAccess(); +#endif + delete m_pInfo; + m_pInfo = NULL; + } +#ifdef ZIP_ARCHIVE_USE_LOCKING + } + catch(...) + { + UnlockAccess(); + throw; + } + UnlockAccess(); +#endif + +} diff --git a/harbour/contrib/hbziparch/ZipCentralDir.h b/harbour/contrib/hbziparch/ZipCentralDir.h new file mode 100644 index 0000000000..65fa7f527a --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCentralDir.h @@ -0,0 +1,822 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipCentralDir.h +* Includes the CZipCentralDir class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPCENTRALDIR_DOT_H) +#define ZIPARCHIVE_ZIPCENTRALDIR_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (push) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class +#endif + +#include "ZipException.h" +#include "ZipFileHeader.h" +#include "ZipAutoBuffer.h" +#include "ZipCollections.h" +#include "ZipCompatibility.h" +#include "ZipExport.h" +#include "ZipCallbackProvider.h" +#include "ZipMutex.h" + + +/** + Represents the central directory record in the archive. +*/ +class ZIP_API CZipCentralDir +{ +public: + + /** + Used in fast finding files by the filename. + A structure for the internal use only. + \see + CZipCentralDir::m_pFindArray + \see + CZipArchive::FindFile + \see + CZipArchive::EnableFindFast + */ + struct ZIP_API CZipFindFast + { + CZipFindFast() + { + m_uIndex = 0; + m_pHeader= NULL; + } + CZipFindFast(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex):m_pHeader(pHeader), m_uIndex(uIndex){} + + /** + A pointer to the structure in CZipCentralDir. We extract a name from it. + */ + CZipFileHeader* m_pHeader; + + /** + The index in the central directory of the #m_pHeader. + */ + ZIP_INDEX_TYPE m_uIndex; + }; + + + /** + Stores general information about the central directory. + \see + CZipArchive::GetCentralDirInfo + */ + struct ZIP_API CInfo + { + + /** + The position of the End of Central Directory Record. + In the Zip64 it points to the Zip64 counterpart. + */ + ZIP_SIZE_TYPE m_uEndOffset; + + /** + The zero-based number of the volume with the End of Central Directory Record. To determine the total number of segments in an archive, + add one to this value. Request this information with CZipArchive::GetCentralDirInfo. + */ + ZIP_VOLUME_TYPE m_uLastVolume; + ZIP_VOLUME_TYPE m_uVolumeWithCD; ///< The number of the volume with the start of the central directory. + ZIP_INDEX_TYPE m_uVolumeEntriesNo; ///< The total number of entries in the central directory on the last volume. + ZIP_INDEX_TYPE m_uEntriesNumber; ///< The total number of entries in the central directory. + + /** + The size of the central directory. + This value is valid only if #m_bInArchive is \c true; in other cases use the #GetSize method instead. + */ + ZIP_SIZE_TYPE m_uSize; + + /** + The offset of the start of the central directory with respect to the starting volume number. + It is the value written in the central directory record. + This value is valid only if #m_bInArchive is \c true. + */ + ZIP_SIZE_TYPE m_uOffset; + + + /** + This value is \c true if the central directory is physically present in the archive; \c false otherwise. + */ + bool m_bInArchive; + + private: + friend class CZipCentralDir; + void Init() + { + m_iReference = 1; +#ifdef ZIP_ARCHIVE_USE_LOCKING + m_mutex.Open(); +#endif + m_pCompare = GetCZipStrCompFunc(ZipPlatform::GetSystemCaseSensitivity()); + m_bCaseSensitive = false; + m_bFindFastEnabled = false; + m_pszComment.Release(); + // initialize ( necessary when using 64 bits - we are copying only 4 bytes in Read()) + m_bInArchive = false; + m_uEndOffset = 0; + m_uLastVolume = 0; + m_uVolumeWithCD = 0; + m_uVolumeEntriesNo = 0; + m_uEntriesNumber = 0; + m_uSize = 0; + m_uOffset = 0; + } + bool CheckIfOK_1() + { + return (m_uEndOffset >= m_uOffset + m_uSize); + } + ZIP_SIZE_TYPE CalculateBytesBeforeZip() + { + return m_uEndOffset - m_uSize - m_uOffset; + } + bool CheckIfOK_2() + { + return (m_uSize || !m_uEntriesNumber) && (m_uEntriesNumber || !m_uSize); + } + void DiskChange(ZIP_VOLUME_TYPE uCurrentVolume) + { + m_uLastVolume = uCurrentVolume; + if (m_uEntriesNumber) + { + m_uVolumeEntriesNo = 0; + } + else + { + m_uVolumeWithCD = m_uLastVolume; + m_uOffset = 0; + } + } + + /** + Gets a value indicating if the current archive properties requires the Zip64 format. + + \return + \c true, if the Zip64 is needed; \c false otherwise. + + \see + 0610051629 + */ + bool NeedsZip64() const + { + return m_uLastVolume >= USHRT_MAX || m_uVolumeWithCD >= USHRT_MAX || m_uVolumeEntriesNo >= USHRT_MAX || m_uEntriesNumber >= USHRT_MAX || m_uSize >= UINT_MAX || m_uOffset >= UINT_MAX; + } + + CZipAutoBuffer m_pszComment; ///< The global archive comment. + + /** + The case-sensitivity of CZipCentralDir::m_pFindArray sorting. + */ + bool m_bCaseSensitive; + + /** + The value set with the CZipCentralDir::EnableFindFast method. + */ + bool m_bFindFastEnabled; + + private: + /** + The method used in string comparisons. It is set depending on the current case-sensitivity. + */ + ZIPSTRINGCOMPARE m_pCompare; + int m_iReference; +#ifdef ZIP_ARCHIVE_USE_LOCKING + ZipArchiveLib::CZipMutex m_mutex; +#endif + }; + + CZipCentralDir(); + virtual ~CZipCentralDir(); + + static char m_gszSignature[]; ///< The End of Central Directory Record signature. + static char m_gszSignature64Locator[]; ///< The Zip64 End of Central Directory Locator signature. + CZipFileHeader* m_pOpenedFile; ///< It points to the currently opened file or it is \c NULL, if no file is opened. + + /** + Initializes the object. + + \param pStorage + The current storage to use. + + \param pCallbacks + The current callbacks provider. + + \param pStringSettings + The current string settings. + + \param pSource + If not \c NULL, then it specifies the central directory for sharing. + + \note + Throws exceptions. + + */ + void Init(CZipStorage* pStorage, ZipArchiveLib::CZipCallbackProvider* pCallbacks, CZipStringStoreSettings* pStringSettings, CZipCentralDir* pSource = NULL); + + /** + Reads the central directory from the archive. + + \param bExhaustiveRead + \c true, if the exhaustive read should be performed, \c false otherwise. + + \note + Throws exceptions. + + \see + CZipArchive::SetExhaustiveRead + */ + void Read(bool bExhaustiveRead); + + /** + Opens the file with the given index. + + \param uIndex + A zero-based index of the file to open. + + \note + Throws exceptions. + */ + void OpenFile(ZIP_INDEX_TYPE uIndex); + + /** + Tests if the given file index is valid. + + \param uIndex + A zero-based index to test. + + \return + \c true, if the file with the given index exists inside the archive; \c false otherwise. + */ + bool IsValidIndex(ZIP_INDEX_TYPE uIndex)const; + + /** + Removes the file header from the central directory. + + \param pHeader + The header to remove. + + \param uIndex + The index of the header to remove. Use \c ZIP_FILE_INDEX_UNSPECIFIED, if the index is not known. + + \param bShift + If \c true, the data inside the archive is moved over the hole created after removing the file. + If \c false, the unused area inside the archive remains. + + \note + Throws exceptions. + */ + void RemoveFile(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex = ZIP_FILE_INDEX_UNSPECIFIED, bool bShift = true); + + + /** + Removes last file from the central directory. + + \param pHeader + The header to remove. + + \param uIndex + The index of the header to remove. Use \c ZIP_FILE_INDEX_UNSPECIFIED, if the index is not known. + + */ + void RemoveLastFile(CZipFileHeader* pHeader = NULL, ZIP_INDEX_TYPE uIndex = ZIP_FILE_INDEX_UNSPECIFIED); + + /** + Removes all files. + + \note + Throws exceptions. + */ + void RemoveAll(); + + /** + Closes the central directory. + */ + void Close(); + + /** + Adds a new file to the central directory. + + \param header + Used as a template for the data stored inside the archive. + + \param uReplaceIndex + The index of the file to be replaced. Use \c ZIP_FILE_INDEX_UNSPECIFIED, if the index is not known. + + \param iLevel + The compression level. + + \param bRichHeaderTemplateCopy + \c true, if copy crc and sizes values from \a header; \c false otherwise. + + \return + The new header. + + \note + Throws exceptions. + */ + CZipFileHeader* AddNewFile(const CZipFileHeader & header, ZIP_INDEX_TYPE uReplaceIndex, int iLevel, bool bRichHeaderTemplateCopy = false); + + /** + Removes physically the central directory from the archive. + + \note + Throws exceptions. + */ + void RemoveFromDisk(); + + /** + Gets the central directory size. + \param bWhole + If \c true, include the size of the file headers. + If \c false, the size of the file headers is not included. + + \return + The size of the central directory. + + \see + CZipArchive::GetCentralDirSize + */ + ZIP_SIZE_TYPE GetSize(bool bWhole = false) const; + + /** + Closes a file opened for reading inside the archive. + \param skipCheckingDataDescriptor + If \c true, the data descriptor that is located after the compressed data in the archive is checked for validity. + Set this value to \c false after closing the file after an exception was thrown. + + \note + Throws exceptions. + */ + void CloseFile(bool skipCheckingDataDescriptor = false); + + /** + Closes a file opened for reading inside the archive. + + \note + Throws exceptions. + */ + void CloseNewFile(); + + /** + Writes the central directory to the archive. + + \note + Throws exceptions. + */ + void Write(); + + /** + Enables Find Fast. + + \see + CZipArchive::EnableFindFast + */ + void EnableFindFast(bool bEnable, bool bCaseSensitive); + + /** + Searches for the file. + + \see + CZipArchive::FindFile + */ + ZIP_INDEX_TYPE FindFile(LPCTSTR lpszFileName, bool bCaseSensitive, bool bSporadically, bool bFileNameOnly); + + + /** + Gets the Find Fast index. + + \see + CZipArchive::GetFindFastIndex + */ + ZIP_INDEX_TYPE GetFindFastIndex(ZIP_INDEX_TYPE uFindFastIndex)const + { + if (!IsValidIndex(uFindFastIndex) || !m_pInfo->m_bFindFastEnabled) + return ZIP_FILE_INDEX_NOT_FOUND; + + return (*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)uFindFastIndex]->m_uIndex; + } + + /** + Points to CZipArchive::m_storage. + */ + CZipStorage* m_pStorage; + + /** + Points to the current callback provider. + */ + ZipArchiveLib::CZipCallbackProvider* m_pCallbacks; + + /** + Gets the information about the file with the given index. + + \see + CZipArchive::operator[](ZIP_INDEX_TYPE) + */ + CZipFileHeader* operator[](ZIP_INDEX_TYPE uIndex) + { + return (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)uIndex]; + } + + /** + Gets the information about the file with the given index. + + \see + CZipArchive::operator[](ZIP_INDEX_TYPE) const + */ + const CZipFileHeader* operator[](ZIP_INDEX_TYPE uIndex) const + { + return (*m_pHeaders)[(ZIP_ARRAY_SIZE_TYPE)uIndex]; + } + + /** + Gets the number of files in the archive. + + \return + The number of files in the archive. + + */ + ZIP_ARRAY_SIZE_TYPE GetCount() const + { + return m_pHeaders == NULL ? 0 : m_pHeaders->GetSize(); + } + + /** + Sets the global comment. + + \see + CZipArchive::SetGlobalComment + */ + void SetComment(LPCTSTR lpszComment); + + /** + Gets the global comment. + + \see + CZipArchive::GetGlobalComment + */ + void GetComment(CZipString& szComment) const + { + ZipCompatibility::ConvertBufferToString(szComment, m_pInfo->m_pszComment, m_pStringSettings->m_uCommentCodePage); + } + + /** + Sets the file comment. + + \see + CZipArchive::SetFileComment + */ + bool SetFileComment(ZIP_INDEX_TYPE uIndex, LPCTSTR lpszComment); + + + /** + Finds the index of the file with the given name. + + \param lpszFileName + The name of the file to find. + + \return + The index in CZipCentralDir::m_pFindArray with the corresponding CZipFindFast structure + or \c ZIP_FILE_INDEX_NOT_FOUND, if there is no such file with the given name. + + \see + CZipArchive::FindFile + */ + ZIP_INDEX_TYPE FindFileNameIndex(LPCTSTR lpszFileName) const; + + /** + Gets the information about the central directory. + + \see + CZipArchive::GetCentralDirInfo + */ + void GetInfo(CInfo& info) const {info = *m_pInfo;} + + /** + Gets a value indicating whether the Find Fast feature is enabled or not. + + \return + The value of CInfo::m_bFindFastEnabled. + */ + bool IsFindFastEnabled(){return m_pInfo->m_bFindFastEnabled;} + + /** + Rebuilds the CZipCentralDir::m_pFindArray array. + */ + void RebuildFindFastArray() + { + if (m_pInfo->m_bFindFastEnabled) + BuildFindFastArray(m_pInfo->m_bCaseSensitive); + } + + /** + The current string store settings. + + \see + SetStringStoreSettings + */ + CZipStringStoreSettings* m_pStringSettings; + + /** + Consistency checks to ignore. Can be one or more of the CZipArchive::ConsistencyCheck values. + \see + CZipArchive::SetIgnoredConsistencyChecks + */ + int m_iIgnoredChecks; + + /** + Checks if the specified consistency check should be performed or not. + \param iLevel + The level to check. Can be one or more of CZipArchive::ConsistencyCheck values. + + \return + \c true, if the specified check should be performed; \c false otherwise. + + \see + m_iIgnoredChecks + */ + bool IsConsistencyCheckOn(int iLevel) + { + // check, if not ignored + return (m_iIgnoredChecks & iLevel) == 0; + } + + +protected: + + +#if _MSC_VER > 1000 + #pragma warning( push ) + #pragma warning (disable : 4702) // unreachable code +#endif + + /** + The method used in comparison when sorting headers. + */ + static int CompareHeaders(const void *pArg1, const void *pArg2) + { + CZipFileHeader* pw1 = *(CZipFileHeader**)pArg1; + CZipFileHeader* pw2 = *(CZipFileHeader**)pArg2; + if (pw1 == pw2) + return 0; + + if (pw1->m_uVolumeStart == pw2->m_uVolumeStart) + { + if (pw1->m_uOffset < pw2->m_uOffset) + return -1; + else if (pw1->m_uOffset > pw2->m_uOffset) + return 1; + ASSERT(FALSE); + + + // two files with the same offsets in the same volume??? + CZipException::Throw(CZipException::badZipFile); + return 0; // just for the compiler comfort (and discomfort of another) + } + else if (pw1->m_uVolumeStart < pw2->m_uVolumeStart) + return -1; + else // if (pw1->m_uVolumeStart > pw2->m_uVolumeStart) + return 1; + } + +#if _MSC_VER > 1000 + #pragma warning( pop ) +#endif + + static int CompareFindFastCollate(const void* pArg1, const void* pArg2) + { + CZipFindFast* pHeader1 = *(CZipFindFast**)pArg1; + CZipFindFast* pHeader2 = *(CZipFindFast**)pArg2; + return pHeader1->m_pHeader->GetFileName().Collate(pHeader2->m_pHeader->GetFileName()); + } + + static int CompareFindFastCollateNoCase(const void* pArg1, const void* pArg2) + { + CZipFindFast* pHeader1 = *(CZipFindFast**)pArg1; + CZipFindFast* pHeader2 = *(CZipFindFast**)pArg2; + return pHeader1->m_pHeader->GetFileName().CollateNoCase(pHeader2->m_pHeader->GetFileName()); + } + + /** + Holds the information about all the files inside the archive. + + \see + CZipFileHeader + */ + CZipArray* m_pHeaders; + + + /** + Builds the CZipCentralDir::m_pFindArray array. + */ + void BuildFindFastArray( bool bCaseSensitive ); + + void ClearFindFastArray() + { + ZIP_ARRAY_SIZE_TYPE uCount = m_pFindArray->GetSize(); + for (ZIP_ARRAY_SIZE_TYPE i = 0; i < uCount; i++) + delete (*m_pFindArray)[i]; + m_pFindArray->RemoveAll(); + } + + /** + The Find Fast array. + + \see + CZipFindFast + \see + CInfo::m_bFindFastEnabled + \see + CZipArchive::FindFile + */ + CZipArray* m_pFindArray; + + + /** + The method used in comparison involving the Find Fast feature. + + \param lpszFileName + The name of the file. + + \param uIndex + The index from the CZipCentralDir::m_pFindArray array. + + \return + The return value has the following meaning: + - 0 if the filenames are the same + - < 0 if the filename stored in the array is less than \a lpszFileName + - > 0 if the filename stored in the array is greater than \a lpszFileName + */ + int CompareElement(LPCTSTR lpszFileName, ZIP_INDEX_TYPE uIndex) const + { + return ((*m_pFindArray)[(ZIP_ARRAY_SIZE_TYPE)uIndex]->m_pHeader->GetFileName().*(m_pInfo->m_pCompare))(lpszFileName); + } + + /** + Inserts a new CZipFindFast element to the CZipCentralDir::m_pFindArray array + Initializes the CZipFindFast object with \a pHeader and \a uIndex values. + + \param pHeader + The element to insert. + + \param uIndex + The original index of \a pHeader in the central directory. + If set to \c ZIP_FILE_INDEX_UNSPECIFIED, it is assumed to be the last element. + + \return + The index in the CZipCentralDir::m_pFindArray array. + */ + ZIP_INDEX_TYPE InsertFindFastElement(CZipFileHeader* pHeader, ZIP_INDEX_TYPE uIndex); + + + /** + The central directory information. + + \see + CInfo + */ + CInfo* m_pInfo; + + /** + Reads file headers from the archive. + + \param bExhaustiveRead + \c true, if the exhaustive read should be performed, \c false otherwise. + + \note + Throws exceptions. + + \see + CZipArchive::SetExhaustiveRead + */ + void ReadHeaders(bool bExhaustiveRead); + + /** + Frees the memory allocated for the CZipFileHeader structures. + */ + void RemoveHeaders(); + + /** + Removes data descriptors from a segmented archive that turned out to be one-segment only. + It is not called for encrypted files. + + \param bFromBuffer + If \c true, removes from the write buffer in memory otherwise from the file on the disk. + + \return + \c false, if the file mapping to memory was not successful + (can happen only when \a bFromBuffer is \c false); \c true otherwise. + + \note + Throws exceptions. + */ + bool RemoveDataDescr(bool bFromBuffer); + + /** + Writes the file headers to the archive. + \note + Throws exceptions. + */ + void WriteHeaders(bool bOneDisk); + + /** + Writes the End of Central Directory Record. + + \return + The size of the record. + + \note + Throws exceptions. + */ + void WriteCentralEnd(); + + + /** + Throws an exception with the given code. + */ + void ThrowError(int err) const; + + /** + Creates data that can be shared between different archive objects. + + \see + DestroySharedData + */ + void CreateSharedData(); + + /** + Destroys data shared between different archive objects, if the usage reference count + of the data is zero. + + \note + Throws exceptions. + + \see + CreateSharedData + */ + void DestroySharedData(); + +#ifdef ZIP_ARCHIVE_USE_LOCKING + /** + Locks the access to the shared data. + + \note + Throws exceptions. + + \see + UnlockAccess + \see + CreateSharedData + */ + void LockAccess() + { + + ASSERT(m_pInfo); + m_pInfo->m_mutex.Lock(); + } + + /** + Unlocks the access to the shared data. + + \note + Throws exceptions. + + \see + LockAccess + \see + CreateSharedData + */ + void UnlockAccess() + { + if (m_pInfo) + m_pInfo->m_mutex.Unlock(); + } +#endif + +}; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + + +#endif // !defined(ZIPARCHIVE_ZIPCENTRALDIR_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipCollections.h b/harbour/contrib/hbziparch/ZipCollections.h new file mode 100644 index 0000000000..39bef29c21 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCollections.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipCollections.h +* Includes the collections classes used by the ZipArchive Library. +* +*/ + + +#ifndef ZIPARCHIVE_ZIPCOLLECTIONS_DOT_H +#define ZIPARCHIVE_ZIPCOLLECTIONS_DOT_H + +#if _MSC_VER > 1000 + #pragma once +#endif + +#include "_platform.h" +#include "ZipExport.h" + +#ifdef ZIP_ARCHIVE_STL + #include "ZipCollections_stl.h" +#else + #include "ZipCollections_mfc.h" +#endif + +typedef CZipArray CZipIndexesArray; + +#endif /* ZIPARCHIVE_ZIPCOLLECTIONS_DOT_H */ + diff --git a/harbour/contrib/hbziparch/ZipCollections_mfc.h b/harbour/contrib/hbziparch/ZipCollections_mfc.h new file mode 100644 index 0000000000..51890571ea --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCollections_mfc.h @@ -0,0 +1,91 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPCOLLECTIONS_DOT_H + #error Do not include this file directly. Include ZipCollections.h instead +#endif + +#if _MSC_VER > 1000 + #pragma warning( push ) + #pragma warning (disable:4786) // 'identifier' : identifier was truncated to 'number' characters in the debug information +#endif + +#include + +#define ZIP_ARRAY_SIZE_TYPE INT_PTR + +typedef CStringArray CZipStringArray; + +template +class CZipArray : public CArray +{ +public: + typedef int (*CompareFunction)(const void* pArg1, const void* pArg2); +private: + static int CompareAsc(const void *pArg1, const void *pArg2) + { + TYPE w1 = *(TYPE*)pArg1; + TYPE w2 = *(TYPE*)pArg2; + return w1 == w2 ? 0 :(w2 > w1 ? - 1 : 1); + } + static int CompareDesc(const void *pArg1, const void *pArg2) + { + TYPE w1 = *(TYPE*)pArg1; + TYPE w2 = *(TYPE*)pArg2; + return w1 == w2 ? 0 :(w1 > w2 ? - 1 : 1); + } +public: + void Sort(bool bAscending) + { + Sort(bAscending ? CompareAsc : CompareDesc); + } + void Sort(CompareFunction pFunction) + { + INT_PTR uSize = GetSize(); + if (!uSize) // if ommitted operator [] will fail if empty + return; + qsort((void*)&((*this)[0]), (size_t)uSize , sizeof(TYPE), pFunction); + } +}; + +template +class CZipPtrList : public CTypedPtrList +{ +public: + typedef POSITION iterator; + typedef POSITION const_iterator; + + bool IteratorValid(const iterator &iter) const + { + return iter != NULL; + } + +}; + +template +class CZipMap : public CMap +{ +public: + typedef POSITION iterator; + typedef POSITION const_iterator; + + bool IteratorValid(const iterator &iter) const + { + return iter != NULL; + } +}; + +#if _MSC_VER > 1000 + #pragma warning( pop ) +#endif \ No newline at end of file diff --git a/harbour/contrib/hbziparch/ZipCollections_stl.h b/harbour/contrib/hbziparch/ZipCollections_stl.h new file mode 100644 index 0000000000..336b9328c8 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCollections_stl.h @@ -0,0 +1,226 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPCOLLECTIONS_DOT_H + #error Do not include this file directly. Include ZipCollections.h instead +#endif + +#if _MSC_VER > 1000 + #pragma warning( push, 3 ) // STL + #pragma warning (disable : 4284) //return type for 'identifier::operator >' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation + #pragma warning (disable : 4018) //'expression' : signed/unsigned mismatch +#endif + +#include +#include +#include +#include +#include +#include "ZipString.h" +#include "ZipException.h" + +#define ZIP_ARRAY_SIZE_TYPE size_t + +template +class CZipArray : private std::vector +{ +public: + typedef int (*CompareFunction)(const void* pArg1, const void* pArg2); +private: + struct Sorter + { + CompareFunction m_pFunction; + Sorter(CompareFunction pFunction) + { + m_pFunction = pFunction; + } + bool operator ()(TYPE const& t1, TYPE const& t2) + { + return (*m_pFunction)(&t1, &t2) < 0; + } + }; +public: + typedef typename std::vector::iterator iterator; + typedef typename std::vector inherited; +protected: + iterator GetIterFromIndex(size_t uIndex) + { + iterator iter = this->begin(); + iter += uIndex; + // int t = 0; while (t != uIndex) {iter++;t++;} + return iter; + } +public: + void Sort(bool bAscending) + { + if (bAscending) + std::sort (this->begin(), this->end(), std::less()); + else + std::sort (this->begin(), this->end(), std::greater()); + } + void Sort(CompareFunction pFunction) + { + std::sort(this->begin(), this->end(), Sorter(pFunction)); + } + + + size_t GetSize() const{return this->size(); } + size_t GetCount() const{return this->size(); } + size_t GetUpperBound() const + { + size_t ret = this->size(); + if (ret == 0) + CZipException::Throw(CZipException::outOfBounds); + return ret - 1; + } + TYPE& GetAt(size_t uIndex) {return this->at(uIndex);} + const TYPE& GetAt(size_t uIndex) const {return this->at(uIndex);} + size_t Add(const TYPE& x) {push_back(x);return GetUpperBound();} + void RemoveAll() {this->clear();} + void RemoveAt(size_t uIndex) { erase(GetIterFromIndex(uIndex));} + void InsertAt(size_t uIndex, const TYPE& x){insert(GetIterFromIndex(uIndex), x);} + + TYPE& operator[](size_t uIndex) + { + return inherited::operator[](uIndex); + } + TYPE operator[](size_t uIndex) const + { + return inherited::operator[](uIndex); + } +}; + + +typedef CZipArray CZipStringArray; +typedef CZipArray CZipWordArray; + + +template +class CZipPtrList : private std::list +{ + +public: + typedef typename std::list::iterator iterator; + typedef typename std::list::const_iterator const_iterator; + size_t GetCount() const {return this->size();} + void AddTail(const TYPE& x){push_back(x);} + void AddHead(const TYPE& x){push_front(x);} + void RemoveHead() {this->pop_front();} + void RemoveTail() {this->pop_back();} + void RemoveAll() {this->clear();} + TYPE& GetHead() {return this->front();} + TYPE GetHead() const {return this->front();} + TYPE& GetTail() {return this->back();} + TYPE GetTail() const {return this->back();} + iterator GetHeadPosition() { return this->begin();} + const_iterator GetHeadPosition() const { return this->begin();} + iterator GetTailPosition() { return this->back();} + TYPE& GetNext(iterator& pos) { return *pos++;} + const TYPE GetNext(const_iterator& pos) const{ return *pos++;} + TYPE& GetPrev(iterator& pos) { return *pos--;} + TYPE GetPrev(iterator& pos) const{ return *pos--;} + iterator Find(TYPE& x) { return std::find(this->begin(), this->end(), x);} + void RemoveAt(iterator& pos) { erase(pos);} + bool IteratorValid(const_iterator &iter) const + { + return iter != this->end(); + } + bool IteratorValid(iterator &iter) + { + return iter != this->end(); + } + iterator FindIndex(size_t uIndex) + { + iterator iter = this->begin(); + size_t t = 0; while (t != uIndex) {iter++;t++;} + return iter; + } + const_iterator FindIndex(size_t uIndex) const + { + const_iterator iter = this->begin(); + size_t t = 0; while (t != uIndex) {iter++;t++;} + return iter; + } + TYPE& GetAt(const iterator& pos) { return *pos;} + TYPE GetAt(const_iterator& pos) const{ return *pos;} + +}; + +// simplified and partial only +template +class CZipMap : private std::map +{ +public: + typedef typename std::map::iterator iterator; + typedef typename std::map::const_iterator const_iterator; + typedef typename std::map, std::allocator > >::value_type v_type; + void SetAt( KEY key, VALUE newValue) + { + insert(v_type(key, newValue)); + } + ZBOOL RemoveKey( KEY key ) + { + return erase(key) != 0; + } + ZBOOL Lookup( KEY key, VALUE& rValue ) const + { +#if (__GNUC__ >= 3) // The actual version number may be different. + const_iterator iter = std::map::find(key); + if (iter == std::map::end()) +#else + const_iterator iter = find(key); + if (iter == end()) +#endif + return FALSE; + else + { + rValue = iter->second; + return TRUE; + } + } + + iterator GetStartPosition() { return this->begin();} + const_iterator GetStartPosition() const { return this->begin();} + + bool IteratorValid(const_iterator &iter) const + { + return iter != this->end(); + } + bool IteratorValid(iterator &iter) + { + return iter != this->end(); + } + + void GetNextAssoc(iterator &iter, KEY& key, VALUE& value) + { + key = iter->first; + value = iter->second; + iter++; + } + + void GetNextAssoc(const_iterator &iter, KEY& key, VALUE& value) + { + key = iter->first; + value = iter->second; + iter++; + } + void RemoveAll() {this->clear();} + +}; + +#if _MSC_VER > 1000 + #pragma warning( pop) +#endif + + diff --git a/harbour/contrib/hbziparch/ZipCompatibility.cpp b/harbour/contrib/hbziparch/ZipCompatibility.cpp new file mode 100644 index 0000000000..a796efa85a --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCompatibility.cpp @@ -0,0 +1,219 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipCompatibility.h" +#include "ZipPlatform.h" +#include "ZipException.h" +#include "ZipAutoBuffer.h" +#include "ZipFileHeader.h" + + +enum iInternalAttr +{ + attROnly = 0x01, + attHidd = 0x02, + attSys = 0x04, + attDir = 0x10, + attArch = 0x20 +}; +// *********************** WINDOWS ************************** +#ifndef _WIN32 + #define FILE_ATTRIBUTE_READONLY 0x00000001 + #define FILE_ATTRIBUTE_HIDDEN 0x00000002 + #define FILE_ATTRIBUTE_SYSTEM 0x00000004 + #define FILE_ATTRIBUTE_DIRECTORY 0x00000010 + #define FILE_ATTRIBUTE_ARCHIVE 0x00000020 +#endif +// *********************** UINX ************************** + +#define USER_PERMISSIONS_MASK 0x01C0 +#define EXTRACT_USER_PERMISSIONS(x) ((x & USER_PERMISSIONS_MASK) >> 6) +#define CREATE_USER_PERMISSIONS(x) ((x & 0x0007) << 6) + +#define GROUP_PERMISSIONS_MASK 0x0038 +#define CREATE_GROUP_PERMISSIONS(x) ((x & 0x0007) << 3) + + +#define OTHER_PERMISSIONS_MASK 0x0007 +#define CREATE_OTHER_PERMISSIONS(x) (x & 0x0007) + +#define UNIX_DIRECTORY_ATTRIBUTE 0x4000 +#define UNIX_FILE_ATTRIBUTE 0x8000 + +#define UNIX_EXEC 1 +#define UNIX_WRITE 2 +#define UNIX_READ 4 + +using namespace ZipCompatibility; + +typedef DWORD(*conv_func)(DWORD , bool ); + +DWORD AttrDos(DWORD , bool ); +DWORD AttrUnix(DWORD, bool); +DWORD AttrMac(DWORD , bool ); + +conv_func conv_funcs[11] = {AttrDos, + NULL, + NULL, + AttrUnix, + NULL, + NULL, + AttrDos, + AttrMac, + NULL, + NULL, + AttrDos +}; + + + +DWORD ZipCompatibility::ConvertToSystem(DWORD uAttr, int iFromSystem, int iToSystem) +{ + if (iToSystem != iFromSystem && iFromSystem < 11 && iToSystem < 11) + { + conv_func p = conv_funcs[iFromSystem], q = conv_funcs[iToSystem]; + if (p && q) + uAttr = q( p(uAttr, true), false); + else + CZipException::Throw(CZipException::platfNotSupp); + } + return uAttr; +} + + +DWORD AttrDos(DWORD uAttr, bool ) +{ + return uAttr; +} + + + +DWORD AttrUnix(DWORD uAttr, bool bFrom) +{ + DWORD uNewAttr = 0; + if (bFrom) + { + bool isDir = (uAttr & UNIX_DIRECTORY_ATTRIBUTE) != 0; + if (isDir) + uNewAttr = attDir; + + uAttr = EXTRACT_USER_PERMISSIONS (uAttr); + + // we may set archive attribute if the file hasn't got the execute permissions + // and is not a directory + if (!isDir && !(uAttr & UNIX_EXEC)) + uNewAttr |= attArch ; + + if (!(uAttr & UNIX_WRITE)) + uNewAttr |= attROnly; + + if (!(uAttr & UNIX_READ)) + uNewAttr |= attHidd; + } + else + { + + uNewAttr = 0; + + // we cannot assume that if the file hasn't the archive attribute set + // then it is executable and set execute permissions + + if (!(uAttr & attHidd)) + uNewAttr |= (CREATE_OTHER_PERMISSIONS (UNIX_READ) | CREATE_GROUP_PERMISSIONS (UNIX_READ)) | + CREATE_USER_PERMISSIONS (UNIX_READ); + + + if (!(uAttr & attROnly)) + uNewAttr |= (CREATE_GROUP_PERMISSIONS (UNIX_WRITE) | CREATE_USER_PERMISSIONS (UNIX_WRITE)); + + if (uAttr & attDir) + { + uNewAttr |= UNIX_DIRECTORY_ATTRIBUTE; + uNewAttr |= (CREATE_OTHER_PERMISSIONS (UNIX_EXEC) | CREATE_GROUP_PERMISSIONS (UNIX_EXEC)) | + CREATE_USER_PERMISSIONS (UNIX_EXEC); + } + else + uNewAttr |= UNIX_FILE_ATTRIBUTE; + + } + + return uNewAttr; +} + +DWORD AttrMac(DWORD uAttr, bool ) +{ + return uAttr & (attDir | attROnly); +} + +// ************************************************************************ +ZIPINLINE bool ZipCompatibility::IsPlatformSupported(int iCode) +{ + return iCode == zcDosFat || iCode == zcUnix || iCode == zcMacintosh + || iCode == zcNtfs || iCode == zcOs2Hpfs; +} + +void ZipCompatibility::ConvertBufferToString(CZipString& szString, const CZipAutoBuffer& buffer, UINT uCodePage) +{ +#ifdef _UNICODE + ZipPlatform::MultiByteToWide(buffer, szString, uCodePage); +#else + // iLen does not include the NULL character + int iLen; + if (uCodePage == CP_OEMCP) + { + CZipAutoBuffer buf; + buf = buffer; + ZipPlatform::AnsiOem(buf, false); + iLen = buf.GetSize(); + memcpy(szString.GetBuffer(iLen), buf.GetBuffer(), iLen); + } + else + { + iLen = buffer.GetSize(); + memcpy(szString.GetBuffer(iLen), buffer.GetBuffer(), iLen); + } + szString.ReleaseBuffer(iLen); +#endif +} + +void ZipCompatibility::ConvertStringToBuffer(LPCTSTR lpszString, CZipAutoBuffer& buffer, UINT uCodePage) +{ +#ifdef _UNICODE + ZipPlatform::WideToMultiByte(lpszString, buffer, uCodePage); +#else + int iLen = (int)strlen(lpszString); + // iLen does not include the NULL character + buffer.Allocate(iLen); + memcpy(buffer, lpszString, (size_t)iLen); + if (uCodePage == CP_OEMCP) + ZipPlatform::AnsiOem(buffer, true); +#endif +} + +void ZipCompatibility::SlashBackslashChg(CZipString& szFileName, bool bReplaceSlash) +{ + TCHAR t1 = _T('\\') /*backslash*/, t2 = _T('/'), c1, c2; + if (bReplaceSlash) + { + c1 = t1; + c2 = t2; + } + else + { + c1 = t2; + c2 = t1; + } + szFileName.Replace(c2, c1); +} diff --git a/harbour/contrib/hbziparch/ZipCompatibility.h b/harbour/contrib/hbziparch/ZipCompatibility.h new file mode 100644 index 0000000000..c590aeea4d --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCompatibility.h @@ -0,0 +1,145 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + + +/** +* \file ZipCompatibility.h +* ZipCompatibility namespace declaration. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPCOMPATIBILITY_DOT_H) +#define ZIPARCHIVE_ZIPCOMPATIBILITY_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +class CZipAutoBuffer; +class CZipFileHeader; + +#include "ZipString.h" + +/** + Includes functions that provide support for the proper conversion of attributes + and filenames between different system platforms. +*/ +namespace ZipCompatibility +{ + /** + The codes of the compatibility of the file attribute information. + + \see + CZipArchive::GetSystemCompatibility + \see + CZipFileHeader::GetSystemCompatibility + \see + ZipPlatform::GetSystemID + */ + enum ZipPlatforms + { + zcDosFat, ///< MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems) + zcAmiga, ///< Amiga + zcVaxVms, ///< VAX/VMS + zcUnix, ///< Unix / Linux + zcVmCms, ///< VM/CMS + zcAtari, ///< Atari ST + zcOs2Hpfs, ///< OS/2 H.P.F.S. + zcMacintosh, ///< Macintosh + zcZsystem, ///< Z-System + zcCpm, ///< CP/M + zcNtfs ///< Windows NTFS + }; + + /** + Checks whether the system with the given code is supported by the ZipArchive Library. + + \param iCode + One of the #ZipPlatforms values to check. + + \return + \c true, if supported; \c false otherwise. + */ + bool IsPlatformSupported(int iCode); + + /** + Converts the system attributes between different system platforms. + + \param uAttr + The attributes to convert. + + \param iFromSystem + The system code to convert \a uAttr from. + + \param iToSystem + The system code to convert \a uAttr to. + + \return + The converted attributes. + + \note + Throws exceptions. + + \see + ZipPlatforms + */ + DWORD ConvertToSystem(DWORD uAttr, int iFromSystem, int iToSystem); + + /** + Converts the string stored in \a buffer using the given code page. + + \param buffer + The buffer to convert the string from. + + \param szString + The string to receive the result. + + \param uCodePage + The code page used in conversion. + + \see + 0610051525 + */ + void ConvertBufferToString(CZipString& szString, const CZipAutoBuffer& buffer, UINT uCodePage); + + /** + Converts the \a lpszString using the given code page. + + \param lpszString + The string to convert from. + + \param buffer + The buffer to receive the result. + + \param uCodePage + The code page used in conversion. + + \see + 0610051525 + */ + void ConvertStringToBuffer(LPCTSTR lpszString, CZipAutoBuffer& buffer, UINT uCodePage); + + /** + Changes the path separators from slash to backslash or vice-versa in \a szFileName. + + \param szFileName + The filename to have the path separators changed. + + \param bReplaceSlash + If \c true, changes slash to backslash. If \c false, changes backslash to slash. + */ + void SlashBackslashChg(CZipString& szFileName, bool bReplaceSlash); +}; + +#endif // !defined(ZIPARCHIVE_ZIPCOMPATIBILITY_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipCompressor.cpp b/harbour/contrib/hbziparch/ZipCompressor.cpp new file mode 100644 index 0000000000..3a59a2cab1 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCompressor.cpp @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipCompressor.h" +#include "BytesWriter.h" +#include "DeflateCompressor.h" + +using namespace ZipArchiveLib; + +CZipCompressor* CZipCompressor::CreateCompressor(WORD uMethod, CZipStorage* pStorage) +{ + if (uMethod == methodStore || uMethod == methodDeflate) + return new CDeflateCompressor(pStorage); + return NULL; +} + +void CZipCompressor::UpdateFileCrc(const void *pBuffer, DWORD uSize) +{ + m_pFile->m_uCrc32 = zarch_crc32(m_pFile->m_uCrc32, (zarch_Bytef*)pBuffer, uSize); +} + +void CZipCompressor::UpdateCrc(const void *pBuffer, DWORD uSize) +{ + m_uCrc32 = zarch_crc32(m_uCrc32, (zarch_Bytef*)pBuffer, uSize); +} + +void CZipCompressor::UpdateOptions(const COptionsMap& optionsMap) +{ + const COptions* pOptions = GetOptions(); + if (pOptions == NULL) + return; + const COptions* pNewOptions = optionsMap.Get(pOptions->GetType()); + if (pNewOptions != NULL) + UpdateOptions(pNewOptions); +} + +void CZipCompressor::InitBuffer() +{ + // This should be greated that 64k for deflate when creating offsets pairs is enabled + // otherwise deflate will not be able to write one block in one go and will never report + // a flushed block for low-compressable data + const COptions* pOptions = GetOptions(); + DWORD bufferSize = 0; + if (pOptions != NULL) + bufferSize = pOptions->m_iBufferSize; + if (bufferSize == 0) + bufferSize = COptions::cDefaultBufferSize; + m_pBuffer.Allocate(bufferSize); +} + + +void CZipCompressor::COptionsMap::Set(const CZipCompressor::COptions* pOptions) +{ + if (pOptions == NULL) + return; + int iType = pOptions->GetType(); + Remove(iType); + SetAt(iType, pOptions->Clone()); +} + +CZipCompressor::COptions* CZipCompressor::COptionsMap::Get(int iType) const +{ + COptions* pTemp = NULL; + if (Lookup(iType, pTemp)) + return pTemp; + else + return NULL; +} + +void CZipCompressor::COptionsMap::Remove(int iType) +{ + COptions* pTemp = Get(iType); + if (pTemp != NULL) + { + delete pTemp; + RemoveKey(iType); + } +} + +CZipCompressor::COptionsMap::~COptionsMap() +{ + COptionsMap::iterator iter = GetStartPosition(); + while (IteratorValid(iter)) + { + COptions* pOptions = NULL; + int iType = 0; + GetNextAssoc(iter, iType, pOptions); + delete pOptions; + } + RemoveAll(); +} + diff --git a/harbour/contrib/hbziparch/ZipCompressor.h b/harbour/contrib/hbziparch/ZipCompressor.h new file mode 100644 index 0000000000..a55b4e0583 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCompressor.h @@ -0,0 +1,485 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipCompressor.h +* Includes the CZipCompressor class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPCOMPRESSOR_DOT_H) +#define ZIPARCHIVE_ZIPCOMPRESSOR_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #pragma warning( push ) + #pragma warning (disable : 4100) // unreferenced formal parameter +#endif + +#include "ZipExport.h" +#include "ZipAutoBuffer.h" +#include "ZipFileHeader.h" +#include "ZipStorage.h" +#include "ZipCryptograph.h" +#include "ZipException.h" + +/** + A base class for compressors used in compression and decompression of data. +*/ +class ZIP_API CZipCompressor +{ +protected: + CZipStorage* m_pStorage; ///< The current storage object. + CZipAutoBuffer m_pBuffer; ///< A buffer that receives compressed data or provides data for decompression. + CZipCryptograph* m_pCryptograph; ///< Current cryptograph. + CZipFileHeader* m_pFile; ///< The file header being compressed or decompressed. + + + /** + Initializes a new instance of the CZipCompressor class. + + \param pStorage + The current storage object. + */ + CZipCompressor(CZipStorage* pStorage) + :m_pStorage(pStorage) + { + m_pCryptograph = NULL; + m_uUncomprLeft = 0; + m_uComprLeft = 0; + m_uCrc32 = 0; + } + +public: + /** + The type of a compressor. + */ + enum CompressorType + { + typeDeflate = 1, ///< Deflate compression (default in zip archives). + typeBzip2 ///< Bzip2 compression. + }; + + /** + The compression level. + */ + enum CompressionLevel + { + levelDefault = -1, ///< The default compression level (equals 6 for deflate). + levelStore = 0, ///< No compression used. Data is stored. + levelFastest = 1, ///< The fastest compression. The compression ratio is the lowest (apart from #levelStore). + levelBest = 9 ///< The highest compression ratio. It's usually the slowest. + }; + + /** + The compression method. + */ + enum CompressionMethod + { + methodStore = 0, ///< A file is stored, not compressed. + methodDeflate = 8, ///< The deflate compression method. + /** + A file is compressed using the bzip2 algorithm. + + \see + 0610231446|bzip2 + */ + methodBzip2 = 12, + /** + This value means that WinZip AES encryption is used. + The original compression method is stored in a WinZip extra field. + It is only an informational value - you cannot set it as a compression method. The ZipArchive + Library handles this value internally. + + \see + 0610201627|aes + */ + methodWinZipAes = 99 + }; + + /** + The base class for compressors options. + + \see + 0610231446|options + \see + CZipArchive::SetCompressionOptions + */ + struct ZIP_API COptions + { + + /** + Helper constants. + */ + enum Constants + { + /** + The default size of the buffer used in compression and decompression operations. + */ + cDefaultBufferSize = 2 * 65536 + }; + + COptions() + { + m_iBufferSize = cDefaultBufferSize; + } + + /** + Gets the type of the compressor to which the current options apply. + + \return + The type of the compressor. It can be one of the #CompressorType values. + */ + virtual int GetType() const = 0; + + /** + Clones the current options object. + + \return + The cloned object of the same type as the current object. + */ + virtual COptions* Clone() const = 0; + + /** + The size of the buffer used in compression and decompression operations. + By default it is set to to #cDefaultBufferSize. For the optimal performance of the + deflate algorithm it should be set at least to 128kB. + + \see + CZipArchive::SetAdvanced + */ + int m_iBufferSize; + virtual ~COptions() + { + } + }; + + + /** + A dictionary used for keeping options for different types of compressors. + + \see + CZipArchive::SetCompressionOptions + */ + class ZIP_API COptionsMap : public CZipMap + { + public: + void Set(const COptions* pOptions); + void Remove(int iType); + COptions* Get(int iType) const; + ~COptionsMap(); + }; + + /** + Returns the value indicating whether the given compression method is supported by the ZipArchive Library. + + \param uCompressionMethod + The compression method. Can be one of the #CompressionMethod values. + + \return + \c true, if the compression method is supported, \c false otherwise. + */ + static bool IsCompressionSupported(WORD uCompressionMethod) + { + return uCompressionMethod == methodStore || uCompressionMethod == methodDeflate + ; + } + + ZIP_SIZE_TYPE m_uUncomprLeft; ///< The number of bytes left to decompress. + ZIP_SIZE_TYPE m_uComprLeft; ///< The number of bytes left to compress. + DWORD m_uCrc32; ///< The CRC32 file checksum. + + /** + Returns the value indicating, if the current #CZipCompressor object supports the given compression method. + + \param uMethod + The compression method. Can be one of the #CompressionMethod values. + + \return + \c true, if the compression method is supported; \c false otherwise. + + */ + virtual bool CanProcess(WORD uMethod) = 0; + + + /** + The method called when a new file is opened for compression. + + \param iLevel + The compression level. + + \param pFile + The file being compressed. + + \param pCryptograph + The current CZipCryptograph. Can be \c NULL, if no encryption is used. + + \see + Compress + \see + FinishCompression + */ + virtual void InitCompression(int iLevel, CZipFileHeader* pFile, CZipCryptograph* pCryptograph) + { + InitBuffer(); + m_uComprLeft = 0; + m_pFile = pFile; + m_pCryptograph = pCryptograph; + } + + /** + The method called when a new file is opened for extraction. + + \param pFile + The file being extracted. + + \param pCryptograph + The current CZipCryptograph. Can be \c NULL, if no decryption is used. + + \see + Decompress + \see + FinishDecompression + */ + virtual void InitDecompression(CZipFileHeader* pFile, CZipCryptograph* pCryptograph) + { + InitBuffer(); + m_pFile = pFile; + m_pCryptograph = pCryptograph; + + m_uComprLeft = m_pFile->GetDataSize(false, true); + m_uUncomprLeft = m_pFile->m_uUncomprSize; + m_uCrc32 = 0; + } + + /** + Compresses the given data. + + \param pBuffer + The buffer that holds the data to compress. + + \param uSize + The size of \a pBuffer. + + \see + InitCompression + \see + FinishCompression + */ + virtual void Compress(const void *pBuffer, DWORD uSize) = 0; + + /** + Decompresses the given data. + + \param pBuffer + The buffer that receives the decompressed data. + + \param uSize + The size of \a pBuffer. + + \return + The number of bytes decompressed and written to \a pBuffer. + + \note + This method should be called repeatedly until it returns 0. + + \see + InitDecompression + \see + FinishDecompression + */ + virtual DWORD Decompress(void *pBuffer, DWORD uSize) = 0; + + /** + The method called at the end of the compression process. + + \param bAfterException + Set to \c true, if an exception occurred before or to \c false otherwise. + + \see + InitCompression + \see + Compress + */ + virtual void FinishCompression(bool bAfterException){} + + /** + The method called at the end of the decompression process. + + \param bAfterException + Set to \c true, if an exception occurred before or to \c false otherwise. + + \see + InitDecompression + \see + Decompress + */ + virtual void FinishDecompression(bool bAfterException){} + + /** + Returns the current options of the compressor. + + \return + The current options for the compressor. + + \see + 0610231446|options + \see + CZipArchive::SetCompressionOptions + \see + UpdateOptions + */ + virtual const COptions* GetOptions() const + { + return NULL; + } + + /** + Updates the current options with the options stored in \a optionsMap, + if the appropriate options are present in the map. + + \param optionsMap + The map to get the new options from. + + \see + 0610231446|options + \see + GetOptions + */ + void UpdateOptions(const COptionsMap& optionsMap); + + + virtual ~CZipCompressor() + { + } + + /** + A factory method that creates an appropriate compressor for the given compression method. + + \param uMethod + The compression method to create a compressor for. Can be one of #CompressionMethod values. + + \param pStorage + The current storage object. + */ + static CZipCompressor* CreateCompressor(WORD uMethod, CZipStorage* pStorage); + + +protected: + /** + Updates the current options with the new options. + + \param pOptions + The new options to apply. + */ + virtual void UpdateOptions(const COptions* pOptions) + { + } + /** + Updates CRC value while compression. + + \param pBuffer + A buffer with data for which the CRC value should be updated. + + \param uSize + The size of the buffer. + */ + void UpdateFileCrc(const void *pBuffer, DWORD uSize); + + /** + Updates CRC value while decompression. + + \param pBuffer + A buffer with data for which the CRC value should be updated. + + \param uSize + The size of the buffer. + */ + void UpdateCrc(const void *pBuffer, DWORD uSize); + + /** + Flushes data in the buffer into the storage, encrypting the data if needed. + + \note + Throws exceptions. + */ + void FlushWriteBuffer() + { + if (m_pCryptograph) + m_pCryptograph->Encode(m_pBuffer, (DWORD)m_uComprLeft); + m_pStorage->Write(m_pBuffer, (DWORD)m_uComprLeft, false); + m_uComprLeft = 0; + } + + /** + Initializes the internal buffer. + + \see + ReleaseBuffer + */ + void InitBuffer(); + + /** + Releases the internal buffer. + + \see + InitBuffer + */ + void ReleaseBuffer() + { + m_pBuffer.Release(); + } + + /** + Converts internal error code of the compressor to the ZipArchive Library error code. + + \param iErr + An internal error code. + + \return + A ZipArchive Library error code. + */ + virtual int ConvertInternalError(int iErr) const + { + return iErr; + } + + /** + Throws an exception with a given error code. + + \param iErr + An error code. + + \param bInternal + \c true, if \a iErr is an internal error code and needs a conversion to the ZipArchive Library error code; \c false otherwise. + + \note + Throws exceptions. + + \see + ConvertInternalError + */ + void ThrowError(int iErr, bool bInternal = false) + { + if (bInternal) + iErr = ConvertInternalError(iErr); + CZipException::Throw(iErr, m_pStorage->IsClosed(true) ? _T("") : (LPCTSTR)m_pStorage->m_pFile->GetFilePath()); + } +}; + +#if _MSC_VER > 1000 + #pragma warning( pop ) +#endif + +#endif diff --git a/harbour/contrib/hbziparch/ZipCrc32Cryptograph.cpp b/harbour/contrib/hbziparch/ZipCrc32Cryptograph.cpp new file mode 100644 index 0000000000..990d6f2b85 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCrc32Cryptograph.cpp @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipCrc32Cryptograph.h" + +bool CZipCrc32Cryptograph::InitDecode(CZipAutoBuffer& password, CZipFileHeader& currentFile, CZipStorage& storage) +{ + CryptInitKeys(password); + CZipAutoBuffer buf(ZIPARCHIVE_ENCR_HEADER_LEN); + storage.Read(buf, ZIPARCHIVE_ENCR_HEADER_LEN, false); + BYTE b = 0; + for (int i = 0; i < ZIPARCHIVE_ENCR_HEADER_LEN; i++) + { + b = buf[i]; // only temporary + CryptDecode((char&)b); + } + // check the last byte + return currentFile.IsDataDescriptor() ? + (BYTE(currentFile.m_uModTime >> 8) == b) : (BYTE(currentFile.m_uCrc32 >> 24) == b); +} + +void CZipCrc32Cryptograph::InitEncode(CZipAutoBuffer& password, CZipFileHeader& currentFile, CZipStorage& storage) +{ + CZipAutoBuffer buf(ZIPARCHIVE_ENCR_HEADER_LEN); + // use pseudo-crc since we don't know it yet + CryptInitKeys(password); + srand(UINT(time(NULL))); + // genereate pseudo-random sequence + char c; + char* buffer = (char*)buf; + for (int i = 0; i < ZIPARCHIVE_ENCR_HEADER_LEN - 2; i++) + { + int t1 = rand(); + c = (char)((t1 >> 6) & 0xFF); + if (!c) + c = (char)(t1 & 0xFF); + CryptEncode(c); + buffer[i] = c; + + } + long iCrc = (long)currentFile.m_uModTime << 16; + c = (char)((iCrc >> 16) & 0xFF); + CryptEncode(c); + buffer[ZIPARCHIVE_ENCR_HEADER_LEN - 2] = c; + c = (char)((iCrc >> 24) & 0xFF); + CryptEncode(c); + buffer[ZIPARCHIVE_ENCR_HEADER_LEN - 1] = c; + storage.Write(buf, ZIPARCHIVE_ENCR_HEADER_LEN, false); + currentFile.m_uComprSize += ZIPARCHIVE_ENCR_HEADER_LEN; +} + +void CZipCrc32Cryptograph::CryptInitKeys(CZipAutoBuffer& password) +{ + m_keys[0] = 305419896L; + m_keys[1] = 591751049L; + m_keys[2] = 878082192L; + for (DWORD i = 0; i < password.GetSize(); i++) + CryptUpdateKeys(password[i]); +} + +void CZipCrc32Cryptograph::CryptUpdateKeys(char c) +{ + m_keys[0] = CryptCRC32(m_keys[0], c); + m_keys[1] += m_keys[0] & 0xff; + m_keys[1] = m_keys[1] * 134775813L + 1; + c = char(m_keys[1] >> 24); + m_keys[2] = CryptCRC32(m_keys[2], c); +} + diff --git a/harbour/contrib/hbziparch/ZipCrc32Cryptograph.h b/harbour/contrib/hbziparch/ZipCrc32Cryptograph.h new file mode 100644 index 0000000000..e602c566a8 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCrc32Cryptograph.h @@ -0,0 +1,120 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipCrc32Cryptograph.h +* Includes the CZipCrc32Cryptograph class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPCRC32CRYPTOGRAPH_DOT_H) +#define ZIPARCHIVE_ZIPCRC32CRYPTOGRAPH_DOT_H + +#if _MSC_VER > 1000 + #pragma once +#endif + +#include "zlib/zlib.h" + +#include "ZipCryptograph.h" +#include "ZipFileHeader.h" +#include "ZipStorage.h" + + +#define ZIPARCHIVE_ENCR_HEADER_LEN 12 + +/** + Performs the traditional zip encryption. + + \see + 0610201627|std +*/ +class ZIP_API CZipCrc32Cryptograph : public CZipCryptograph +{ +public: + CZipCrc32Cryptograph(){} + + bool InitDecode(CZipAutoBuffer& password, CZipFileHeader& currentFile, CZipStorage& storage); + void InitEncode(CZipAutoBuffer& password, CZipFileHeader& currentFile, CZipStorage& storage); + void Decode(char* pBuffer, DWORD uSize) + { + for (DWORD i = 0; i < uSize; i++) + CryptDecode(pBuffer[i]); + } + void Encode(char* pBuffer, DWORD uSize) + { + for (DWORD i = 0; i < uSize; i++) + CryptEncode(pBuffer[i]); + } + + bool CanHandle(int iEncryptionMethod) + { + return iEncryptionMethod == CZipCryptograph::encStandard; + } + + /** + See CZipCryptograph::GetEncryptedInfoSizeBeforeData + */ + static DWORD GetEncryptedInfoSizeBeforeData() + { + return ZIPARCHIVE_ENCR_HEADER_LEN; + } + + /** + See CZipCryptograph::GetEncryptedInfoSizeAfterData + */ + static DWORD GetEncryptedInfoSizeAfterData() + { + return 0; + } + + /** + Returns the CRC table. + */ + static const DWORD* GetCRCTable() + { + return zarch_get_crc_table(); + } +private: + + void CryptDecode(char &c) + { + c ^= CryptDecryptByte(); + CryptUpdateKeys(c); + } + + char CryptDecryptByte() + { + int temp = (m_keys[2] & 0xffff) | 2; + return (char)(((temp * (temp ^ 1)) >> 8) & 0xff); + } + void CryptInitKeys(CZipAutoBuffer& password); + void CryptUpdateKeys(char c); + DWORD CryptCRC32(DWORD l, char c) + { + const DWORD *CRC_TABLE = zarch_get_crc_table(); + return CRC_TABLE[(l ^ c) & 0xff] ^ (l >> 8); + } + void CryptEncode(char &c) + { + char t = CryptDecryptByte(); + CryptUpdateKeys(c); + c ^= t; + } + DWORD m_keys[3]; +public: + ~CZipCrc32Cryptograph(){} +}; + +#endif diff --git a/harbour/contrib/hbziparch/ZipCryptograph.cpp b/harbour/contrib/hbziparch/ZipCryptograph.cpp new file mode 100644 index 0000000000..9ec7aa59b7 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCryptograph.cpp @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipCryptograph.h" +#include "ZipAesCryptograph.h" +#include "ZipCrc32Cryptograph.h" + +CZipCryptograph* CZipCryptograph::CreateCryptograph(int iEncryptionMethod) +{ + if (iEncryptionMethod == encNone) + return NULL; + return new CZipCrc32Cryptograph(); +} + + +DWORD CZipCryptograph::GetEncryptedInfoSize(int iEncryptionMethod) +{ + if (iEncryptionMethod != encNone) + { + if (iEncryptionMethod == encStandard) + return CZipCrc32Cryptograph::GetEncryptedInfoSizeBeforeData() + CZipCrc32Cryptograph::GetEncryptedInfoSizeAfterData(); + } + return 0; +} + +DWORD CZipCryptograph::GetEncryptedInfoSizeBeforeData(int iEncryptionMethod) +{ + if (iEncryptionMethod != encNone) + { + if (iEncryptionMethod == encStandard) + return CZipCrc32Cryptograph::GetEncryptedInfoSizeBeforeData(); + } + return 0; +} + + +DWORD CZipCryptograph::GetEncryptedInfoSizeAfterData(int iEncryptionMethod) +{ + if (iEncryptionMethod != encNone) + { + if (iEncryptionMethod == encStandard) + return CZipCrc32Cryptograph::GetEncryptedInfoSizeAfterData(); + } + return 0; +} diff --git a/harbour/contrib/hbziparch/ZipCryptograph.h b/harbour/contrib/hbziparch/ZipCryptograph.h new file mode 100644 index 0000000000..ebe2895e90 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipCryptograph.h @@ -0,0 +1,231 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipCryptograph.h +* Includes the CZipCryptograph class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPCRYPTOGRAPH_DOT_H) +#define ZIPARCHIVE_ZIPCRYPTOGRAPH_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #pragma warning( push ) + #pragma warning (disable : 4100) // unreferenced formal parameter +#endif // _MSC_VER > 1000 + +#include "ZipAutoBuffer.h" +#include "ZipStorage.h" + +class CZipFileHeader; + +/** + The base class for cryptographs used in encryption and decryption of file data. + + \see + 0610201627 +*/ +class ZIP_API CZipCryptograph +{ +public: + + /** + The encryption method. + + \see + 0610201627 + */ + enum EncryptionMethod + { + encStandard, ///< The traditional zip encryption. + encWinZipAes128, ///< WinZip AES 128-bit encryption. + encWinZipAes192, ///< WinZip AES 192-bit encryption. + encWinZipAes256, ///< WinZip AES 256-bit encryption. + encNone = 0xFF ///< Indicates no encryption. + }; + + /** + A factory method that creates an appropriate cryptograph for the given method. + + \param iEncryptionMethod + The encryption method to create a cryptograph for. Can be one of #EncryptionMethod values. + + \return + The new cryptograph. The caller is responsible for destroying the object. + If the method is not supported, creates CZipCrc32Cryptograph. + */ + static CZipCryptograph* CreateCryptograph(int iEncryptionMethod); + + /** + Determines if the given method is one of the WinZip AES encryption method. + + \param iEncryptionMethod + The encryption method to test. Can be one of #EncryptionMethod values. + + \return + \c true, if the method is one the WinZip AES encryption methods; \c false otherwise. + */ + static bool IsWinZipAesEncryption(int iEncryptionMethod) + { + return iEncryptionMethod == encWinZipAes128 || iEncryptionMethod == encWinZipAes192 || iEncryptionMethod == encWinZipAes256; + } + + /** + Returns the total size of the extra data that is added to the compression stream during encryption with the given method. + + \param iEncryptionMethod + The encryption method. Can be one of #EncryptionMethod values. + + \return + The total size of extra data for the given encryption method. + + */ + static DWORD GetEncryptedInfoSize(int iEncryptionMethod); + + /** + Returns the size of the extra data that is added before the compression stream during encryption with the given method. + + \param iEncryptionMethod + The encryption method. Can be one of #EncryptionMethod values. + + \return + The size of extra data at the beginning of the compression stream for the given encryption method. + + */ + static DWORD GetEncryptedInfoSizeBeforeData(int iEncryptionMethod); + + /** + Returns the size of the extra data that is added after the compression stream during encryption with the given method. + + \param iEncryptionMethod + The encryption method. Can be one of #EncryptionMethod values. + + \return + The size of extra data at the end of the compression stream for the given encryption method. + + */ + static DWORD GetEncryptedInfoSizeAfterData(int iEncryptionMethod); + + /** + Determines if the given encryption method is supported by the current compilation of the ZipArchive Library. + + \param iEncryptionMethod + The encryption method to test. Can be one of #EncryptionMethod values. + + \return + \c true, if the method is supported; \c false otherwise. + */ + static bool IsEncryptionSupported(int iEncryptionMethod) + { + return iEncryptionMethod == encStandard; + } + + /** + The method called when an existing file is opened for extraction. + + \param password + The supplied password with the CZipArchive::SetPassword method. + + \param currentFile + The file being decoded and extracted. + + \param storage + The current CZipStorage. + + \return + \c true, if the password is initially considered correct; \c false otherwise. + */ + virtual bool InitDecode(CZipAutoBuffer& password, CZipFileHeader& currentFile, CZipStorage& storage) = 0; + + /** + The method called when a new file is opened for compression. + + \param password + The supplied password with the CZipArchive::SetPassword method. + + \param currentFile + The file being compressed and encoded. + + \param storage + The current CZipStorage. + */ + virtual void InitEncode(CZipAutoBuffer& password, CZipFileHeader& currentFile, CZipStorage& storage) = 0; + + /** + Decodes the given data. + + \param pBuffer + The buffer that holds the data to decode and that receives the results. + + \param uSize + The size of \a pBuffer. + */ + virtual void Decode(char* pBuffer, DWORD uSize) = 0; + + /** + Encodes the given data. + + \param pBuffer + The buffer that holds the data to encode and that receives the results. + + \param uSize + The size of \a pBuffer. + */ + virtual void Encode(char* pBuffer, DWORD uSize) = 0; + + /** + The method called at the end of the decoding process. + + \param currentFile + The file being decoded and extracted. + + \param storage + The current CZipStorage. + */ + virtual void FinishDecode(CZipFileHeader& currentFile, CZipStorage& storage){}; + + /** + The method called at the end of the decoding process. + + \param currentFile + The file being compressed and encoded. + + \param storage + The current CZipStorage. + */ + virtual void FinishEncode(CZipFileHeader& currentFile, CZipStorage& storage){}; + + /** + Returns the value indicating whether the current compressor can handle the given encryption method. + + \param iEncryptionMethod + The encryption method to test. Can be one of #EncryptionMethod values. + + \return + \c true, if the current compressor can handle the given encryption method; \c false otherwise. + */ + virtual bool CanHandle(int iEncryptionMethod) + { + return false; + } + virtual ~CZipCryptograph(){} +}; + +#if _MSC_VER > 1000 + #pragma warning( pop ) +#endif // _MSC_VER > 1000 + +#endif diff --git a/harbour/contrib/hbziparch/ZipException.cpp b/harbour/contrib/hbziparch/ZipException.cpp new file mode 100644 index 0000000000..4ce902a495 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipException.cpp @@ -0,0 +1,279 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipException.h" +#include "zlib/zlib.h" +#include + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// +#if defined _MFC_VER && defined ZIP_ARCHIVE_MFC + IMPLEMENT_DYNAMIC( CZipException, CException) +#endif + +CZipException::CZipException(int iCause, LPCTSTR lpszZipName) +#ifdef _MFC_VER + :CException(TRUE) +#endif +{ + m_iCause = iCause; + + if (lpszZipName) + m_szFileName = lpszZipName; +} + +CZipException::~CZipException() throw() +{ + +} + +// inline void CZipException::Throw(int iZipError, LPCTSTR lpszZipName) +// { +// #ifdef _MFC_VER +// throw new CZipException(iZipError, lpszZipName); +// #else +// CZipException e(iZipError, lpszZipName); +// throw e; +// #endif +// MSVC++: ignore "Unreachable code" warning here, it's due to +// optimizations +// } + + +#ifdef ZIP_ENABLE_ERROR_DESCRIPTION + +ZBOOL CZipException::GetErrorMessage(LPTSTR lpszError, UINT nMaxError, + UINT* ) + +{ + if (!lpszError || !nMaxError) + return FALSE; + CZipString sz = GetErrorDescription(); + if (sz.IsEmpty()) + return FALSE; + UINT iLen = sz.GetLength(); + if (nMaxError - 1 < iLen) + iLen = nMaxError - 1; + LPTSTR lpsz = sz.GetBuffer(iLen); +#if _MSC_VER >= 1400 + #ifdef _UNICODE + wcsncpy_s(lpszError, nMaxError, lpsz, iLen); + #else + strncpy_s(lpszError, nMaxError, lpsz, iLen); + #endif +#else + #ifdef _UNICODE + wcsncpy(lpszError, lpsz, iLen); + #else + strncpy(lpszError, lpsz, iLen); + #endif +#endif + + lpszError[iLen] = _T('\0'); + return TRUE; +} + + +CZipString CZipException::GetErrorDescription() +{ + return GetInternalErrorDescription(m_iCause); +} + + +CZipString CZipException::GetSystemErrorDescription() +{ +#ifdef WIN32 + DWORD x = GetLastError(); + if (x) + { + LPVOID lpMsgBuf; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, x, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, 0, NULL); + CZipString sz = (LPCTSTR)lpMsgBuf; + LocalFree(lpMsgBuf); + return sz; + } +#endif + return GetInternalErrorDescription(errno == 0 ? genericError : errno, true); +} + +CZipString CZipException::GetInternalErrorDescription(int iCause, bool bNoLoop) +{ + CZipString sz; + switch (iCause) + { + case EROFS: + sz = _T("Read-only file system."); + break; + case ESPIPE: + sz = _T("Illegal seek."); + break; + case ENOSPC: + sz = _T("No space left on device."); + break; + case EFBIG: + sz = _T("File too large."); + break; + case EMFILE: + sz = _T("Too many open files."); + break; + case ENFILE: + sz = _T("File table overflow."); + break; + case EINVAL: + sz = _T("Invalid argument."); + break; + case EISDIR: + sz = _T("Is a directory."); + break; + case ENOTDIR: + sz = _T("Not a directory."); + break; + case ENODEV: + sz = _T("No such device."); + break; + case EXDEV: + sz = _T("Cross-device link."); + break; + case EEXIST: + sz = _T("File exists."); + break; + case EFAULT: + sz = _T("Bad address."); + break; + case EACCES: + sz = _T("Permission denied."); + break; + case ENOMEM: + sz = _T("Not enough space."); + break; + case EBADF: + sz = _T("Bad file number."); + break; + case ENXIO: + sz = _T("No such device or address."); + break; + case EIO: + sz = _T("I/O error."); + break; + case EINTR: + sz = _T("Interrupted system call."); + break; + case ENOENT: + sz = _T("No such file or directory."); + break; + case EPERM: + sz = _T("Not super-user."); + break; + case badZipFile: + sz = _T("Damaged or not a zip file."); + break; + case badCrc: + sz = _T("Crc is mismatched."); + break; + case noCallback: + sz = _T("There is no spanned archive callback object set."); + break; + case aborted: + sz = _T("Volume change aborted in a segmented archive."); + break; + case abortedAction: + sz = _T("Action aborted."); + break; + case abortedSafely: + sz = _T("Action aborted safely."); + break; + case nonRemovable: + sz = _T("The device selected for the spanned archive is not removable."); + break; + case tooManyVolumes: + sz = _T("The limit of the maximum volumes reached."); + break; + case tooManyFiles: + sz = _T("The limit of the maximum files in an archive reached."); + break; + case tooLongData: + sz = _T("The filename, the comment or the local or central extra field of the file added to the archive is too long."); + break; + case tooBigSize: + sz = _T("The file size is too large to be supported."); + break; + case badPassword: + sz = _T("An incorrect password set for the file being decrypted."); + break; + case dirWithSize: + sz = _T("The directory with a non-zero size found while testing."); + break; + case internalError: + sz = _T("An internal error."); + break; + case notRemoved: + sz.Format(_T("%s (%s)."), _T("Error while removing a file"), (LPCTSTR)GetSystemErrorDescription()); + break; + case notRenamed: + sz.Format(_T("%s (%s)."), _T("Error while renaming a file"), (LPCTSTR)GetSystemErrorDescription()); + break; + case platfNotSupp: + sz = _T("Cannot create a file for the specified platform."); + break; + case cdirNotFound: + sz = _T("The central directory was not found in the archive (or you were trying to open not the last volume of a segmented archive)."); + break; + case noZip64: + sz = _T("The Zip64 format has not been enabled for the library, but is required to use the archive."); + break; + case noAES: + sz = _T("WinZip AES encryption has not been enabled for the library, but is required to decompress the archive."); + break; +#ifdef ZIP_ARCHIVE_STL + case outOfBounds: + sz = _T("The collection is empty and the bounds do not exist."); + break; +#endif +#ifdef ZIP_ARCHIVE_USE_LOCKING + case mutexError: + sz = _T("Locking or unlocking resources access was unsuccessful."); + break; +#endif + case streamEnd: + sz = _T("Zlib library error (end of stream)."); + break; + case errNo: + sz = GetInternalErrorDescription(errno != errNo ? errno : genericError); + break; + case streamError: + sz = _T("Zlib library error (stream error)."); + break; + case dataError: + sz = _T("Zlib library error (data error)."); + break; + case memError: + sz = _T("Not enough memory."); + break; + case bufError: + sz = _T("Zlib library error (buffer error)."); + break; + case versionError: + sz = _T("Zlib library error (version error)."); + break; + default: + sz = bNoLoop ? _T("Unknown error") :(LPCTSTR) GetSystemErrorDescription(); + } + return sz; +} + +#endif //ZIP_ENABLE_ERROR_DESCRIPTION diff --git a/harbour/contrib/hbziparch/ZipException.h b/harbour/contrib/hbziparch/ZipException.h new file mode 100644 index 0000000000..baff6fbb28 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipException.h @@ -0,0 +1,223 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipException.h +* Includes the CZipException class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPEXCEPTION_DOT_H) +#define ZIPARCHIVE_ZIPEXCEPTION_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#pragma warning( push ) +#pragma warning (disable:4702) // disable "Unreachable code" warning in Throw function in the Release mode + #if defined ZIP_HAS_DLL + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class + #pragma warning( disable : 4275 ) // non dll-interface used as base for dll-interface class + #endif +#endif + + +#include "ZipString.h" +#include "ZipBaseException.h" +#include "ZipExport.h" + +/** + Represents exceptions specific to the ZipArchive Library. + + \see + 0610222049 +*/ +class ZIP_API CZipException : public CZipBaseException +{ +public: + + /** + Throws an exception. + Whether it throws an object or a pointer to it, depends + on the current version (STL or MFC correspondingly). + + \param iCause + The error cause. Takes one of the #ZipErrors values. + + \param lpszZipName + The name of the file where the error occurred (if applicable). + May be \c NULL. + + \see + 0610222049 + */ + static void Throw(int iCause = CZipException::genericError, LPCTSTR lpszZipName = NULL) + { + #ifdef ZIP_ARCHIVE_MFC + throw new CZipException(iCause, lpszZipName); + #else + CZipException e(iCause, lpszZipName); + throw e; + #endif + } + + /** + Initializes a new instance of the CZipException class. + + \param iCause + The error cause. Takes one of the #ZipErrors values. + + \param lpszZipName + The name of the file where the error occurred (if applicable). + May be \c NULL. + */ + CZipException(int iCause = genericError, LPCTSTR lpszZipName = NULL); + + CZipException(CZipException& e) + { + m_szFileName = e.m_szFileName; + m_iCause = e.m_iCause; + } + +#ifdef ZIP_ENABLE_ERROR_DESCRIPTION + + /** + Gets the error description. + + \return + The error description. + */ + CZipString GetErrorDescription(); + + + /** + Gets the error description. This method is provided for compatibility with the MFC version (\c CException::GetErrorMessage). + + \param lpszError + The buffer to receive the error message. + + \param nMaxError + The maximum number of characters \a lpszError can hold, + including the ending \c NULL character. + + \return + \c TRUE if the error string was successfully copied to \a lpszError; \c FALSE otherwise. + + \note + The method will not copy more than \c nMaxError - 1 characters + to the buffer, and it always appends a \c NULL character. + If \a lpszError is too small, the error message will be truncated. + */ + ZBOOL GetErrorMessage(LPTSTR lpszError, UINT nMaxError, UINT* = NULL); + +#endif //ZIP_ENABLE_ERROR_DESCRIPTION + + /** + The name of the zip file where the error occurred. + */ + CZipString m_szFileName; + + /** + The codes of errors thrown by the ZipArchive Library. + */ + enum ZipErrors + { + noError, ///< No error. +// 1 - 42 reserved for errno (from STL) values - used only in non-MFC versions +// 43 - 99 reserved + genericError = 100, ///< An unknown error. + badZipFile, ///< Damaged or not a zip file. + badCrc, ///< Crc is mismatched. + noCallback, ///< There is no spanned archive callback object set. + aborted, ///< The volume change callback in a segmented archive method returned \c false. + abortedAction, ///< The action callback method returned \c false. + abortedSafely, ///< The action callback method returned \c false, but the data is not corrupted. + nonRemovable, ///< The device selected for the spanned archive is not removable. + tooManyVolumes, ///< The limit of the maximum volumes reached. + tooManyFiles, ///< The limit of the maximum files in an archive reached. + tooLongData, ///< The filename, the comment or the local or central extra field of the file added to the archive is too long. + tooBigSize, ///< The file size is too large to be supported. + badPassword, ///< An incorrect password set for the file being decrypted. + dirWithSize, ///< The directory with a non-zero size found while testing. + internalError, ///< An internal error. + notRemoved, ///< Error while removing a file (under Windows call \c GetLastError() to find out more). + notRenamed, ///< Error while renaming a file (under Windows call \c GetLastError() to find out more). + platfNotSupp, ///< Cannot create a file for the specified platform. + cdirNotFound, ///< The central directory was not found in the archive (or you were trying to open not the last disk of a segmented archive). + noZip64, ///< The Zip64 format has not been enabled for the library, but is required to use the archive. + noAES, ///< WinZip AES encryption has not been enabled for the library, but is required to decompress the archive. +#ifdef ZIP_ARCHIVE_STL + outOfBounds, ///< The collection is empty and the bounds do not exist. +#endif +#ifdef ZIP_ARCHIVE_USE_LOCKING + mutexError, ///< Locking or unlocking resources access was unsuccessful. +#endif + streamEnd = 500, ///< Zlib library error. + needDict, ///< Zlib library error. + errNo, ///< Zlib library error. + streamError, ///< Zlib library error. + dataError, ///< Zlib library error. + memError, ///< Zlib library or \c CZipMemFile error. + bufError, ///< Zlib library error. + versionError, ///< Zlib library error. + }; + + /** + The error code - takes one of the CZipException::ZipErrors values. + */ + int m_iCause; + + virtual ~CZipException() throw(); + +protected: + +#ifdef ZIP_ENABLE_ERROR_DESCRIPTION + + /** + Gets the error description. + + \param iCause + The error cause. Takes one of the #ZipErrors values. + + \param bNoLoop + If \c true, does not search for en error description, it the error code is #genericError. + + \return + The error description. + */ + CZipString GetInternalErrorDescription(int iCause, bool bNoLoop = false); + + + /** + Gets the error description based on system variables. + + \return + The error description. + */ + CZipString GetSystemErrorDescription(); + + +#endif //ZIP_ENABLE_ERROR_DESCRIPTION + +#if defined _MFC_VER && defined ZIP_ARCHIVE_MFC + DECLARE_DYNAMIC(CZipException) +#endif +}; + +#if _MSC_VER > 1000 + #pragma warning( pop ) +#endif + +#endif // !defined(ZIPARCHIVE_ZIPEXCEPTION_DOT_H) + + diff --git a/harbour/contrib/hbziparch/ZipExtraData.cpp b/harbour/contrib/hbziparch/ZipExtraData.cpp new file mode 100644 index 0000000000..37c3b4a412 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipExtraData.cpp @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipArchive.h" +#include "ZipExtraData.h" +#include "BytesWriter.h" + +using namespace ZipArchiveLib; + +bool CZipExtraData::Read(char* buffer, WORD uSize) +{ + if (uSize < 4) + return false; + WORD size; + CBytesWriter::ReadBytes(m_uHeaderID, buffer); + CBytesWriter::ReadBytes(size, buffer + 2); + if (uSize - 4 < size) + return false; + m_data.Allocate(size); + memcpy(m_data, buffer + 4, size); + return true; +} + +WORD CZipExtraData::Write(char* buffer)const +{ + CBytesWriter::WriteBytes(buffer, m_uHeaderID); + WORD size = (WORD)m_data.GetSize(); + CBytesWriter::WriteBytes(buffer + 2, size); + memcpy(buffer + 4, m_data, size); + return (WORD)(size + 4); +} diff --git a/harbour/contrib/hbziparch/ZipExtraData.h b/harbour/contrib/hbziparch/ZipExtraData.h new file mode 100644 index 0000000000..00a17ac73b --- /dev/null +++ b/harbour/contrib/hbziparch/ZipExtraData.h @@ -0,0 +1,158 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipExtraData.h +* Includes the CZipExtraData class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPEXTRADATA_DOT_H) +#define ZIPARCHIVE_ZIPEXTRADATA_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "ZipExport.h" +#include "ZipAutoBuffer.h" +#include "ZipExtraField.h" +#include "memory.h" + +/** + Represents a single data record in an extra field. + + \see + 0610242300 +*/ +class ZIP_API CZipExtraData +{ + friend class CZipExtraField; +public: + + /** + The custom data contained by this record. + */ + CZipAutoBuffer m_data; + + CZipExtraData() + { + m_uHeaderID = 0; + } + + CZipExtraData(const CZipExtraData& extra) + { + *this = extra; + } + + /** + Initializes a new instance of the CZipExtraData class. + + \param uHeaderID + The unique ID of the data. + */ + CZipExtraData(WORD uHeaderID) + { + m_uHeaderID = uHeaderID; + } + + CZipExtraData& operator=(const CZipExtraData& extra) + { + m_uHeaderID = extra.m_uHeaderID; + DWORD uSize = extra.m_data.GetSize(); + m_data.Allocate(uSize); + if (uSize > 0) + memcpy(m_data, extra.m_data, uSize); + return *this; + } + bool operator==(const CZipExtraData& extra) + { + return m_uHeaderID == extra.m_uHeaderID && m_data.GetSize() == extra.m_data.GetSize() && memcmp(m_data, extra.m_data, m_data.GetSize()) == 0; + } + bool operator != (const CZipExtraData& extra) + { + return !(*this == extra); + } + bool operator > (const CZipExtraData& extra) + { + return m_uHeaderID > extra.m_uHeaderID; + } + bool operator < (const CZipExtraData& extra) + { + return m_uHeaderID < extra.m_uHeaderID; + } + bool operator >= (const CZipExtraData& extra) + { + return m_uHeaderID > extra.m_uHeaderID || *this == extra; + } + + bool operator <= (const CZipExtraData& extra) + { + return m_uHeaderID < extra.m_uHeaderID || *this == extra; + } + + /** + Gets the total size, the extra data will occupy in the archive. + + \return + The size in bytes. + */ + int GetTotalSize() const + { + return 4 + m_data.GetSize(); + } + + /** + Gets the data ID. + + \return + The data ID. + */ + WORD GetHeaderID() const + { + return m_uHeaderID; + } + +protected: + + /** + Reads the extra data record from \a buffer. + + \param buffer + The buffer to read the data from. + + \param uSize + The size of the data to read. + + \return + \c false, if \a uSize was smaller than the declared extra data size; \c true otherwise. + */ + bool Read(char* buffer, WORD uSize); + + /** + Writes the extra data record to \a buffer. + + \param buffer + The buffer to write to. + + \return + The total size of extra data in bytes. + */ + WORD Write(char* buffer)const; + +private: + WORD m_uHeaderID; +}; + +#endif // !defined(ZIPARCHIVE_ZIPEXTRADATA_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipExtraField.cpp b/harbour/contrib/hbziparch/ZipExtraField.cpp new file mode 100644 index 0000000000..9882ff132d --- /dev/null +++ b/harbour/contrib/hbziparch/ZipExtraField.cpp @@ -0,0 +1,88 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipExtraField.h" + +bool CZipExtraField::Read(CZipStorage *pStorage, WORD uSize) +{ + if (uSize == 0) + return true; + Clear(); + CZipAutoBuffer buffer; + buffer.Allocate(uSize); + pStorage->Read(buffer, uSize, true); + char* position = (char*) buffer; + do + { + CZipExtraData* pExtra = new CZipExtraData(); + if (!pExtra->Read(position, uSize)) + { + delete pExtra; + return false; + } + int totalSize = pExtra->GetTotalSize(); + if (totalSize > uSize || totalSize < 0) + return false; + position += totalSize; + uSize = (WORD)(uSize - totalSize); + Add(pExtra); + } + while (uSize > 0); + return true; +} + + +void CZipExtraField::Write(char* buffer)const +{ + int offset = 0; + for (int i = 0; i < GetCount(); i++) + offset += GetAt(i)->Write(buffer + offset); +} + +int CZipExtraField::GetTotalSize()const +{ + int total = 0; + for (int i = 0; i < GetCount(); i++) + total += GetAt(i)->GetTotalSize(); + return total; +} + +void CZipExtraField::RemoveInternalHeaders() +{ + for (int i = GetCount() - 1; i >= 0; i--) + { + WORD headerID = GetAt(i)->GetHeaderID(); + if ( + headerID == ZIP_EXTRA_ZARCH_NAME) + RemoveAt(i); + } +} + +CZipExtraData* CZipExtraField::Lookup(WORD headerID, int& index) const +{ + // we can do a non-efficient search here + // usually the number of extra fields is low, if any + for (int i = 0; i < GetCount(); i++) + { + CZipExtraData* pExtra = GetAt(i); + if (pExtra->m_uHeaderID == headerID) + { + index = i; + return pExtra; + } + } + return NULL; +} + diff --git a/harbour/contrib/hbziparch/ZipExtraField.h b/harbour/contrib/hbziparch/ZipExtraField.h new file mode 100644 index 0000000000..6864fd058a --- /dev/null +++ b/harbour/contrib/hbziparch/ZipExtraField.h @@ -0,0 +1,273 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipExtraField.h +* Includes the CZipExtraField class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPEXTRAFIELD_DOT_H) +#define ZIPARCHIVE_ZIPEXTRAFIELD_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "ZipExport.h" +#include "ZipExtraData.h" +#include "ZipCollections.h" +#include "ZipStorage.h" + + +#define ZIP_EXTRA_ZARCH_NAME 0x5A4C // ZL - ZipArchive Library + +#define ZIP_EXTRA_ZARCH_SEEK 0x5A4D + + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class +#endif + +/** + Represents a local or central extra field in a zip archive. + This is a collection of extra data records (CZipExtraData). + + \see + 0610242300 + \see + CZipExtraData +*/ +class ZIP_API CZipExtraField +{ + friend class CZipFileHeader; +public: + CZipExtraField(){} + CZipExtraField(const CZipExtraField& arr) + { + *this = arr; + } + CZipExtraField& operator=(const CZipExtraField& field) + { + Clear(); + for (int i = 0; i < field.GetCount(); i++) + Add(new CZipExtraData(*field.GetAt(i))); + return *this; + } + + /** + Gets the total size, the extra data will occupy in the archive. + + \return + The size in bytes. + */ + int GetTotalSize() const; + + /** + Validates the current size of the extra field. + + \return + \c false, if the size is larger than allowed; \c false otherwise. + */ + bool Validate() const + { + return GetTotalSize() <= USHRT_MAX; + } + + /** + Gets the number of extra data records included in the extra field. + + \return + The number of extra fields included. + */ + int GetCount() const + { + return (int)m_aData.GetSize(); + } + + /** + Gets the extra data record at the given index. + + \param index + The index of extra data record to retrieve. + + \return + The extra data record. + */ + CZipExtraData* GetAt(int index) const + { + return m_aData.GetAt(index); + } + + /** + Removes the extra data record at the given index. + + \param index + The index of the extra data record to remove. + */ + void RemoveAt(int index) + { + delete (GetAt(index)); + m_aData.RemoveAt(index); + } + + /** + Adds a new extra data record to the extra field. + + \param pExtra + The extra data record to add. + + \return + The index of \a pExtra in the internal collection. + */ + int Add(CZipExtraData* pExtra) + { + return (int)m_aData.Add(pExtra); + } + + /** + Creates a new extra data record with the given ID + and adds it to the extra field. + + \param headerID + The extra data ID. + + \return + The created extra data record. + + \see + CZipExtraData::GetHeaderID + */ + CZipExtraData* CreateNew(WORD headerID) + { + int temp; + return CreateNew(headerID, temp); + } + + /** + Creates a new extra data record with the given ID + and adds it to the extra field. + + \param headerID + The extra data ID. + + \param idx + Receives the value of the index of the new + extra data in the internal collection. + + \return + The created extra data record. + + \see + CZipExtraData::GetHeaderID + */ + CZipExtraData* CreateNew(WORD headerID, int& idx) + { + CZipExtraData* pData = new CZipExtraData(headerID); + idx = (int)m_aData.Add(pData); + return pData; + } + + /** + Removes all extra data records from the extra field, + that are internally used by the ZipArchive Library. + */ + void RemoveInternalHeaders(); + + /** + Lookups the extra field for the extra data record with the given ID. + + \param headerID + The ID of the extra data to lookup. + + \return + The found extra data record or \c NULL, if the extra data could not be found. + */ + CZipExtraData* Lookup(WORD headerID) const + { + int temp; + return Lookup(headerID, temp); + } + + /** + Returns the value indicating whether the extra data record with the given ID is present in the extra field. + + \param headerID + The ID of the extra data to check. + + \return + \c true, if the extra data record with the given ID is present in the extra field; \c false otherwise. + */ + bool HasHeader(WORD headerID) + { + return Lookup(headerID) != NULL; + } + + /** + Lookups the extra field for the extra data record with the given ID. + + \param headerID + The ID of the extra data to lookup. + + \param index + Receives the value of the index of the found + extra data in the internal collection. + + \return + The found extra data record or \c NULL, if the extra data could not be found. + */ + CZipExtraData* Lookup(WORD headerID, int& index) const; + ~CZipExtraField() + { + Clear(); + } +protected: + + /** + Removes all extra data records from the extra field. + */ + void Clear() + { + for (int i = 0; i < GetCount(); i++) + delete (GetAt(i)); + m_aData.RemoveAll(); + } + + /** + Reads the extra field from \a buffer. + + \param pStorage + The storage to read the data from. + + \param uSize + The size of the data to read. + + \return + \c false, if \a uSize was smaller than the declared extra field size; \c true otherwise. + */ + bool Read(CZipStorage* pStorage, WORD uSize); + + /** + Writes the extra field to \a buffer. + + \param buffer + The buffer to write to. + */ + void Write(char* buffer) const; +private: + CZipArray m_aData; +}; + + +#endif // !defined(ZIPARCHIVE_ZIPEXTRAFIELD_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipFile.h b/harbour/contrib/hbziparch/ZipFile.h new file mode 100644 index 0000000000..72b218ab2b --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFile.h @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipFile.h +* Includes the CZipFile class. +* +*/ + + +#if !defined(ZIPARCHIVE_ZIPFILE_DOT_H) +#define ZIPARCHIVE_ZIPFILE_DOT_H + +#if _MSC_VER > 1000 + #pragma once +#endif + +#include "_features.h" + +#if defined ZIP_ARCHIVE_STL || defined ZIP_FILE_USES_STL + #include "ZipFile_stl.h" +#else + #include "ZipFile_mfc.h" +#endif + + + +#endif // !defined(ZIPARCHIVE_ZIPFILE_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipFileHeader.cpp b/harbour/contrib/hbziparch/ZipFileHeader.cpp new file mode 100644 index 0000000000..2a091cfc8a --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFileHeader.cpp @@ -0,0 +1,792 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipFileHeader.h" +#include "ZipAutoBuffer.h" +#include "ZipArchive.h" +#include "ZipPlatform.h" +#include "ZipCompatibility.h" +#include + +#include "ZipCrc32Cryptograph.h" +#include "BytesWriter.h" + +#define FILEHEADERSIZE 46 +#define LOCALFILEHEADERSIZE 30 +#define ZIP_EXTRA_ZARCH_NAME_VER 1 + +using namespace ZipArchiveLib; + +char CZipFileHeader::m_gszSignature[] = {0x50, 0x4b, 0x01, 0x02}; +char CZipFileHeader::m_gszLocalSignature[] = {0x50, 0x4b, 0x03, 0x04}; +CZipFileHeader::CZipFileHeader() +{ + m_uExternalAttr = 0;//ZipPlatform::GetDefaultAttributes(); + m_uModDate = m_uModTime = 0; + m_uMethod = CZipCompressor::methodDeflate; + m_uVersionMadeBy = 0; + m_uCrc32 = 0; + // initialize to 0, because on 64 bit platform unsigned long is 8 byte and we are copying only 4 bytes in Read() + m_uComprSize = m_uUncomprSize = m_uOffset = 0; + m_uLocalFileNameSize = 0; + m_uLocalComprSize = m_uLocalUncomprSize = 0; + m_uVolumeStart = 0; + m_pszFileName = NULL; + m_uEncryptionMethod = CZipCryptograph::encNone; + m_bIgnoreCrc32 = false; + m_uFlag = 0; +} + +CZipFileHeader::~CZipFileHeader() +{ + if (m_pszFileName != NULL) + delete m_pszFileName; +} + +bool CZipFileHeader::Read(CZipCentralDir& centralDir, bool bReadSignature) +{ + CZipStorage *pStorage = centralDir.m_pStorage; + WORD uFileNameSize, uCommentSize, uExtraFieldSize; + CZipAutoBuffer buf(FILEHEADERSIZE); + if (bReadSignature) + { + pStorage->Read(buf, FILEHEADERSIZE, true); + if (!VerifySignature(buf)) + return false; + } + else + pStorage->Read((char*)buf + 4, FILEHEADERSIZE - 4, true); + + CBytesWriter::ReadBytes(m_uVersionMadeBy, buf + 4); + CBytesWriter::ReadBytes(m_uVersionNeeded, buf + 6); + CBytesWriter::ReadBytes(m_uFlag, buf + 8); + CBytesWriter::ReadBytes(m_uMethod, buf + 10); + CBytesWriter::ReadBytes(m_uModTime, buf + 12); + CBytesWriter::ReadBytes(m_uModDate, buf + 14); + CBytesWriter::ReadBytes(m_uCrc32, buf + 16); + CBytesWriter::ReadBytes(m_uComprSize, buf + 20, 4); + CBytesWriter::ReadBytes(m_uUncomprSize, buf + 24, 4); + CBytesWriter::ReadBytes(uFileNameSize, buf + 28); + CBytesWriter::ReadBytes(uExtraFieldSize, buf + 30); + CBytesWriter::ReadBytes(uCommentSize, buf + 32); + CBytesWriter::ReadBytes(m_uVolumeStart, buf + 34, 2); + CBytesWriter::ReadBytes(m_uInternalAttr, buf + 36); + CBytesWriter::ReadBytes(m_uExternalAttr, buf + 38); + CBytesWriter::ReadBytes(m_uOffset, buf + 42, 4); + buf.Release(); + + // we may need to modify this later + m_uEncryptionMethod = (BYTE)((m_uFlag & (WORD) 1) != 0 ? CZipCryptograph::encStandard : CZipCryptograph::encNone); + + ZIP_VOLUME_TYPE uCurDsk = pStorage->GetCurrentVolume(); + m_pszFileNameBuffer.Allocate(uFileNameSize); // don't add NULL at the end + pStorage->Read(m_pszFileNameBuffer, uFileNameSize, true); + + if (centralDir.m_pStringSettings->IsStandardNameCodePage()) + m_stringSettings.SetDefaultNameCodePage(GetSystemCompatibility()); + else + m_stringSettings.m_uNameCodePage = centralDir.m_pStringSettings->m_uNameCodePage; + + if (!centralDir.m_pStringSettings->IsStandardCommentCodePage()) + m_stringSettings.m_uCommentCodePage = centralDir.m_pStringSettings->m_uCommentCodePage; + + if (!m_aCentralExtraData.Read(pStorage, uExtraFieldSize)) + return false; + + CZipExtraData* pExtra = m_aCentralExtraData.Lookup(ZIP_EXTRA_ZARCH_NAME); + if (pExtra != NULL) + { + WORD uExtraDataSize = (WORD)pExtra->m_data.GetSize(); + int offset = 1; + if (offset > uExtraDataSize) + return false; + if (pExtra->m_data[0] <= ZIP_EXTRA_ZARCH_NAME_VER) // else don't parse it + { + offset++; + if (offset > uExtraDataSize) + return false; + BYTE flag = pExtra->m_data[1]; + bool bReadCommentCp = (flag & 4) != 0; + if ((flag & 1) != 0) + { + // code page present + if (offset + 4 > uExtraDataSize) + return false; + // avoid warnings + DWORD temp; + CBytesWriter::ReadBytes(temp, pExtra->m_data + offset); + m_stringSettings.m_uNameCodePage = temp; + offset += 4; + } + + if ((flag & 3) == 3) + { + m_stringSettings.m_bStoreNameInExtraData = true; + int iFileNameSize = pExtra->m_data.GetSize() - 2 - 4; + if (bReadCommentCp) + iFileNameSize -= 4; + // code page present + if (offset + iFileNameSize > uExtraDataSize || iFileNameSize <= 0) + return false; + CZipAutoBuffer buffer; + buffer.Allocate(iFileNameSize); + memcpy(buffer, pExtra->m_data + offset, iFileNameSize); + m_pszFileName = new CZipString(_T("")); + ZipCompatibility::ConvertBufferToString(*m_pszFileName, buffer, m_stringSettings.m_uNameCodePage); + offset += iFileNameSize; + m_pszFileNameBuffer.Release(); + } + else + m_stringSettings.m_bStoreNameInExtraData = false; + + if (bReadCommentCp) + { + // code page present + if (offset + 4 > uExtraDataSize) + return false; + DWORD temp; + CBytesWriter::ReadBytes(temp, pExtra->m_data + offset); + m_stringSettings.m_uCommentCodePage = temp; + // offset += 4; + } + } + } + + + if (uCommentSize) + { + m_pszComment.Allocate(uCommentSize); + pStorage->Read(m_pszComment, uCommentSize, true); + } + + return pStorage->GetCurrentVolume() == uCurDsk; // check that the whole header is in one volume +} + + +time_t CZipFileHeader::GetTime()const +{ + struct tm atm; + atm.tm_sec = (m_uModTime & ~0xFFE0) << 1; + atm.tm_min = (m_uModTime & ~0xF800) >> 5; + atm.tm_hour = m_uModTime >> 11; + + atm.tm_mday = m_uModDate & ~0xFFE0; + atm.tm_mon = ((m_uModDate & ~0xFE00) >> 5) - 1; + atm.tm_year = (m_uModDate >> 9) + 80; + atm.tm_isdst = -1; + return mktime(&atm); +} + +// write the header to the central dir +DWORD CZipFileHeader::Write(CZipStorage *pStorage) +{ + m_aCentralExtraData.RemoveInternalHeaders(); + + WORD uMethod = m_uMethod; + + if (!CheckLengths(false)) + CZipException::Throw(CZipException::tooLongData); + + PrepareFileName(); + + + if (m_stringSettings.m_bStoreNameInExtraData) + { + if (m_pszFileName == NULL && m_pszFileNameBuffer.IsAllocated()) + GetFileName(false); // don't clear the buffer, it will be needed in a moment + ASSERT(m_pszFileName != NULL); + if (m_pszFileName->GetLength() == 0) + m_stringSettings.m_bStoreNameInExtraData = false; + } + + int iSystemCompatibility = GetSystemCompatibility(); + if (!m_stringSettings.IsStandard(iSystemCompatibility)) + { + CZipExtraData* pExtra = m_aCentralExtraData.CreateNew(ZIP_EXTRA_ZARCH_NAME); + bool bWriteCommentCp = !m_stringSettings.IsStandardCommentCodePage(); + + BYTE flag = 0; + int offset = 2; + char* data = NULL; + if (m_stringSettings.m_bStoreNameInExtraData) + { + CZipAutoBuffer buffer; + // m_pszFileNameBuffer contains CP_ACP page, we don't check if the current page is CP_ACP - too large dependency on PrepareFileName + ZipCompatibility::ConvertStringToBuffer(*m_pszFileName, buffer, m_stringSettings.m_uNameCodePage); + int size = 2 + 4 + buffer.GetSize(); + if (bWriteCommentCp) + size += 4; + pExtra->m_data.Allocate(size); + data = (char*)pExtra->m_data; + CBytesWriter::WriteBytes(data + offset, (DWORD)m_stringSettings.m_uNameCodePage); + offset += 4; + memcpy(data + offset, buffer, buffer.GetSize()); + offset += buffer.GetSize(); + flag = 3; + } + else if (!m_stringSettings.IsStandardNameCodePage(iSystemCompatibility)) + { + int size = 2 + 4; + if (bWriteCommentCp) + size += 4; + pExtra->m_data.Allocate(size); + data = (char*)pExtra->m_data; + CBytesWriter::WriteBytes(data + offset, (DWORD)m_stringSettings.m_uNameCodePage); + offset += 4; + flag = 1; + } + + if (bWriteCommentCp) + { + if (!pExtra->m_data.IsAllocated()) + { + pExtra->m_data.Allocate(2 + 4); + data = (char*)pExtra->m_data; + } + ASSERT(data); + CBytesWriter::WriteBytes(data + offset, (DWORD)m_stringSettings.m_uCommentCodePage); + flag |= 4; + } + + data[0] = ZIP_EXTRA_ZARCH_NAME_VER; + data[1] = flag; + } + + WORD uFileNameSize = (WORD)m_pszFileNameBuffer.GetSize(), uCommentSize = (WORD)GetCommentSize(), + uExtraFieldSize = (WORD)m_aCentralExtraData.GetTotalSize(); + DWORD uSize = FILEHEADERSIZE + uFileNameSize + uCommentSize + uExtraFieldSize; + CZipAutoBuffer buf(uSize); + char* dest = (char*)buf; + memcpy(dest, m_gszSignature, 4); + CBytesWriter::WriteBytes(dest + 4, m_uVersionMadeBy); + CBytesWriter::WriteBytes(dest + 6, m_uVersionNeeded); + CBytesWriter::WriteBytes(dest + 8, m_uFlag); + CBytesWriter::WriteBytes(dest + 10, uMethod); + CBytesWriter::WriteBytes(dest + 12, m_uModTime); + CBytesWriter::WriteBytes(dest + 14, m_uModDate); + WriteCrc32(dest + 16); + CBytesWriter::WriteBytes(dest + 20, CBytesWriter::WriteSafeU32(m_uComprSize)); + CBytesWriter::WriteBytes(dest + 24, CBytesWriter::WriteSafeU32(m_uUncomprSize)); + CBytesWriter::WriteBytes(dest + 28, uFileNameSize); + CBytesWriter::WriteBytes(dest + 30, uExtraFieldSize); + CBytesWriter::WriteBytes(dest + 32, uCommentSize); + CBytesWriter::WriteBytes(dest + 34, CBytesWriter::WriteSafeU16(m_uVolumeStart)); + CBytesWriter::WriteBytes(dest + 36, m_uInternalAttr); + CBytesWriter::WriteBytes(dest + 38, m_uExternalAttr); + CBytesWriter::WriteBytes(dest + 42, CBytesWriter::WriteSafeU32(m_uOffset)); + + memcpy(dest + 46, m_pszFileNameBuffer, uFileNameSize); + + if (uExtraFieldSize) + m_aCentralExtraData.Write(dest + 46 + uFileNameSize); + + if (uCommentSize) + memcpy(dest + 46 + uFileNameSize + uExtraFieldSize, m_pszComment, uCommentSize); + + pStorage->Write(dest, uSize, true); + + // remove to avoid miscalculations in GetSize() + m_aCentralExtraData.RemoveInternalHeaders(); + ClearFileName(); + return uSize; +} + +bool CZipFileHeader::ReadLocal(CZipCentralDir& centralDir) +{ + char buf[LOCALFILEHEADERSIZE]; + CZipStorage* pStorage = centralDir.m_pStorage; + pStorage->Read(buf, LOCALFILEHEADERSIZE, true); + if (memcmp(buf, m_gszLocalSignature, 4) != 0) + return false; + + bool bIsDataDescr = (((WORD)*(buf + 6)) & 8) != 0; + + WORD uTemp; + CBytesWriter::ReadBytes(uTemp, buf + 6); + // do not compare the whole flag - the bits reserved by PKWARE may differ + // in local and central headers + if (centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalFlag) + && (uTemp & 0xf) != (m_uFlag & 0xf)) + return false; + + // method + WORD uMethod; + CBytesWriter::ReadBytes(uMethod, buf + 8); + + // this may be different in the local header (it may contain disk name for example) + CBytesWriter::ReadBytes(m_uLocalFileNameSize, buf + 26); + WORD uExtraFieldSize; + CBytesWriter::ReadBytes(uExtraFieldSize, buf + 28); + ZIP_VOLUME_TYPE uCurDsk = pStorage->GetCurrentVolume(); + // skip reading the local file name + pStorage->m_pFile->Seek(m_uLocalFileNameSize, CZipAbstractFile::current); + if (!m_aLocalExtraData.Read(pStorage, uExtraFieldSize)) + return false; + + CBytesWriter::ReadBytes(m_uLocalComprSize, buf + 18, 4); + CBytesWriter::ReadBytes(m_uLocalUncomprSize, buf + 22, 4); + if (uMethod == CZipCompressor::methodWinZipAes && IsEncrypted()) + CZipException::Throw(CZipException::noAES); + + if (centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalMethod) + && uMethod != m_uMethod ) + return false; + + if (!bIsDataDescr && centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalCRC | CZipArchive::checkLocalSizes)) + { + // read all at once - probably overally faster than checking and reading separately + DWORD uCrc32; + CBytesWriter::ReadBytes(uCrc32, buf + 14); + if (centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalCRC) + && uCrc32 != m_uCrc32) + return false; + + if (centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalSizes) + // do not check, if local compressed size is 0 - this usually means, that some archiver + // could not update the compressed size after compression + && ( m_uLocalComprSize != 0 && m_uLocalComprSize != m_uComprSize || m_uLocalUncomprSize != m_uUncomprSize)) + return false; + } + return pStorage->GetCurrentVolume() == uCurDsk; // check that the whole header is in one volume +} + +void CZipFileHeader::SetTime(const time_t & ttime) +{ +#if _MSC_VER >= 1400 + tm gts; + tm* gt = >s; + localtime_s(gt, &ttime); +#else + tm* gt = localtime(&ttime); +#endif + WORD year, month, day, hour, min, sec; + if (gt == NULL) + { + year = 0; + month = day = 1; + hour = min = sec = 0; + } + else + { + year = (WORD)(gt->tm_year + 1900); + if (year <= 1980) + year = 0; + else + year -= 1980; + month = (WORD)gt->tm_mon + 1; + day = (WORD)gt->tm_mday; + hour = (WORD)gt->tm_hour; + min = (WORD)gt->tm_min; + sec = (WORD)gt->tm_sec; + } + + m_uModDate = (WORD) (day + ( month << 5) + (year << 9)); + m_uModTime = (WORD) ((sec >> 1) + (min << 5) + (hour << 11)); +} + +void CZipFileHeader::ConvertFileName(CZipAutoBuffer& buffer) const +{ + if (m_pszFileName == NULL) + return; + CZipString temp = *m_pszFileName; + ZipCompatibility::SlashBackslashChg(temp, false); + if (m_stringSettings.m_bStoreNameInExtraData) + ZipCompatibility::ConvertStringToBuffer(temp, buffer, m_stringSettings.GetDefaultNameCodePage(GetSystemCompatibility())); + else + ZipCompatibility::ConvertStringToBuffer(temp, buffer, m_stringSettings.m_uNameCodePage); +} + +void CZipFileHeader::ConvertFileName(CZipString& szFileName) const +{ + if (!m_pszFileNameBuffer.IsAllocated() || m_pszFileNameBuffer.GetSize() == 0) + return; + ZipCompatibility::ConvertBufferToString(szFileName, m_pszFileNameBuffer, m_stringSettings.m_uNameCodePage); + int sc = ZipPlatform::GetSystemID(); + if (sc == ZipCompatibility::zcDosFat || sc == ZipCompatibility::zcNtfs) + ZipCompatibility::SlashBackslashChg(szFileName, true); + else // some archives may have an invalid path separator stored + ZipCompatibility::SlashBackslashChg(szFileName, false); +} + +// write the local header +void CZipFileHeader::WriteLocal(CZipStorage *pStorage) +{ + if (IsDataDescriptor()) + { + m_uLocalComprSize = 0; + // write, if we know it - WinZip 9.0 in segmented mode with AES encryption will + // complain otherwise (this seems like a bug, because the data descriptor is present and + // local descriptor should be discarded) + if (!IsWinZipAesEncryption()) + m_uLocalUncomprSize = 0; + } + else + { + m_uLocalComprSize = GetDataSize(true, false); + } + + WORD uMethod = m_uMethod; + + PrepareFileName(); + m_uLocalFileNameSize = (WORD)m_pszFileNameBuffer.GetSize(); + DWORD uExtraFieldSize = m_aLocalExtraData.GetTotalSize(); + DWORD iLocalSize = LOCALFILEHEADERSIZE + uExtraFieldSize + m_uLocalFileNameSize; + CZipAutoBuffer buf(iLocalSize); + char* dest = (char*) buf; + memcpy(dest, m_gszLocalSignature, 4); + + CBytesWriter::WriteBytes(dest + 4, m_uVersionNeeded); + CBytesWriter::WriteBytes(dest + 6, m_uFlag); + CBytesWriter::WriteBytes(dest + 8, uMethod); + CBytesWriter::WriteBytes(dest + 10, m_uModTime); + CBytesWriter::WriteBytes(dest + 12, m_uModDate); + WriteSmallDataDescriptor(dest + 14); + CBytesWriter::WriteBytes(dest + 26, m_uLocalFileNameSize); + CBytesWriter::WriteBytes(dest + 28, (WORD)uExtraFieldSize); + memcpy(dest + 30, m_pszFileNameBuffer, m_uLocalFileNameSize); + + if (uExtraFieldSize) + m_aLocalExtraData.Write(dest + 30 + m_uLocalFileNameSize); + + // possible volume change before writing to the file in the segmented archive + // so write the local header first + pStorage->Write(dest, iLocalSize, true); + + m_uVolumeStart = pStorage->GetCurrentVolume(); + m_uOffset = pStorage->GetPosition() - iLocalSize; + ClearFileName(); +} + +WORD CZipFileHeader::GetDataDescriptorSize(bool bConsiderSignature) const +{ + if (IsDataDescriptor()) + { + + WORD size = 12; + return (WORD)(bConsiderSignature ? size + 4 : size); + } + else + return 0; +} + +bool CZipFileHeader::NeedsDataDescriptor() const +{ + return m_uEncryptionMethod == CZipCryptograph::encStandard; +} + +void CZipFileHeader::PrepareData(int iLevel, bool bSegm) +{ + // could be == 1, but the way below it works for PredictMaximumFileSizeInArchive when used on an existing segmented archive - for whatever reason + m_uInternalAttr = 0; + + // version made by + + SetVersion((WORD)(0x14)); + + + m_uCrc32 = 0; + m_uComprSize = 0; + m_uUncomprSize = 0; + + ASSERT(CZipCompressor::IsCompressionSupported(m_uMethod) && ((iLevel == 0) == (m_uMethod == CZipCompressor::methodStore))); + + m_uFlag = 0; + if (m_uMethod == CZipCompressor::methodDeflate) + switch (iLevel) + { + case 1: + m_uFlag |= 6; + break; + case 2: + m_uFlag |= 4; + break; + case 8: + case 9: + m_uFlag |= 2; + break; + } + + UpdateFlag(bSegm); + + m_uVersionNeeded = 0; + if (m_uVersionNeeded == 0) + m_uVersionNeeded = IsDirectory() ? 0xa : 0x14; // 1.0 or 2.0 +} + + +void CZipFileHeader::GetCrcAndSizes(char * pBuffer)const +{ + WriteCrc32(pBuffer); + CBytesWriter::WriteBytes(pBuffer + 4, m_uComprSize, 4); + CBytesWriter::WriteBytes(pBuffer + 8, m_uUncomprSize, 4); +} + +bool CZipFileHeader::CheckDataDescriptor(CZipStorage* pStorage) const +{ + if (!IsDataDescriptor()) + return true; + + const int sizeOfSize = 4; + + const int size = 4 + 2 * sizeOfSize; // crc and two sizes + + CZipAutoBuffer buf(size + 4); + pStorage->Read(buf, size, false); + char* pBuf; + + // when an archive is segmented, files that are divided between volume have bit 3 of flag set + // which tell about the presence of the data descriptor after the compressed data + // This signature may be in a segmented archive that is one volume only + // (it is detected as a not segmented archive) + if (memcmp(buf, CZipStorage::m_gszExtHeaderSignat, 4) == 0) // there is a signature + { + pStorage->Read((char*)buf + size, 4, false); + pBuf = (char*)buf + 4; + } + else + pBuf = buf; + + DWORD uCrc32 = 0; + ZIP_SIZE_TYPE uCompressed = 0, uUncompressed = 0; + + CBytesWriter::ReadBytes(uCrc32, pBuf); + CBytesWriter::ReadBytes(uCompressed, pBuf + 4, sizeOfSize); + CBytesWriter::ReadBytes(uUncompressed, pBuf + 4 + sizeOfSize, sizeOfSize); + return uCrc32 == m_uCrc32 && uCompressed == m_uComprSize && uUncompressed == m_uUncomprSize; +} + +DWORD CZipFileHeader::GetSize()const +{ + DWORD uSize = FILEHEADERSIZE + PredictFileNameSize() + GetCommentSize(); + uSize += m_aCentralExtraData.GetTotalSize(); + if (m_stringSettings.m_bStoreNameInExtraData) + { + CZipString temp; + if (m_pszFileName != NULL) + temp = *m_pszFileName; + else + ConvertFileName(temp); + if (temp.GetLength() > 0) + { + uSize += 4 + 2 + 4; // headerID, size + version, flag + filename code page + CZipAutoBuffer buffer; + ZipCompatibility::ConvertStringToBuffer(temp, buffer, m_stringSettings.m_uNameCodePage); + uSize += buffer.GetSize(); + if (!m_stringSettings.IsStandardCommentCodePage()) + uSize += 4; + } + } + return uSize; +} + +DWORD CZipFileHeader::GetLocalSize(bool bReal)const +{ + DWORD uSize = LOCALFILEHEADERSIZE + m_aLocalExtraData.GetTotalSize(); + if (bReal) + uSize += m_uLocalFileNameSize; + else + uSize += PredictFileNameSize(); + return uSize; +} + +void CZipFileHeader::SetComment(LPCTSTR lpszComment) +{ + ZipCompatibility::ConvertStringToBuffer(lpszComment, m_pszComment, m_stringSettings.m_uCommentCodePage); +} + +CZipString CZipFileHeader::GetComment() const +{ + CZipString temp; + ZipCompatibility::ConvertBufferToString(temp, m_pszComment, m_stringSettings.m_uCommentCodePage); + return temp; +} + +int CZipFileHeader::GetCompressionLevel() const +{ + if (m_uMethod == CZipCompressor::methodStore) + return CZipCompressor::levelStore; + else if ((m_uFlag & (WORD) 6) != 0) + return 1; + else if ((m_uFlag & (WORD) 4) != 0) + return 2; + else if ((m_uFlag & (WORD) 2) != 0) + return CZipCompressor::levelBest; + else + return CZipCompressor::levelDefault; +} + +void CZipFileHeader::SetFileName(LPCTSTR lpszFileName) +{ + if (m_pszFileName == NULL) + m_pszFileName = new CZipString(lpszFileName); + else + *m_pszFileName = lpszFileName; + m_pszFileNameBuffer.Release(); +} + +CZipString& CZipFileHeader::GetFileName(bool bClearBuffer) +{ + if (m_pszFileName != NULL) + return *m_pszFileName; + m_pszFileName = new CZipString(_T("")); + ConvertFileName(*m_pszFileName); + // don't keep it in memory + if (bClearBuffer) + m_pszFileNameBuffer.Release(); + return *m_pszFileName; +} + +bool CZipFileHeader::IsDirectory() +{ + return ZipPlatform::IsDirectory(GetSystemAttr()); +} + +DWORD CZipFileHeader::GetSystemAttr() +{ + int iSystemComp = GetSystemCompatibility(); + if (ZipCompatibility::IsPlatformSupported(iSystemComp)) + { + DWORD uAttr = iSystemComp == ZipCompatibility::zcUnix ? (m_uExternalAttr >> 16) : (m_uExternalAttr & 0xFFFF); + if (!uAttr && CZipPathComponent::HasEndingSeparator(GetFileName())) + return ZipPlatform::GetDefaultDirAttributes(); // can happen + else + { + uAttr = ZipCompatibility::ConvertToSystem(uAttr, iSystemComp, ZipPlatform::GetSystemID()); +#ifdef ZIP_ARCHIVE_LNX + // converting from Windows attributes may create a not readable linux directory + if (iSystemComp != ZipCompatibility::zcUnix && ZipPlatform::IsDirectory(uAttr)) + return ZipPlatform::GetDefaultDirAttributes(); +#endif + return uAttr; + } + } + else + return CZipPathComponent::HasEndingSeparator(GetFileName()) ? ZipPlatform::GetDefaultDirAttributes() : ZipPlatform::GetDefaultAttributes(); +} + +void CZipFileHeader::SetSystemAttr(DWORD uAttr) +{ + // make it readable under Unix as well, since it stores its attributes in HIWORD(uAttr) + int iSystemComp = GetSystemCompatibility(); + m_uExternalAttr = ZipCompatibility::ConvertToSystem(uAttr, ZipPlatform::GetSystemID(), iSystemComp); + if (iSystemComp == ZipCompatibility::zcUnix) + { + m_uExternalAttr <<= 16; + if (ZipPlatform::IsDirectory(uAttr)) + m_uExternalAttr |= 0x10; // make it recognizable under other systems (all use 0x10 for directory) + } + else + // make it readable under linux + m_uExternalAttr |= (ZipCompatibility::ConvertToSystem(uAttr, ZipPlatform::GetSystemID(), ZipCompatibility::zcUnix) << 16); +} + +CZipFileHeader& CZipFileHeader::operator=(const CZipFileHeader& header) +{ + m_uVersionMadeBy = header.m_uVersionMadeBy; + m_uVersionNeeded = header.m_uVersionNeeded; + m_uFlag = header.m_uFlag; + m_uMethod = header.m_uMethod; + m_uModTime = header.m_uModTime; + m_uModDate = header.m_uModDate; + m_uCrc32 = header.m_uCrc32; + m_uComprSize = header.m_uComprSize; + m_uUncomprSize = header.m_uUncomprSize; + m_uVolumeStart = header.m_uVolumeStart; + m_uInternalAttr = header.m_uInternalAttr; + m_uLocalComprSize = header.m_uLocalComprSize; + m_uLocalUncomprSize = header.m_uUncomprSize; + m_uExternalAttr = header.m_uExternalAttr; + m_uLocalFileNameSize = header.m_uLocalFileNameSize;; + m_uOffset = header.m_uOffset; + m_aLocalExtraData = header.m_aLocalExtraData; + m_aCentralExtraData = header.m_aCentralExtraData; + m_uEncryptionMethod = header.m_uEncryptionMethod; + if (m_pszFileName) + delete m_pszFileName; + + if (header.m_pszFileName) + m_pszFileName = new CZipString(*header.m_pszFileName); + else + m_pszFileName = NULL; + + m_pszFileNameBuffer = header.m_pszFileNameBuffer; + m_pszComment = header.m_pszComment; + m_stringSettings = header.m_stringSettings; + + return *this; +} + +void CZipFileHeader::WriteSmallDataDescriptor(char* pDest, bool bLocal) +{ + WriteCrc32(pDest); + if (bLocal) + { + CBytesWriter::WriteBytes(pDest + 4, m_uLocalComprSize, 4); + CBytesWriter::WriteBytes(pDest + 8, m_uLocalUncomprSize, 4); + } + else + { + CBytesWriter::WriteBytes(pDest + 4, m_uComprSize, 4); + CBytesWriter::WriteBytes(pDest + 8, m_uUncomprSize, 4); + } +} + + +void CZipFileHeader::WriteDataDescriptor(CZipStorage* pStorage) +{ + if (!IsDataDescriptor()) + return; + bool signature = NeedsSignatureInDataDescriptor(pStorage); + CZipAutoBuffer buf; + buf.Allocate(GetDataDescriptorSize(signature)); + char* pBuf; + if (signature) + { + memcpy(buf, CZipStorage::m_gszExtHeaderSignat, 4); + pBuf = (char*)buf + 4; + } + else + pBuf = buf; + WriteCrc32(pBuf); + CBytesWriter::WriteBytes(pBuf + 4, m_uComprSize, 4); + CBytesWriter::WriteBytes(pBuf + 8, m_uUncomprSize, 4); + pStorage->Write(buf, buf.GetSize(), true); +} + +void CZipFileHeader::UpdateLocalHeader(CZipStorage* pStorage) +{ + if (pStorage->IsSegmented() != 0 || IsDataDescriptor()) + // there is nothing to fix + return; + pStorage->Flush(); + ZIP_FILE_USIZE uPos = pStorage->m_pFile->GetPosition(); + // update crc and sizes, the sizes may already be all right, + // but 8 more bytes won't make a difference, we need to update crc32 anyway + CZipAutoBuffer buf(12); + m_uLocalComprSize = CBytesWriter::WriteSafeU32(m_uComprSize); + m_uLocalUncomprSize = CBytesWriter::WriteSafeU32(m_uUncomprSize); + WriteSmallDataDescriptor(buf); + pStorage->Seek(m_uOffset + 14); + pStorage->m_pFile->Write(buf, 12); + + pStorage->m_pFile->Seek(uPos); +} + +void CZipFileHeader::WriteCrc32(char* pBuf) const +{ + DWORD uCrc = m_bIgnoreCrc32 ? 0 : m_uCrc32; + CBytesWriter::WriteBytes(pBuf, uCrc); +} + diff --git a/harbour/contrib/hbziparch/ZipFileHeader.h b/harbour/contrib/hbziparch/ZipFileHeader.h new file mode 100644 index 0000000000..ddae37572b --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFileHeader.h @@ -0,0 +1,709 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipFileHeader.h +* Includes the CZipFileHeader class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPFILEHEADER_DOT_H) +#define ZIPARCHIVE_ZIPFILEHEADER_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "ZipExport.h" +#include "ZipStorage.h" +#include "ZipAutoBuffer.h" +#include "sys/types.h" +#include "ZipCompatibility.h" +#include "ZipCollections.h" +#include "ZipExtraField.h" +#include "ZipStringStoreSettings.h" +#include "ZipCryptograph.h" + + +class CZipCentralDir; + +/** + Represents a single file stored in a zip archive. +*/ +class ZIP_API CZipFileHeader +{ + friend class CZipCentralDir; + friend class CZipArchive; +public: + CZipFileHeader(); + CZipFileHeader(const CZipFileHeader& header) + { + *this = header; + } + CZipFileHeader& operator=(const CZipFileHeader& header); + virtual ~CZipFileHeader(); + + /** + Predicts the filename size after conversion using the current filename code page. + + \return + The number of characters not including a terminating \c NULL character. + */ + int PredictFileNameSize() const + { + if (m_pszFileNameBuffer.IsAllocated()) + return m_pszFileNameBuffer.GetSize(); + CZipAutoBuffer buffer; + ConvertFileName(buffer); + return buffer.GetSize(); + } + + /** + Gets the comment size. + + \return + The number of characters in the comment not including a terminating \c NULL character. + */ + WORD GetCommentSize() const {return (WORD)m_pszComment.GetSize();} + + + /** + Gets the filename. If necessary, performs the conversion using the current filename code page. + Caches the result of conversion for faster access the next time. + + \param bClearBuffer + If \c true, releases the internal buffer after performing the filename conversion. + If \c false, the internal buffer is not released and both representations of the + filename are kept in memory (converted and not converted). This takes more memory, but the + conversion does not take place again when the central directory is written back to the archive. + + \return + The converted filename. + + \see + 0610051525 + \see + GetStringStoreSettings + \see + CZipStringStoreSettings::m_uNameCodePage + */ + CZipString& GetFileName(bool bClearBuffer = true); + + /** + Sets the filename. + + \param lpszFileName + The filename to set. + */ + void SetFileName(LPCTSTR lpszFileName); + + /** + Gets the file comment. + + \return + The file comment. + */ + CZipString GetComment() const; + + /** + Sets the file comment. + + \param lpszComment + The file comment. + */ + void SetComment(LPCTSTR lpszComment); + + /** + Gets a value indicating whether the data descriptor is present or not. + + \return + \c true, if the data descriptor is present; \c false otherwise. + */ + bool IsDataDescriptor()const { return (m_uFlag & (WORD) 8) != 0;} + + /** + Gets the data descriptor size as it is required for the current file. + Takes into account various factors, such as the archive segmentation type, + encryption and the need for the Zip64 format. + + \param pStorage + The storage to test for segmentation type. + + \return + The required data descriptor size in bytes. + */ + WORD GetDataDescriptorSize(const CZipStorage* pStorage) const + { + return GetDataDescriptorSize(NeedsSignatureInDataDescriptor(pStorage)); + } + + /** + Gets the data descriptor size as it is required for the current file. + Takes into account various factors, such as the need for the data descriptor signature + or for the Zip64 format. + + \param bConsiderSignature + \c true, if the data descriptor signature is needed; \c false otherwise. + + \return + The required data descriptor size in bytes. + */ + WORD GetDataDescriptorSize(bool bConsiderSignature = false) const; + + + /** + Gets the size of the compressed data. + + \param bUseLocal + If \c true, uses #m_uLocalComprSize; otherwise uses #m_uComprSize; + + \param bReal + If \c true, the returned value does not include the encrypted information size, only the data size. + If \c false, the encrypted information size is added (you should not use this value + when the file exists in the archive). + + \return + The compressed data size in bytes. + + \see + GetEncryptedInfoSize + */ + ZIP_SIZE_TYPE GetDataSize(bool bUseLocal = false, bool bReal = true) const + { + ZIP_SIZE_TYPE uSize = bUseLocal ? m_uLocalComprSize : m_uComprSize; + DWORD uEncrSize = GetEncryptedInfoSize(); + return bReal ? (uSize - uEncrSize) : (uSize + uEncrSize); + } + + /** + Gets the encrypted information size. The returned value depends on the used encryption method. + + \return + The encrypted information size in bytes. + */ + DWORD GetEncryptedInfoSize() const + { + return CZipCryptograph::GetEncryptedInfoSize(m_uEncryptionMethod); + } + + /** + Gets the total size of the structure in the central directory. + + \return + The total size in bytes. + */ + DWORD GetSize()const; + + /** + Gets the local header size. Before calling this method, the local information must be up-to-date + (see 0610242128|local for more information). + + \param bReal + If \c true, uses the real local filename size. + If \c false, predicts the filename size. + + \return + The local header size in bytes. + */ + DWORD GetLocalSize(bool bReal) const; + + /** + Gets a value indicating if the compression is efficient. + + \return + \c true if the compression is efficient; \c false if the file should be + stored without the compression instead. + */ + bool CompressionEfficient() + { + ZIP_SIZE_TYPE uBefore = m_uUncomprSize; + // ignore the length of encryption info + ZIP_SIZE_TYPE uAfter = GetDataSize(false, true); + return uAfter <= uBefore; + } + + /** + Gets the compression ratio. + + \return + The compression ratio of the file. + */ + float GetCompressionRatio() + { +#if _MSC_VER >= 1300 || !defined(_ZIP64) + return m_uUncomprSize ? ((float)m_uComprSize * 100 ) / m_uUncomprSize: 0; +#else + return m_uUncomprSize ? ((float)(__int64)(m_uComprSize) / (float)(__int64)m_uUncomprSize) * 100: 0; +#endif + } + + /** + Sets the file modification date. + + \param ttime + The date to set. If this value is incorrect, the date defaults to January 1, 1980. + + \see + GetTime + */ + void SetTime(const time_t& ttime); + + /** + Gets the file modification time. + + \return + The modification time. + + \see + SetTime + */ + time_t GetTime()const; + + /** + Gets the file system compatibility. + External software can use this information e.g. to determine end-of-line + format for text files etc. + The ZipArchive Library uses it to perform a proper file attributes conversion. + + \return + The file system compatibility. Can be one of the ZipCompatibility::ZipPlatforms values. + \see + CZipArchive::GetSystemComatibility + \see + ZipPlatform::GetSystemID + */ + int GetSystemCompatibility()const + { + return (m_uVersionMadeBy & 0xFF00) >> 8; + } + + /** + Gets the file attributes. + + \return + The file attributes, converted if necessary to be compatible with the current system. + + \note + Throws an exception, if the archive system or the current system + is not supported by the ZipArchive Library. + + \see + GetOriginalAttributes + */ + DWORD GetSystemAttr(); + + /** + Gets the file attributes exactly as they are stored in the archive. + + \return + The file attributes as they are stored in the archive. + No conversion is performed. + + \note + The attributes for Linux are stored shifted left by 16 bits in this field. + \see + GetSystemAttr + */ + DWORD GetOriginalAttributes() const {return m_uExternalAttr;} + + /** + Gets a value indicating whether the file represents a directory or not. + This method checks the file attributes. If the attributes value is zero, + the method checks for the presence of a path + separator at the end of the filename. If the path separator is present, + the file is assumed to be a directory. + + \return + \c true, if the file represents a directory; \c false otherwise. + */ + bool IsDirectory(); + + + /** + Gets the string store settings for the file. + + \return + The string store settings. + + \see + 0610051525 + \see + CZipArchive::GetStringStoreSettings + */ + CZipStringStoreSettings GetStringStoreSettings() + { + return m_stringSettings; + } + + /** + Gets a value indicating if the file is encrypted or not. + If the file is encrypted, you need to set the password with the + CZipArchive::SetPassword method before decompressing the file. + + \return + \c true if the file is encrypted; \c false otherwise. + + \see + CZipArchive::SetPassword + */ + bool IsEncrypted()const { return m_uEncryptionMethod != CZipCryptograph::encNone;} + + /** + Gets the encryption method of the file. + + \return + The file encryption method. Can be one of the CZipCryptograph::EncryptionMethod values. + */ + int GetEncryptionMethod() const {return m_uEncryptionMethod;} + + /** + Gets a value indicating if the file is encrypted using WinZip AES encryption method or not. + + \return + \c true, if the file is encrypted using WinZip AES encryption method; \c false otherwise. + */ + bool IsWinZipAesEncryption() const + { + return CZipCryptograph::IsWinZipAesEncryption(m_uEncryptionMethod); + } + + /** + Gets an approximate file compression level. + + \return + The compression level. May not be the real value used when compressing the file. + */ + int GetCompressionLevel() const; + + /** + Returns the value indicating whether the current CZipFileHeader object has the time set or not. + + \return + \c true, if the time is set; \c false otherwise. + */ + bool HasTime() + { + return m_uModTime != 0 || m_uModDate != 0; + } + + static char m_gszSignature[]; ///< The central file header signature. + static char m_gszLocalSignature[]; ///< The local file header signature. + WORD m_uVersionMadeBy; ///< The "made by" version and the system compatibility. + WORD m_uVersionNeeded; ///< The version needed to extract the file. + WORD m_uFlag; ///< A general purpose bit flag. + WORD m_uMethod; ///< The compression method. Can be one of the CZipCompressor::CompressionMethod values. + WORD m_uModTime; ///< The file last modification time. + WORD m_uModDate; ///< The file last modification date. + DWORD m_uCrc32; ///< The crc-32 value. + ZIP_SIZE_TYPE m_uComprSize; ///< The compressed size. + ZIP_SIZE_TYPE m_uUncomprSize; ///< The uncompressed size. + ZIP_VOLUME_TYPE m_uVolumeStart; ///< The volume number at which the compressed file starts. + WORD m_uInternalAttr; ///< Internal file attributes. + ZIP_SIZE_TYPE m_uLocalComprSize; ///< The compressed size written in the local header. + ZIP_SIZE_TYPE m_uLocalUncomprSize; ///< The uncompressed size written in the local header. + ZIP_SIZE_TYPE m_uOffset; ///< Relative offset of the local header with respect to CZipFileHeader::m_uVolumeStart. + CZipExtraField m_aLocalExtraData; ///< The local extra field. Do not modify after you have started compressing the file. + CZipExtraField m_aCentralExtraData; ///< The central extra field. +protected: + DWORD m_uExternalAttr; ///< External file attributes. + WORD m_uLocalFileNameSize; ///< The local filename length. + BYTE m_uEncryptionMethod; ///< The file encryption method. Can be one of the CZipCryptograph::EncryptionMethod values. + bool m_bIgnoreCrc32; ///< A value indicating whether to ignore Crc32 checking or not. + + + + /** + Sets the file system compatibility. + + \param iSystemID + The file system compatibility. Can be one of the ZipCompatibility::ZipPlatforms values. + + \see + GetSystemCompatibility + */ + void SetSystemCompatibility(int iSystemID) + { + m_uVersionMadeBy &= 0x00FF; + m_uVersionMadeBy |= (WORD)(iSystemID << 8); + } + + /** + Sets the file attributes. + To set the attributes of this structure use the CZipArchive::SetFileHeaderAttr method. + + \param uAttr + The attributes to set. + + \note + Throws exceptions, if the archive system or the current system + is not supported by the ZipArchive Library. + + \see + CZipArchive::SetFileHeaderAttr + \see + GetSystemAttr + */ + void SetSystemAttr(DWORD uAttr); + + /** + Prepares the filename for writing to the archive. + */ + void PrepareFileName() + { + if (m_pszFileNameBuffer.IsAllocated() || m_pszFileName == NULL) + return; + ConvertFileName(m_pszFileNameBuffer); + } + + /** + Validates an existing data descriptor after file decompression. + + \param pStorage + The storage to read the data descriptor from. + + \return + \c true, if the data descriptor is valid; \c false otherwise. + */ + bool CheckDataDescriptor(CZipStorage* pStorage) const; + + + /** + Prepares the data for writing when adding a new file. When Zip64 extensions are required for this file, + this method adds Zip64 extra data to #m_aLocalExtraData. + + \param iLevel + The compression level. + + \param bSegm + Set to \c true, if the archive is segmented; \c false otherwise. + */ + void PrepareData(int iLevel, bool bSegm); + + /** + Writes the local file header to the \a pStorage. + The filename and extra field are the same as those that will be stored in the central directory. + + \param pStorage + The storage to write the local file header to. + + \note + Throws exceptions. + */ + void WriteLocal(CZipStorage *pStorage); + + /** + Reads the local file header from an archive and validates the read data. + + \param centralDir + The current central directory. + + \return + \c true, if read data is consistent; \c false otherwise. + + \note + Throws exceptions. + + \see + CZipArchive::SetIgnoredConsistencyChecks + */ + bool ReadLocal(CZipCentralDir& centralDir); + + /** + Writes the central file header to \a pStorage. + + \param pStorage + The storage to write the central file header to. + + \return + The size of the file header. + + \note + Throws exceptions. + */ + DWORD Write(CZipStorage *pStorage); + + /** + Reads the central file header from \a pStorage and validates the read data. + + \param centralDir + The current central directory. + + \param bReadSignature + \c true, if the the central header signature should be read; \c false otherwise. + + + \return + \c true, if the read data is consistent; \c false otherwise. + + \note + Throws exceptions. + */ + bool Read(CZipCentralDir& centralDir, bool bReadSignature); + + + /** + Validates the member fields lengths. + The tested fields are: filename, extra fields and comment. + + \return + \c false, if any of the lengths exceeds the allowed value. + */ + bool CheckLengths(bool local) const + { + if (m_pszComment.GetSize() > USHRT_MAX || m_pszFileNameBuffer.GetSize() > USHRT_MAX) + return false; + else if (local) + return m_aLocalExtraData.Validate(); + else + return m_aCentralExtraData.Validate(); + } + + /** + Writes the Crc32 to \a pBuf. + + \param pBuf + The buffer to write the Crc32 to. Must have be of at least 4 bytes size. + */ + void WriteCrc32(char* pBuf) const; + + + /** + Gets a value indicating whether the file needs the data descriptor. + The data descriptor is needed when a file is encrypted or the Zip64 format needs to be used. + + \return + \c true, if the data descriptor is needed; \c false otherwise. + */ + bool NeedsDataDescriptor() const; + + + /** + Writes the data descriptor. + + \param pDest + The buffer to receive the data. + + \param bLocal + Set to \c true, if the local sizes are used; \c false otherwise. + */ + void WriteSmallDataDescriptor(char* pDest, bool bLocal = true); + + /** + Writes the data descriptor taking into account the Zip64 format. + + \param pStorage + The storage to write the data descriptor to. + */ + void WriteDataDescriptor(CZipStorage* pStorage); + + bool NeedsSignatureInDataDescriptor(const CZipStorage* pStorage) const + { + return pStorage->IsSegmented() != 0 || IsEncrypted(); + } + + /** + Updates the local header in the archive after is has already been written. + + \param pStorage + The storage to update the data descriptor in. + */ + void UpdateLocalHeader(CZipStorage* pStorage); + + /** + Verifies the central header signature. + + \param buf + The buffer that contains the signature to verify. + + \return + \c true, if the signature is valid; \c false otherwise. + */ + static bool VerifySignature(CZipAutoBuffer& buf) + { + return memcmp(buf, m_gszSignature, 4) == 0; + } + + /** + Updates the general purpose bit flag. + + \param bSegm + \c true, if the current archive is a segmented archive; \c false otherwise. + */ + void UpdateFlag(bool bSegm) + { + if (bSegm || m_uEncryptionMethod == CZipCryptograph::encStandard) + m_uFlag |= 8; // data descriptor present + + if (IsEncrypted()) + m_uFlag |= 1; // encrypted file + } + + +private: + + /** + Sets the "made by" version. + + \param uVersion + The version to set. + */ + void SetVersion(WORD uVersion) + { + if ((m_uVersionMadeBy & 0x00FF) != (uVersion & 0x00FF)) + { + m_uVersionMadeBy &= 0xFF00; + m_uVersionMadeBy |= (WORD)(uVersion & 0x00FF); + } + } + + void ConvertFileName(CZipAutoBuffer& buffer) const; + void ConvertFileName(CZipString& szFileName) const; + + void ClearFileName() + { + if (m_stringSettings.m_bStoreNameInExtraData) + // we are keeping m_pszFileName, clear the buffer, we need the original, when writing extra header and when accessing the filename + m_pszFileNameBuffer.Release(); + else if (m_pszFileName != NULL) + { + delete m_pszFileName; + m_pszFileName = NULL; + } + } + + void GetCrcAndSizes(char* pBuffer)const; + + bool NeedsZip64() const + { + return m_uComprSize >= UINT_MAX || m_uUncomprSize >= UINT_MAX || m_uVolumeStart >= USHRT_MAX || m_uOffset >= UINT_MAX; + } + + + void OnNewFileClose(CZipStorage* pStorage) + { + UpdateLocalHeader(pStorage); + WriteDataDescriptor(pStorage); + pStorage->Flush(); + } + + CZipAutoBuffer m_pszFileNameBuffer; + + CZipString* m_pszFileName; + + CZipStringStoreSettings m_stringSettings; + + CZipAutoBuffer m_pszComment; +}; + +#endif // !defined(ZIPARCHIVE_ZIPFILEHEADER_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipFileMapping.h b/harbour/contrib/hbziparch/ZipFileMapping.h new file mode 100644 index 0000000000..48da906d38 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFileMapping.h @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipFileMapping.h +* Includes the ZipArchiveLib::CZipFileMapping class. +* +*/ + + +#if !defined(ZIPARCHIVE_ZIPFILEMAPPING_DOT_H) +#define ZIPARCHIVE_ZIPFILEMAPPING_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "_platform.h" + +#ifdef ZIP_ARCHIVE_WIN + #include "ZipFileMapping_win.h" +#else + #include "ZipFileMapping_lnx.h" +#endif + +#endif // !defined(ZIPARCHIVE_ZIPFILEMAPPING_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipFileMapping_lnx.h b/harbour/contrib/hbziparch/ZipFileMapping_lnx.h new file mode 100644 index 0000000000..14997b27b7 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFileMapping_lnx.h @@ -0,0 +1,62 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPFILEMAPPING_DOT_H + #error Do not include this file directly. Include ZipFileMapping.h instead +#endif + + +#include + +namespace ZipArchiveLib +{ + struct CZipFileMapping + { + CZipFileMapping() + { + m_iSize = 0; + m_pFileMap = NULL; + } + bool CreateMapping(CZipFile* pFile) + { + if (!pFile) + return false; + m_iSize = pFile->GetLength(); + m_pFileMap = mmap(0, m_iSize, PROT_READ|PROT_WRITE, MAP_SHARED, pFile->m_hFile, 0); + return (m_pFileMap != NULL); + } + void RemoveMapping() + { + + if (m_pFileMap) + { + munmap(m_pFileMap, m_iSize); + m_pFileMap = NULL; + } + } + ~CZipFileMapping() + { + RemoveMapping(); + } + char* GetMappedMemory() + { + return reinterpret_cast (m_pFileMap); + } + protected: + void* m_pFileMap; + size_t m_iSize; + + }; +} + diff --git a/harbour/contrib/hbziparch/ZipFileMapping_win.h b/harbour/contrib/hbziparch/ZipFileMapping_win.h new file mode 100644 index 0000000000..b6463e4e77 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFileMapping_win.h @@ -0,0 +1,68 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPFILEMAPPING_DOT_H + #error Do not include this file directly. Include ZipFileMapping.h instead +#endif + +#include "ZipFile.h" +namespace ZipArchiveLib +{ + struct CZipFileMapping + { + CZipFileMapping() + { + m_hFileMap = NULL; + m_pFileMap = NULL; + } + bool CreateMapping(CZipFile* pFile) + { + if (!pFile) + return false; + m_hFileMap = CreateFileMapping((*pFile), NULL, PAGE_READWRITE, + 0, 0, _T("ZipArchive Mapping File")); + if (!m_hFileMap) + return false; + // Get pointer to memory representing file + m_pFileMap = MapViewOfFile(m_hFileMap, FILE_MAP_WRITE, 0, 0, 0); + return (m_pFileMap != NULL); + } + void RemoveMapping() + { + if (m_pFileMap) + { + UnmapViewOfFile(m_pFileMap); + m_pFileMap = NULL; + } + if (m_hFileMap) + { + CloseHandle(m_hFileMap); + m_hFileMap = NULL; + } + + } + ~CZipFileMapping() + { + RemoveMapping(); + } + char* GetMappedMemory() + { + return reinterpret_cast (m_pFileMap); + } + protected: + HANDLE m_hFileMap; + LPVOID m_pFileMap; + + }; +} diff --git a/harbour/contrib/hbziparch/ZipFile_mfc.cpp b/harbour/contrib/hbziparch/ZipFile_mfc.cpp new file mode 100644 index 0000000000..923535bdfe --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFile_mfc.cpp @@ -0,0 +1,39 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + +#if defined ZIP_ARCHIVE_MFC && !defined ZIP_FILE_USES_STL + +#include "stdafx.h" +#include "ZipFile.h" + +// IMPLEMENT_DYNAMIC(CZipAbstractFile, CFile) +IMPLEMENT_DYNAMIC(CZipFile, CFile) + +CZipFile::CZipFile() +{ +} + +CZipFile::~CZipFile() +{ + Close(); +} + +CZipFile::operator HANDLE() +{ + return (HANDLE)m_hFile; +} + +#endif diff --git a/harbour/contrib/hbziparch/ZipFile_mfc.h b/harbour/contrib/hbziparch/ZipFile_mfc.h new file mode 100644 index 0000000000..9e50c84c8b --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFile_mfc.h @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPFILE_DOT_H + #error Do not include this file directly. Include ZipFile.h instead +#endif + +#if _MSC_VER > 1000 && defined ZIP_HAS_DLL + #pragma warning (push) + #pragma warning( disable : 4275 ) // non dll-interface used as base for dll-interface class +#endif + +#include "ZipAbstractFile.h" +#include "ZipExport.h" + +class ZIP_API CZipFile : public CZipAbstractFile, public CFile +{ +public: + DECLARE_DYNAMIC(CZipFile) + void Flush(){CFile::Flush();} + CZipString GetFilePath() const + { + try + { + // it throws an exception when working on an offline file + return CFile::GetFilePath(); + } + catch (CException* e) + { + e->Delete(); + return this->m_strFileName; + } + } + + ZIP_FILE_USIZE GetPosition() const {return CFile::GetPosition() ;} + void SetLength(ZIP_FILE_USIZE nNewLen) {CFile::SetLength(nNewLen);} + ZIP_FILE_USIZE Seek(ZIP_FILE_SIZE lOff , int nFrom){return CFile::Seek(lOff, nFrom);} + ZIP_FILE_USIZE GetLength() const {return CFile::GetLength();} + + + UINT Read(void *lpBuf, UINT nCount){return CFile::Read(lpBuf, nCount);} + void Write(const void* lpBuf, UINT nCount){CFile::Write(lpBuf, nCount);} + bool Open( LPCTSTR lpszFileName, UINT nOpenFlags, bool bThrowExc) + { + CFileException* e = new CFileException; + bool bRet = CFile::Open(lpszFileName, nOpenFlags, e) != 0; + if (!bRet && bThrowExc) + throw e; + e->Delete(); + return bRet; + } + CZipFile(); + bool IsClosed() const + { + return m_hFile == CFile::hFileNull; + } + + + CZipFile( LPCTSTR lpszFileName, UINT nOpenFlags ):CFile(lpszFileName, nOpenFlags) + { + } + + void Close( ) + { + if (!IsClosed()) + CFile::Close(); + } + operator HANDLE(); + virtual ~CZipFile(); + +}; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + diff --git a/harbour/contrib/hbziparch/ZipFile_stl.cpp b/harbour/contrib/hbziparch/ZipFile_stl.cpp new file mode 100644 index 0000000000..0791fae8ca --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFile_stl.cpp @@ -0,0 +1,144 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "_features.h" + +#if defined ZIP_ARCHIVE_STL || defined ZIP_FILE_USES_STL + +#if defined __APPLE__ || defined __CYGWIN__ + #define FILE_FUNCTIONS_64B_BY_DEFAULT +#else + #undef FILE_FUNCTIONS_64B_BY_DEFAULT +#endif + +#include "stdafx.h" +#include "ZipFile.h" +#include "ZipException.h" +#include "ZipPlatform.h" + +#include + +CZipFile::CZipFile() +{ + m_hFile = -1; +} + +void CZipFile::ThrowError() const +{ + CZipException::Throw(errno, m_szFileName); +} + + +ZIP_FILE_USIZE CZipFile::GetLength() const +{ + // cannot use Seek here, Seek is not const + ZIP_SIZE_TYPE lLen, lCur; + lCur = _lseek(m_hFile, 0, current); + if (lCur == (ZIP_SIZE_TYPE)-1) + ThrowError(); + lLen = _lseek(m_hFile, 0, end); + + // first go back + bool err = _lseek(m_hFile, lCur, begin) == -1; + + if (err || lLen == (ZIP_SIZE_TYPE)-1) + ThrowError(); + return lLen; + +} + + +bool CZipFile::Open(LPCTSTR lpszFileName, UINT openFlags, bool bThrow) +{ + if (!IsClosed()) + Close(); + +#ifdef O_BINARY + UINT iNewFlags = O_BINARY; +#else + UINT iNewFlags = 0; +#endif + + bool bReadOnly = false; + if (openFlags & CZipFile::modeCreate) + iNewFlags |= O_CREAT; + if ((openFlags & CZipFile::modeReadWrite) == CZipFile::modeReadWrite) + iNewFlags |= O_RDWR; + else if (openFlags & CZipFile::modeRead) + { + // O_RDONLY is defined as 0 + bReadOnly = true; + iNewFlags |= O_RDONLY; + } + else if (openFlags & CZipFile::modeWrite) + iNewFlags |= O_WRONLY; + + if (!(openFlags & CZipFile::modeNoTruncate) && !bReadOnly) + iNewFlags |= O_TRUNC; + m_hFile = ZipPlatform::OpenFile(lpszFileName, iNewFlags, openFlags & 0x1C); + if (m_hFile == -1) + if (bThrow) + CZipException::Throw(errno, lpszFileName); + else + return false; + m_szFileName = lpszFileName; + return true; +} + + +void CZipFile::SetLength(ULONGLONG uNewLen) +{ + ZipPlatform::TruncateFile(m_hFile, uNewLen); +} + +ZIP_FILE_USIZE CZipFile::GetPosition() const +{ + #ifndef __GNUC__ + ZIP_FILE_USIZE ret = _tell(m_hFile); + #else + ZIP_FILE_USIZE ret = lseek(m_hFile, 0, SEEK_CUR); + #endif + if (ret == (ZIP_FILE_USIZE)-1) + ThrowError(); + return ret; +} + +ZIP_FILE_USIZE CZipFile::Seek(ZIP_FILE_SIZE dOff, int nFrom) +{ + // restricted to signed + ZIP_FILE_SIZE ret = (ZIP_FILE_SIZE)_lseek(m_hFile, (long)dOff, nFrom); + if (ret == -1) + ThrowError(); + return (ZIP_FILE_USIZE)ret; +} + +void CZipFile::Flush() +{ + if (!ZipPlatform::FlushFile(m_hFile)) + ThrowError(); +} + +CZipFile::operator HANDLE() +{ + intptr_t fh = ZipPlatform::GetFileSystemHandle(m_hFile); + if (fh == -1) + ThrowError(); +#if _MSC_VER >= 1300 + return (HANDLE)fh; +#else + return (HANDLE)fh; +#endif +} + +#endif diff --git a/harbour/contrib/hbziparch/ZipFile_stl.h b/harbour/contrib/hbziparch/ZipFile_stl.h new file mode 100644 index 0000000000..8b10354fc1 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipFile_stl.h @@ -0,0 +1,119 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPFILE_DOT_H + #error Do not include this file directly. Include ZipFile.h instead +#endif + +#include "ZipAbstractFile.h" +#include "ZipString.h" +#include "ZipExport.h" + +#ifndef __GNUC__ + #include +#else + #include + #include +#endif + +#if !defined (_MSC_VER) || _MSC_VER < 1400 + +// there seems to be a problem under Windows sometimes when using one of the functions below +// without the underscore at the beginning +#ifndef _lseek + #define _lseek lseek +#endif + +#ifndef _read + #define _read read +#endif + +#ifndef _close + #define _close close +#endif + +#ifndef _tell + #define _tell tell +#endif + +#ifndef _write + #define _write write +#endif + +#endif +class ZIP_API CZipFile : public CZipAbstractFile +{ + void ThrowError() const; +public: + int m_hFile; + operator HANDLE(); + enum OpenModes + { + modeRead = 0x0001, + modeWrite = 0x0002, + modeReadWrite = modeRead | modeWrite, + shareDenyWrite = 0x0004, + shareDenyRead = 0x0008, + shareDenyNone = 0x0010, + modeCreate = 0x0020, + modeNoTruncate = 0x0040, + }; + + CZipFile(LPCTSTR lpszFileName, UINT openFlags) + { + m_hFile = -1; + Open(lpszFileName, openFlags, true); + } + void Flush(); + ZIP_FILE_USIZE GetLength() const; + CZipString GetFilePath() const {return m_szFileName;} + bool IsClosed()const { return m_hFile == -1;} + bool Open(LPCTSTR lpszFileName, UINT openFlags, bool bThrow); + void Close() + { + if (IsClosed()) + return; + if (_close(m_hFile) != 0) + ThrowError(); + else + { + m_szFileName.Empty(); + m_hFile = -1; + } + } + void Write(const void* lpBuf, UINT nCount) + { + if (_write(m_hFile, lpBuf, nCount) != (int) nCount) + ThrowError(); + } + ZIP_FILE_USIZE GetPosition() const; + void SetLength(ZIP_FILE_USIZE uNewLen); + UINT Read(void *lpBuf, UINT nCount) + { + errno = 0; + int ret = _read(m_hFile, lpBuf, nCount); + if (ret < (int) nCount && errno != 0) + ThrowError(); + return ret; + + } + + ZIP_FILE_USIZE Seek(ZIP_FILE_SIZE dOff, int nFrom); + + CZipFile (); + virtual ~CZipFile (){Close();}; +protected: + CZipString m_szFileName; + +}; diff --git a/harbour/contrib/hbziparch/ZipMemFile.cpp b/harbour/contrib/hbziparch/ZipMemFile.cpp new file mode 100644 index 0000000000..f3a2240b7f --- /dev/null +++ b/harbour/contrib/hbziparch/ZipMemFile.cpp @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipMemFile.h" +#include "ZipException.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +void CZipMemFile::Grow(size_t nGrowTo) +{ + if (m_nBufSize < (UINT)nGrowTo) + { + if (m_nGrowBy == 0) + CZipException::Throw(CZipException::memError); + size_t nNewSize = m_nBufSize; + while (nNewSize < nGrowTo) + nNewSize += m_nGrowBy; + BYTE* lpNew; + if (m_lpBuf) + lpNew = (BYTE*)realloc((void*) m_lpBuf, nNewSize); + else + lpNew = (BYTE*)malloc(nNewSize); + + if (!lpNew) + CZipException::Throw(CZipException::memError); + m_nBufSize = nNewSize; + m_lpBuf = lpNew; + } +} + +void CZipMemFile::SetLength(ZIP_FILE_USIZE nNewLen) +{ + if (m_nBufSize < (size_t)nNewLen) + Grow((size_t)nNewLen); + else + m_nPos = (size_t)nNewLen; + m_nDataSize = (size_t)nNewLen; +} + +UINT CZipMemFile::Read(void *lpBuf, UINT nCount) +{ + if (m_nPos >= m_nDataSize) + return 0; + UINT nToRead = (m_nPos + nCount > m_nDataSize) ? (UINT)(m_nDataSize - m_nPos) : nCount; + memcpy(lpBuf, m_lpBuf + m_nPos, nToRead); + m_nPos += nToRead; + return nToRead; + +} + +void CZipMemFile::Write(const void *lpBuf, UINT nCount) +{ + if (!nCount) + return; + + if (m_nPos + nCount > m_nBufSize) + Grow(m_nPos + nCount); + memcpy(m_lpBuf + m_nPos, lpBuf, nCount); + m_nPos += nCount; + if (m_nPos > m_nDataSize) + m_nDataSize = m_nPos; +} +ZIP_FILE_USIZE CZipMemFile::Seek(ZIP_FILE_SIZE lOff, int nFrom) +{ + ZIP_FILE_USIZE lNew = m_nPos; + + if (nFrom == CZipAbstractFile::begin) + { + if (lOff < 0) + CZipException::Throw(CZipException::memError); + lNew = lOff; + } + else if (nFrom == CZipAbstractFile::current) + { + if (lOff < 0 && (ZIP_FILE_USIZE)(-lOff) > lNew) + CZipException::Throw(CZipException::memError); + lNew += lOff; + } + else if (nFrom == CZipAbstractFile::end) + { + if (lOff < 0 && ZIP_FILE_USIZE(-lOff) > m_nDataSize) + CZipException::Throw(CZipException::memError); + lNew = m_nDataSize + lOff; + } + else + return lNew; + + // assumption that size_t is always signed + if (lNew > (size_t)(-1)) // max of size_t + CZipException::Throw(CZipException::memError); + if (lNew > m_nDataSize) + Grow((size_t)lNew); + + m_nPos = (size_t)lNew; + return lNew; +} diff --git a/harbour/contrib/hbziparch/ZipMemFile.h b/harbour/contrib/hbziparch/ZipMemFile.h new file mode 100644 index 0000000000..f322bd935b --- /dev/null +++ b/harbour/contrib/hbziparch/ZipMemFile.h @@ -0,0 +1,129 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipMemFile.h +* Includes the CZipMemFile class. +* +*/ +#if !defined(ZIPARCHIVE_ZIPMEMFILE_DOT_H) +#define ZIPARCHIVE_ZIPMEMFILE_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "ZipAbstractFile.h" +#include "ZipString.h" +#include "ZipExport.h" + +/** + Represents a file in memory. + Automatically grows when necessary. +*/ +class ZIP_API CZipMemFile : public CZipAbstractFile +{ +protected: + size_t m_nGrowBy, m_nPos; + size_t m_nBufSize, m_nDataSize; + BYTE* m_lpBuf; + bool m_bAutoDelete; + void Free() + { + if (m_lpBuf) + { + free(m_lpBuf); + m_lpBuf = NULL; + } + } + void Init() + { + m_nGrowBy = m_nPos = 0; + m_nBufSize = m_nDataSize = 0; + m_lpBuf = NULL; + + } + void Grow(size_t nBytes); +public: + bool IsClosed() const { return m_lpBuf == NULL;} + void Flush(){} + + ZIP_FILE_USIZE Seek(ZIP_FILE_SIZE lOff, int nFrom); + ZIP_FILE_USIZE GetLength() const {return m_nDataSize;} + void Write(const void* lpBuf, UINT nCount); + UINT Read(void* lpBuf, UINT nCount); + void SetLength(ZIP_FILE_USIZE nNewLen); + CZipString GetFilePath() const {return _T("");} + CZipMemFile(long nGrowBy = 1024) + { + Init(); + m_nGrowBy = nGrowBy; + m_bAutoDelete = true; + } + + + + CZipMemFile(BYTE* lpBuf, UINT nBufSize, long nGrowBy = 0) + { + Init(); + Attach(lpBuf, nBufSize, nGrowBy); + } + + CZipMemFile(CZipMemFile& from) + { + Copy(from); + } + + void Copy(CZipMemFile& from) + { + SetLength(from.m_nDataSize); + from.Read(m_lpBuf, (UINT)from.m_nDataSize); + } + + ZIP_FILE_USIZE GetPosition() const { return m_nPos;} + void Attach(BYTE* lpBuf, UINT nBufSize, long nGrowBy = 0) + { + Close(); + m_lpBuf = lpBuf; + m_nGrowBy = nGrowBy; + m_nBufSize = nBufSize; + m_nDataSize = nGrowBy == 0 ? nBufSize : 0; + m_bAutoDelete = false; + } + + void ReInit(long nGrowBy = 1024) + { + Close(); + Init(); + m_nGrowBy = nGrowBy; + m_bAutoDelete = true; + } + + BYTE* Detach() + { + BYTE* b = m_lpBuf; + Init(); + return b; + } + void Close() + { + if (m_bAutoDelete) + Free(); + Init(); + } + virtual ~CZipMemFile(){Close();} + +}; + +#endif // !defined(ZIPARCHIVE_ZIPMEMFILE_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipMutex.h b/harbour/contrib/hbziparch/ZipMutex.h new file mode 100644 index 0000000000..90e4a2bd28 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipMutex.h @@ -0,0 +1,38 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipMutex.h +* Includes the ZipArchiveLib::CZipMutex class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPMUTEX_DOT_H) +#define ZIPARCHIVE_ZIPMUTEX_DOT_H + +#if _MSC_VER > 1000 + #pragma once +#endif + +#include "_features.h" + +#ifdef ZIP_ARCHIVE_LNX + #include "ZipMutex_lnx.h" +#else + #include "ZipMutex_win.h" +#endif + + +#endif + diff --git a/harbour/contrib/hbziparch/ZipMutex_lnx.h b/harbour/contrib/hbziparch/ZipMutex_lnx.h new file mode 100644 index 0000000000..1f4943c2ab --- /dev/null +++ b/harbour/contrib/hbziparch/ZipMutex_lnx.h @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPMUTEX_DOT_H + #error Do not include this file directly. Include ZipMutex.h instead +#endif + +#ifdef ZIP_ARCHIVE_USE_LOCKING + +#include + +namespace ZipArchiveLib +{ + +class ZIP_API CZipMutex +{ + pthread_mutex_t m_mutex; + bool m_bOpened; +public: + CZipMutex(bool bOpen = false) + { + if (bOpen) + Open(); + else + m_bOpened = false; + } + + void Open() + { + Close(); + if (pthread_mutex_init(&m_mutex, NULL) == 0) + m_bOpened = true; + else + CZipException::Throw(CZipException::mutexError); + } + + void Lock() + { + if (pthread_mutex_lock(&m_mutex) != 0) + CZipException::Throw(CZipException::mutexError); + } + + void Unlock() + { + if (pthread_mutex_unlock(&m_mutex) != 0) + CZipException::Throw(CZipException::mutexError); + } + + CZipMutex& operator=(const CZipMutex&) + { + m_bOpened = false; + return *this; + } + + + void Close() + { + if (m_bOpened) + if (pthread_mutex_destroy(&m_mutex) == 0) + m_bOpened = false; + else + CZipException::Throw(CZipException::mutexError); + } + + ~CZipMutex() + { + Close(); + } +}; + +} + +#endif diff --git a/harbour/contrib/hbziparch/ZipMutex_win.h b/harbour/contrib/hbziparch/ZipMutex_win.h new file mode 100644 index 0000000000..1610326143 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipMutex_win.h @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPMUTEX_DOT_H + #error Do not include this file directly. Include ZipMutex.h instead +#endif + +#ifdef ZIP_ARCHIVE_USE_LOCKING + +#include "ZipException.h" + +namespace ZipArchiveLib +{ +class ZIP_API CZipMutex +{ + HANDLE m_handle; +public: + CZipMutex(bool bOpen = false) + { + if (bOpen) + Open(); + else + m_handle = NULL; + } + + void Open() + { + Close(); + m_handle = ::CreateMutex(NULL, FALSE, NULL); + if (m_handle == NULL) + CZipException::Throw(CZipException::mutexError); + } + + void Lock() + { + DWORD dwRet = ::WaitForSingleObject(m_handle, INFINITE); + if (dwRet != WAIT_OBJECT_0 && dwRet != WAIT_ABANDONED) + CZipException::Throw(CZipException::mutexError); + } + + void Unlock() + { + if (!::ReleaseMutex(m_handle)) + CZipException::Throw(CZipException::mutexError); + } + + void Close() + { + if (m_handle != NULL) + { + ::CloseHandle(m_handle); + m_handle = NULL; + } + } + + CZipMutex& operator=(const CZipMutex&) + { + m_handle = NULL; + return *this; + } + + ~CZipMutex() + { + Close(); + } +}; + +} + +#endif diff --git a/harbour/contrib/hbziparch/ZipPathComponent.h b/harbour/contrib/hbziparch/ZipPathComponent.h new file mode 100644 index 0000000000..5eb2d49fe3 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipPathComponent.h @@ -0,0 +1,276 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipPathComponent.h +* Includes the CZipPathComponent class. +* +*/ +#if !defined(ZIPARCHIVE_ZIPPATHCOMPONENT_DOT_H) +#define ZIPARCHIVE_ZIPPATHCOMPONENT_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #if defined ZIP_HAS_DLL + #pragma warning (push) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class + #endif +#endif + +#include "ZipString.h" +#include "ZipExport.h" + +/** + Splits a file path into components. +*/ +class ZIP_API CZipPathComponent +{ +public: + CZipPathComponent(){} + virtual ~CZipPathComponent(); + + static const TCHAR m_cSeparator; ///< A system - specific default path separator. + + /** + Appends a path separator to \a szPath, if it is not already appended. + + \param szPath + The path to have a separator appended. + */ + static void AppendSeparator(CZipString& szPath) + { + RemoveSeparators(szPath); + szPath += m_cSeparator; + } + + /** + Combines a path information with a file name information. + + \param szPath + Provides the path information and retrieves the result. + + \param lpszName + The filename to be appended to the path. + */ + static void Combine(CZipString& szPath, LPCTSTR lpszName) + { + AppendSeparator(szPath); + if (lpszName != NULL) + szPath += lpszName; + } + + /** + Removes path separators from the end of \a szPath + + \param szPath + The path to have path separators removed. + */ + static void RemoveSeparators(CZipString& szPath) + { +// szPath.TrimRight(m_cSeparator); + szPath.TrimRight(_T("\\/")); + } + + /** + Removes path separators from the beginning of \a szPath. + + \param szPath + The path to have path separators removed. + */ + static void RemoveSeparatorsLeft(CZipString& szPath) + { + szPath.TrimLeft(_T("\\/")); + } + + + /** + Tests the character, if it is a separator or not. + + \param c + The character to test. + + \return + \c true, if \a c is a path separator; \c false otherwise. + */ + static bool IsSeparator(TCHAR c) + { + return c == _T('\\') || c == _T('/'); + } + + /** + Checks if \a szPath has a path separator appended. + + \param szPath + The path to be tested. + + \return + \c true, if \a szPath has a path separator at the end; \c false otherwise. + */ + static bool HasEndingSeparator(const CZipString& szPath) + { + int iLen = szPath.GetLength(); + if (iLen) + return IsSeparator(szPath[iLen - 1]); + else + return false; + } + + /** + Initializes a new instance of the CZipPathComponent class. + + \param lpszFullPath + The full path to the file. + + \see + SetFullPath + */ + CZipPathComponent(LPCTSTR lpszFullPath) + { + SetFullPath(lpszFullPath); + } + + /** + Sets the full path to the file. + + \param lpszFullPath + The full path to the file including a filename. + The last element in the path is assumed to be a filename. + */ + void SetFullPath(LPCTSTR lpszFullPath); + + /** + Gets the name of the file without an extension (and without a path). + + \return + The title of the file. + */ + CZipString GetFileTitle() const { return m_szFileTitle;} + + /** + Sets the file title (the name without an extension and without a path). + + \param lpszFileTitle + The title to set. + */ + void SetFileTitle(LPCTSTR lpszFileTitle) { m_szFileTitle = lpszFileTitle;} + + + /** + Sets the extension alone. + + \param lpszExt + The extension to set. May contain a dot at the beginning, but doesn't have to. + */ + void SetExtension(LPCTSTR lpszExt) + { + m_szFileExt = lpszExt; + m_szFileExt.TrimLeft(_T('.')); + } + + /** + Gets the extension of the file. + + \return + The extension without a dot. + */ + CZipString GetFileExt() const { return m_szFileExt;} + + /** + Gets the drive of the file. + + \return + The drive without a path separator at the end. + */ + CZipString GetFileDrive() const { return m_szDrive;} + + /** + Gets the full path to the file without the drive. + + \return + The path without the drive and without a path separator at the beginning. + */ + CZipString GetNoDrive() const ; + + /** + Get the filename. + + \return + The filename including an extension and without a path. + */ + CZipString GetFileName() const + { + CZipString szFullFileName = m_szFileTitle; + if (!m_szFileExt.IsEmpty()) + { + szFullFileName += _T("."); + szFullFileName += m_szFileExt; + } + return szFullFileName; + } + + /** + Gets the full path to the file. + + \return + The full path information including the filename. + */ + CZipString GetFullPath() const + { + CZipString szFullPath = GetFilePath(); + CZipString szFileName = GetFileName(); + if (!szFileName.IsEmpty()) + { + if (szFullPath.IsEmpty()) + szFullPath += _T('.'); + szFullPath += m_cSeparator; + szFullPath += szFileName; + } + return szFullPath; + } + + /** + Gets the path part only. + + \return + The path to the file without a filename and without a path separator at the end. + */ + CZipString GetFilePath() const + { + CZipString szDrive = m_szDrive; + CZipString szDir = m_szDirectory; + if (!szDrive.IsEmpty() && !szDir.IsEmpty()) + szDrive += m_cSeparator; + + return m_szPrefix + szDrive + szDir; + } +protected: + /** + \name Path parts. + */ + //@{ + CZipString m_szDirectory, ///< A directory(ies) only without path separators at the end and the beginning. + m_szFileTitle, ///< A filename without an extension. + m_szFileExt, ///< A file extension without a dot. + m_szDrive, ///< A drive (if the system path standard uses it) without a path separator at the end. + m_szPrefix; ///< A prefix (e.g. for the UNC path or Unicode path under Windows). + //@} + +}; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + + +#endif // !defined(ZIPARCHIVE_ZIPPATHCOMPONENT_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipPlatform.h b/harbour/contrib/hbziparch/ZipPlatform.h new file mode 100644 index 0000000000..48ddccd73d --- /dev/null +++ b/harbour/contrib/hbziparch/ZipPlatform.h @@ -0,0 +1,265 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipPlatform.h +* ZipPlatform namespace declaration. +* +*/ +#if !defined(ZIPARCHIVE_ZIPPLATFORM_DOT_H) +#define ZIPARCHIVE_ZIPPLATFORM_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +class CZipFileHeader; +class CZipAutoBuffer; + +#include "ZipString.h" +#include "ZipPathComponent.h" +#include +#include "ZipExport.h" + +/** + Includes functions that require system-specific implementation. +*/ +namespace ZipPlatform +{ + + /** + Gets the default case-sensitivity for the current file system. + + \return + \c true, if the system is case-sensitive; \c false otherwise. + */ + ZIP_API bool GetSystemCaseSensitivity(); + + /** + Gets the current system identifier. + + \return + One of the ZipCompatibility::ZipPlatforms values. + + \see + CZipArchive::SetSystemCompatibility + */ + ZIP_API int GetSystemID(); + + /** + Gets the default file attributes for the current system. + + \return + The default file attributes. + */ + ZIP_API DWORD GetDefaultAttributes(); + + /** + Gets the default directory attributes for the current system. + + \return + The default directory attributes. + */ + ZIP_API DWORD GetDefaultDirAttributes(); + + /** + Gets the free space on the given device. + + \param lpszPath + Points to the device to test. + + \return + The free space in bytes. + */ + ZIP_API ULONGLONG GetDeviceFreeSpace(LPCTSTR lpszPath); + + /** + Gets the name of a temporary file ensuring there is enough free space in the destination directory. + + \param lpszPath + The path to the directory to initially create the file in. + + \param uSizeNeeded + The requested free space size in bytes. If set to ZIP_SIZE_TYPE(-1), the + space availability is not checked. + */ + ZIP_API CZipString GetTmpFileName(LPCTSTR lpszPath = NULL, ZIP_SIZE_TYPE uSizeNeeded = ZIP_SIZE_TYPE(-1)); + + /** + \name Various operations on files and directories. + If the functions returns a \c bool value, then \c true indicates that the operation was successful. + */ + //@{ + ZIP_API bool GetCurrentDirectory(CZipString& sz); ///< Gets the current directory and stores it in \a sz. + ZIP_API bool ChangeDirectory(LPCTSTR lpDirectory); ///< Changes the current directory. + ZIP_API bool SetFileAttr(LPCTSTR lpFileName, DWORD uAttr); ///< Sets the file attributes. + ZIP_API bool GetFileAttr(LPCTSTR lpFileName, DWORD& uAttr); ///< Gets the file attributes. + ZIP_API bool GetFileModTime(LPCTSTR lpFileName, time_t & ttime); ///< Gets the file modification time. + ZIP_API bool SetFileModTime(LPCTSTR lpFileName, time_t ttime); ///< Set the file modification time. + ZIP_API bool GetFileSize(LPCTSTR lpszFileName, ZIP_SIZE_TYPE& dSize); ///< Gets the file size. + ZIP_API bool CreateDirectory(LPCTSTR lpDirectory); ///< Creates a new directory. + ZIP_API bool SetVolLabel(LPCTSTR lpszPath, LPCTSTR lpszLabel); ///< Sets a label on a removable device. \c lpszPath may point to a file on the device. + ZIP_API bool ForceDirectory(LPCTSTR lpDirectory); ///< Creates nested directories at once. + ZIP_API bool RemoveFile(LPCTSTR lpszFileName, bool bThrow = true); ///< Removes a file. + ZIP_API bool RenameFile( LPCTSTR lpszOldName, LPCTSTR lpszNewName, bool bThrow = true); ///< Renames a file. + +#ifdef ZIP_ARCHIVE_LNX + ZIP_API bool SetExeAttr( LPCTSTR lpFileName ); ///< Sets executable permissions for a file. +#endif + +#if defined ZIP_ARCHIVE_STL || defined ZIP_FILE_USES_STL + /** + Truncates the file. + + \note + Defined only in the STL version. + */ + ZIP_API bool TruncateFile(int iDes, ULONGLONG uSize); + + /** + Opens the file. + + \note + Defined only in the STL version. + */ + ZIP_API int OpenFile(LPCTSTR lpszFileName, UINT iMode, int iShareMode); + + /** + Flushes the file to the disk. + + \note + Defined only in the STL version. + */ + ZIP_API bool FlushFile(int iDes); + + /** + Gets the underlying system handle. + + \note + Defined only in the STL version. + */ + ZIP_API intptr_t GetFileSystemHandle(int iDes); +#endif + //@} + + /** + Checks if the given directory exists. + + \param lpszDir + The directory to test. + + \return + \c true, if \a lpszDir exists; \c false otherwise. + */ + ZIP_API bool DirectoryExists(LPCTSTR lpszDir); + + /** + Checks if the given drive is removable. + + \param lpszFilePath + The path to the drive. May point to a file path or a directory on the drive. + + \return + \c true. if the drive is removable; \c false otherwise. + + \note + Implemented only on Windows system, on all others always returns \c true. + */ + ZIP_API bool IsDriveRemovable(LPCTSTR lpszFilePath); + + /** + Checks if the given attributes represent a directory. + + \param uAttr + The attributes to test. + + \return + \c true if the attributes represent a directory; \c false otherwise. + */ + ZIP_API bool IsDirectory(DWORD uAttr); + + /** + Performs the translation between ANSI and OEM character sets. + + \param buffer + The buffer containing characters to be translated. + + \param bAnsiToOem + If \c true, convert ANSI to OEM; if \c false, OEM to ANSI. + */ + ZIP_API void AnsiOem(CZipAutoBuffer& buffer, bool bAnsiToOem); + + /** + Checks if the given file or directory exists. + + \param lpszName + The path to the file or directory to test. + + \return + One of the following values: + - \c -1 : the given file exists and is a directory + - \c 1 : the given file exists and is a regular file + - \c 0 : there is no such a file + */ + ZIP_API int FileExists(LPCTSTR lpszName); + +#ifdef _UNICODE + /** + Converts a wide character string to a multi-byte character string. + + \param lpszIn + The wide character string to convert. + + \param szOut + The buffer to receive the converted string. + Does not contain the terminating \c NULL character. + + \param uCodePage + The code page used in conversion. + + \return + The \a szOut buffer length, or \c -1 when not succeeded. + + \note + Defined only in the UNICODE version. + */ + ZIP_API int WideToMultiByte(LPCWSTR lpszIn, CZipAutoBuffer &szOut, UINT uCodePage); + + /** + Converts a multi-byte character string to a wide character string. + + \param szIn + The multi-byte character string to convert. + Should not contain the terminating \c NULL character. + + \param szOut + Receives the converted string. + + \param uCodePage + The code page used in conversion. + + \return + The length of the string after the conversion (without the terminating \c NULL character) + or \c -1 when the function did not succeed. + + \note + Defined only in the UNICODE version. + */ + ZIP_API int MultiByteToWide(const CZipAutoBuffer &szIn, CZipString& szOut, UINT uCodePage); +#endif +}; + + +#endif // !defined(ZIPARCHIVE_ZIPPLATFORM_DOT_H) + diff --git a/harbour/contrib/hbziparch/ZipPlatformComm.cpp b/harbour/contrib/hbziparch/ZipPlatformComm.cpp new file mode 100644 index 0000000000..a2c1186a5b --- /dev/null +++ b/harbour/contrib/hbziparch/ZipPlatformComm.cpp @@ -0,0 +1,94 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 "ZipFile.h" +#include "ZipPlatform.h" +#include "ZipException.h" + +using namespace ZipPlatform; + +bool ZipPlatform::DirectoryExists(LPCTSTR lpszDir) +{ + CZipString sz; + if (!GetCurrentDirectory(sz)) + return false; + if (!ChangeDirectory(lpszDir)) + return false; + ChangeDirectory(sz); + return true; +} + +bool ZipPlatform::ForceDirectory(LPCTSTR lpDirectory) +{ + ASSERT(lpDirectory); + CZipString szDirectory = lpDirectory; + szDirectory.TrimRight(CZipPathComponent::m_cSeparator); + CZipPathComponent zpc(szDirectory); + if ((zpc.GetFilePath().Compare((LPCTSTR)szDirectory)) == 0 || + (FileExists(szDirectory) == -1)) + return true; + if (!ForceDirectory(zpc.GetFilePath())) + return false; + if (!CreateDirectory(szDirectory)) + return false; + return true; +} + +bool ZipPlatform::GetFileSize(LPCTSTR lpszFileName, ZIP_SIZE_TYPE& dSize) +{ + CZipFile f; + if (!f.Open(lpszFileName, CZipFile::modeRead | CZipFile::shareDenyWrite, false)) + return false; + bool ret; + try + { + ZIP_FILE_USIZE size = f.GetLength(); + // the file may be too large if zip64 is not enabled + ret = size <= ZIP_SIZE_TYPE(-1); + if (ret) + dSize = (ZIP_SIZE_TYPE)size; + } +#ifdef ZIP_ARCHIVE_MFC + catch(CZipBaseException* e) + { + e->Delete(); + ret = false; + } +#else + catch(CZipBaseException e) + { + ret = false; + } +#endif + + try + { + f.Close(); + } +#ifdef ZIP_ARCHIVE_MFC + catch(CZipBaseException* e) + { + e->Delete(); + } +#else + catch(CZipBaseException e) + { + } +#endif + + return ret; +} + + diff --git a/harbour/contrib/hbziparch/ZipStorage.cpp b/harbour/contrib/hbziparch/ZipStorage.cpp new file mode 100644 index 0000000000..a3676d1758 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipStorage.cpp @@ -0,0 +1,615 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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)); +} + diff --git a/harbour/contrib/hbziparch/ZipStorage.h b/harbour/contrib/hbziparch/ZipStorage.h new file mode 100644 index 0000000000..171cb296a5 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipStorage.h @@ -0,0 +1,619 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipStorage.h +* Includes the CZipStorage class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPSTORAGE_DOT_H) +#define ZIPARCHIVE_ZIPSTORAGE_DOT_H + +#if _MSC_VER > 1000 + #pragma once + #if defined ZIP_HAS_DLL + #pragma warning (push) + #pragma warning( disable : 4251 ) // needs to have dll-interface to be used by clients of class + #endif +#endif + +#include "ZipFile.h" +#include "ZipAutoBuffer.h" +#include "ZipString.h" +#include "ZipMemFile.h" +#include "ZipExport.h" +#include "ZipCallback.h" + + + +/** + Represents the storage layer for an archive. +*/ +class ZIP_API CZipStorage +{ + friend class CZipArchive; + friend class CZipCentralDir; +public: + + /** + The type of the segmentation of the archive. + + \see + 0610051553 + \see + CZipArchive::GetSegmMode + */ + enum ZipSegmentationMode + { + 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 + }; + + /** + The direction of seeking operation. + + \see + CZipStorage::Seek + */ + enum SeekType + { + 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. + This value can cause a volume change when a segmented archive is opened for reading. + */ + seekCurrent + }; + 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. + */ + void Open(CZipAbstractFile& af, int iMode); + + /** + Opens or creates an archive. + + The meaning for the parameters is the same as in the CZipArchive::Open(LPCTSTR, int, ZIP_SIZE_TYPE) method. + */ + void Open(LPCTSTR lpszPathName, int iMode, ZIP_SIZE_TYPE uVolumeSize); + + + /** + Closes a segmented archive in creation and reopens it as an existing segmented archive (no modifications allowed). + The archive may also turn out to be a not segmented archive. + */ + void FinalizeSegm(); + + + /** + 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. + + */ + void UpdateSegmMode(ZIP_VOLUME_TYPE uLastVolume); + + /** + Ensures than in a segmented archive, there is enough free space on the current volume. + + \param uNeeded + The size of the required free space in bytes. + + \return + The number of free bytes on the current volume. + + \note + Throws exceptions. + */ + ZIP_SIZE_TYPE AssureFree(ZIP_SIZE_TYPE uNeeded); + + /** + Writes a chunk of data to the archive. + + \param pBuf + The buffer with data. + + \param iSize + The number of bytes to write. + + \param bAtOnce + 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. + + \return + The length of the current archive file increased by the number of bytes in the write buffer. + */ + ZIP_SIZE_TYPE GetOccupiedSpace() const + { + return ZIP_SIZE_TYPE(m_pFile->GetLength() + m_uBytesInWriteBuffer); + } + + /** + The same as the CZipArchive::IsClosed method. + */ + bool IsClosed(bool bArchive) const + { + if (bArchive) + return GetCurrentVolume() == ZIP_VOLUME_NUMBER_UNSPECIFIED; + else + return !m_pFile || !m_bInMemory && m_pFile->IsClosed(); + } + + /** + Reads a chunk of data from the archive. + + \param pBuf + The buffer to receive the data. + + \param iSize + 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). + + \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. + + \return + The position in the file. + + \note + Throws exceptions. + */ + ZIP_SIZE_TYPE GetPosition() const + { + ZIP_SIZE_TYPE uPos = (ZIP_SIZE_TYPE)(m_pFile->GetPosition()) + m_uBytesInWriteBuffer; + if (m_uCurrentVolume == 0) + uPos -= m_uBytesBeforeZip; + return uPos; + } + + + /** + Flushes the data from the read buffer to the disk. + + \note + Throws exceptions. + */ + void Flush(); + + + /** + Forces any data remaining in the file buffer to be written to the disk. + */ + void FlushFile() + { + if (!m_bInMemory && !IsReadOnly()) + m_pFile->Flush(); + } + + void FlushBuffers() + { + Flush(); + FlushFile(); + } + + /** + Changes volumes during writing to a segmented archive. + + \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. + */ + ZIP_VOLUME_TYPE GetCurrentVolume() const {return m_uCurrentVolume;} + + + /** + Changes the volume during extract operations. + + \param uNumber + A zero-based number of the requested volume. + */ + void ChangeVolume(ZIP_VOLUME_TYPE uNumber); + + /** + Changes the current volume to the next volume during extract operations. + */ + void ChangeVolume() + { + ChangeVolume((ZIP_VOLUME_TYPE)(m_uCurrentVolume + 1)); + } + + /** + 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. + */ + int IsSegmented() const + { + return m_iSegmMode == noSegments ? 0 : (m_bNewSegm ? 1 : -1); + } + + /** + Checks, if the archive is a split archive. + + \return + \c true, if the archive is a split archive; \c false otherwise. + */ + bool IsSplit() const + { + return m_iSegmMode == splitArchive; + } + + /** + Checks, if 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; + } + + /** + The same as the CZipArchive::IsReadOnly method. + */ + bool IsReadOnly() + { + return m_bReadOnly || IsSegmented() < 0; + } + + /** + Performs the seeking operation on the #m_pFile. + + \param lOff + The new position in the file. + + \param iSeekType + The direction of the seek operation. + It can be one of the #SeekType values. + */ + ULONGLONG Seek(ULONGLONG lOff, SeekType iSeekType = seekFromBeginning); + + /** + Gets the number of free bytes on the current volume. + + \return + The number of free bytes on the current volume. + */ + ZIP_SIZE_TYPE VolumeLeft() const; + + /** + Closes the storage. + + \param bAfterException + Set to \c true, if an exception was thrown before. + + \return + The file path of the archive. + + \note + Throws exceptions. + */ + CZipString Close(bool bAfterException); + + /** + Represents the physical storage of the current archive segment. + */ + CZipAbstractFile* m_pFile; + + /** + The signature of the extended header. + */ + static char m_gszExtHeaderSignat[]; + +protected: + + /** + Returns the file offset after the last data byte in the archive. + + \return + The file offset after the last data byte in the archive. + */ + ZIP_SIZE_TYPE GetLastDataOffset() + { + 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. + */ + void EmptyWriteBuffer() + { + m_uBytesInWriteBuffer = 0; + } + + /** + Opens a physical file. + + \param lpszName + The name of the file to open. + + \param uFlags + The file open flags. + + \param bThrow + If \c true, throw an exception in case of failure. + + \return + \c true if successful; \c false otherwise. + */ + bool OpenFile(LPCTSTR lpszName, UINT uFlags, bool bThrow = true); + + /** + Renames the last segment file in a split archive when finalizing the whole archive. + + \return + The name of the last segment. + */ + CZipString RenameLastFileInSplitArchive(); + + /** + Writes data to the internal buffer. + + \param *pBuf + The buffer to copy the data from. + + \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. + + \return + The free space in bytes. + */ + ZIP_SIZE_TYPE GetFreeVolumeSpace() const; + + /** + Notifies the callback object. + Throws an exception if the callback method returns \c false. + + \param uNeeded + The minimum number of free bytes required on the disk. + + \param iCode + The code to be passed to the callback method. + + \param szTemp + 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 + 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(); + + /** + Changes a disk when processing a spanned archive. + */ + CZipString ChangeSpannedRead(); + + /** + Gets the free space left in the write buffer. + + \return + The free space left in the write buffer 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. + + 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 spanned archive: the free space on the current volume. + */ + ZIP_SIZE_TYPE m_uCurrentVolSize; + + /** + The write buffer caching data. + */ + CZipAutoBuffer m_pWriteBuffer; + + /** + 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; + + /** + 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 + CZipArchive::GetBytesBeforeZip + */ + ZIP_SIZE_TYPE m_uBytesBeforeZip; + + + /** + The size of the write buffer. + + \see + CZipArchive::SetAdvanced + */ + int m_iWriteBufferSize; + + /** + The size of the buffer used in searching for the central directory. + + \see + CZipArchive::SetAdvanced + */ + int m_iLocateBufferSize; + + /** + Takes one of the #ZipSegmentationMode values. + */ + int m_iSegmMode; + + /** + A callback object called when there is a need for a volume change + in a spanned archive. + + \see + CZipArchive::SetSegmCallback + */ + CZipSegmCallback* m_pSpanChangeVolumeFunc; + + /** + A callback object called when there is a need for a volume change + in a split archive. + + \see + CZipArchive::SetSegmCallback + */ + CZipSegmCallback* m_pSplitChangeVolumeFunc; +private: + CZipSegmCallback* m_pChangeVolumeFunc; + CZipString m_szArchiveName; + CZipFile m_internalfile; + static const ZIP_FILE_USIZE SignatureNotFound; + void ThrowError(int err); +}; + +#if (_MSC_VER > 1000) && (defined ZIP_HAS_DLL) + #pragma warning (pop) +#endif + + +#endif // !defined(ZIPARCHIVE_ZIPSTORAGE_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipString.h b/harbour/contrib/hbziparch/ZipString.h new file mode 100644 index 0000000000..dce1f3537f --- /dev/null +++ b/harbour/contrib/hbziparch/ZipString.h @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipString.h +* Includes the CZipString class. +* +*/ + + +#ifndef ZIPARCHIVE_ZIPSTRING_DOT_H +#define ZIPARCHIVE_ZIPSTRING_DOT_H + +#if _MSC_VER > 1000 + #pragma once +#endif + +#include "_platform.h" + +#ifdef ZIP_ARCHIVE_STL + #include "ZipString_stl.h" +#else + #include "ZipString_mfc.h" +#endif + +#endif /* ZIPARCHIVE_ZIPSTRING_DOT_H */ diff --git a/harbour/contrib/hbziparch/ZipStringStoreSettings.h b/harbour/contrib/hbziparch/ZipStringStoreSettings.h new file mode 100644 index 0000000000..f6069c8ac5 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipStringStoreSettings.h @@ -0,0 +1,210 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file ZipStringStoreSettings.h +* Includes the CZipStringStoreSettings class. +* +*/ + +#if !defined(ZIPARCHIVE_ZIPSTRINGSTRINGSTORESETTINGS_DOT_H) +#define ZIPARCHIVE_ZIPSTRINGSTRINGSTORESETTINGS_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "stdafx.h" +#include "ZipPlatform.h" +#include "ZipCompatibility.h" + + +/** + Settings used in storing strings inside archives. + + \see + 0610051525 + \see + CZipArchive::SetStringStoreSettings. +*/ +class ZIP_API CZipStringStoreSettings +{ +public: + + /** + Gets the default filename code page for the given platform. + + \param iPlatform + One of the ZipCompatibility::ZipPlatforms values. + + \return + The default filename code page. + */ + static UINT GetDefaultNameCodePage(int iPlatform) + { + return iPlatform == ZipCompatibility::zcDosFat ? CP_OEMCP : CP_ACP; + } + + /** + Gets the default filename code page for the current platform. + + \return + The default filename code page. + */ + static UINT GetDefaultNameCodePage() + { + return GetDefaultNameCodePage(ZipPlatform::GetSystemID()); + } + + /** + Gets the default comment code page. It is not platform-dependent. + */ + static UINT GetDefaultCommentCodePage() + { + return CP_ACP; + } + + /** + Initializes a new instance of the CZipStringStoreSettings class. + */ + CZipStringStoreSettings() + { + Reset(); + } + + /** + Sets the default filename code page depening on the given platform. + + \param iPlatform + One of the ZipCompatibility::ZipPlatforms values. + */ + void SetDefaultNameCodePage(int iPlatform) + { + m_uNameCodePage = GetDefaultNameCodePage(iPlatform); + } + + /** + Gets a value indicating whether the current filename code page is + standard for the current platform or not. + + \return + \c true, if the current filename code page is standard; \c false otherwise. + + \see + ZipPlatform::GetSystemID + */ + bool IsStandardNameCodePage() const + { + return m_uNameCodePage == GetDefaultNameCodePage(); + } + + /** + Gets a value indicating whether the current filename code page is + standard for the given platform or not. + + \param iPlatform + One of the ZipCompatibility::ZipPlatforms values. + + \return + \c true, if the current filename code page is standard; \c false otherwise. + */ + bool IsStandardNameCodePage(int iPlatform) const + { + return m_uNameCodePage == GetDefaultNameCodePage(iPlatform); + } + + /** + Gets a value indicating whether the current comment code page is standard. + + \return + \c true, if the current comment code page is standard; \c false otherwise. + */ + bool IsStandardCommentCodePage() const + { + return m_uCommentCodePage == GetDefaultCommentCodePage(); + } + + /** + Gets a value indicating whether the current settings are + standard for the given platform or not. + + \param iPlatform + One of the ZipCompatibility::ZipPlatforms values. + + \return + \c true, if the current settings are standard; \c false otherwise. + */ + bool IsStandard(int iPlatform) const + { + return !m_bStoreNameInExtraData && IsStandardNameCodePage(iPlatform) && IsStandardCommentCodePage(); + } + + /** + Reset the settings to its default values for the given platform. + + \param iPlatform + One of the ZipCompatibility::ZipPlatforms values. + \see + Reset + */ + void Reset(int iPlatform) + { + m_bStoreNameInExtraData = false; + SetDefaultNameCodePage(iPlatform); + m_uCommentCodePage = GetDefaultCommentCodePage(); + } + + /** + Reset the settings to its default values for the current platform. + + \see + Reset(int) + \see + ZipPlatform::GetSystemID + */ + void Reset() + { + Reset(ZipPlatform::GetSystemID()); + } + + /** + Sets the string store settings. + + \see + CZipArchive::SetStringStoreSettings(UINT, bool, UINT) + */ + void Set(UINT uFileNameCodePage, bool bStoreNameInExtraData, UINT uCommentCodePage) + { + m_uNameCodePage = uFileNameCodePage; + m_bStoreNameInExtraData = bStoreNameInExtraData; + m_uCommentCodePage = uCommentCodePage; + } + + /** + If \c true, the converted filenames are stored in extra field in the archive. + */ + bool m_bStoreNameInExtraData; + + /** + The current filename code page. + */ + UINT m_uNameCodePage; + + /** + The current comment code page. + */ + UINT m_uCommentCodePage; +}; + +#endif // !defined(ZIPARCHIVE_ZIPSTRINGSTRINGSTORESETTINGS_DOT_H) diff --git a/harbour/contrib/hbziparch/ZipString_mfc.h b/harbour/contrib/hbziparch/ZipString_mfc.h new file mode 100644 index 0000000000..493a21c02c --- /dev/null +++ b/harbour/contrib/hbziparch/ZipString_mfc.h @@ -0,0 +1,34 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPSTRING_DOT_H + #error Do not include this file directly. Include ZipString.h instead +#endif + + +#include "stdafx.h" +#include "ZipExport.h" + +typedef CString CZipString; + +/** + A pointer type to point to one of: Collate, CollateNoCase, Compare, CompareNoCase. +*/ +typedef int (CZipString::*ZIPSTRINGCOMPARE)( LPCTSTR ) const; + +/** + Return a pointer to a method in the CZipString structure, + used to compare elements depending on the arguments. +*/ +ZIP_API ZIPSTRINGCOMPARE GetCZipStrCompFunc(bool bCaseSensitive, bool bCollate = true); diff --git a/harbour/contrib/hbziparch/ZipString_stl.h b/harbour/contrib/hbziparch/ZipString_stl.h new file mode 100644 index 0000000000..f9168758e3 --- /dev/null +++ b/harbour/contrib/hbziparch/ZipString_stl.h @@ -0,0 +1,328 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_ZIPSTRING_DOT_H + #error Do not include this file directly. Include ZipString.h instead +#endif + +#include "stdafx.h" + +#if _MSC_VER > 1000 + #pragma warning( push, 3 ) // STL requirements +#endif + + +#include +#include +#include +#include +#include +#include + +#include "ZipExport.h" + +#ifndef __GNUC__ + #ifndef _vsntprintf + #ifdef _UNICODE + #define _vsntprintf _vsnwprintf + #else + #define _vsntprintf _vsnprintf + #endif + #endif +#elif !defined(_vsntprintf) + #define _vsntprintf vsnprintf +#endif + +typedef std::basic_string stdbs; +/** + It contains mostly the methods required by ZipArchive Library. +*/ +class ZIP_API CZipString : public stdbs +{ + void TrimInternalL(size_type iPos) + { + if (iPos == npos) + erase (); + if (iPos) + erase(0, iPos); + } + void TrimInternalR(size_type iPos) + { + if (iPos == npos) + erase (); + erase(++iPos); + } + +#ifndef __GNUC__ + static int zslen(const TCHAR* lpsz) + { + if (!lpsz) return 0; + + // we want to take into account the locale stuff (by using standard templates) + + #ifdef _UNICODE + return (int)std::wstring(lpsz).length(); + #else + return (int)std::string(lpsz).length(); + #endif + } +#else + static int zslen(const TCHAR* lpsz) + { + #if (__GNUC__ < 3) // I'm not sure which precisely version should be put here + return lpsz ? std::string_char_traits::length(lpsz) : 0; + #else + return lpsz ? std::char_traits::length(lpsz) : 0; + #endif + + } +#endif + +static TCHAR tl(TCHAR c) +{ + // use_facet doesn't work here well (doesn't convert all the local characters properly) + return std::tolower(c, std::locale()); +} +static TCHAR tu(TCHAR c) +{ + // use_facet doesn't work here well (doesn't convert all the local characters properly) + return std::toupper(c, std::locale()); +} + +public: + CZipString(){} + explicit CZipString (TCHAR ch, int nRepeat = 1):stdbs(nRepeat, ch){} + CZipString( const CZipString& stringSrc ) {assign(stringSrc);} + CZipString( const stdbs& stringSrc ) {assign(stringSrc);} + CZipString( LPCTSTR lpsz ){if (!lpsz) Empty(); else assign(lpsz);} + operator LPCTSTR() const{return c_str();} + + int GetLength() const {return (int) size();} + bool IsEmpty() const {return empty();} + void Empty() {erase(begin(), end());} + TCHAR GetAt (int iIndex) const{return at(iIndex);} + TCHAR operator[] (int iIndex) const{return at(iIndex);} + void SetAt( int nIndex, TCHAR ch ) {at(nIndex) = ch;} + LPTSTR GetBuffer(int nMinBufLength) + { + if ((int)size() < nMinBufLength) + resize(nMinBufLength); + return empty() ? const_cast(data()) : &(at(0)); + } + void ReleaseBuffer( int nNewLength = -1 ) { resize(nNewLength > -1 ? nNewLength : zslen(c_str()));} + void TrimLeft( TCHAR chTarget ) + { + TrimInternalL(find_first_not_of(chTarget)); + } + void TrimLeft( LPCTSTR lpszTargets ) + { + TrimInternalL(find_first_not_of(lpszTargets)); + } + void TrimRight( TCHAR chTarget ) + { + TrimInternalR(find_last_not_of(chTarget)); + } + void TrimRight( LPCTSTR lpszTargets ) + { + TrimInternalR(find_last_not_of(lpszTargets)); + } + +#if _MSC_VER >= 1300 + #pragma warning( push ) + #pragma warning (disable : 4793) // 'vararg' : causes native code generation for function 'void CZipString::Format(LPCTSTR,...)' +#endif + + void Format(LPCTSTR lpszFormat, ...) + { + va_list arguments; + va_start (arguments, lpszFormat); + TCHAR* pBuf = NULL; + int iCounter = 1, uTotal = 0; + do + { + int nChars = iCounter * 1024; + int nLen = sizeof(TCHAR) * nChars; + + TCHAR* pTempBuf = (TCHAR*)realloc((void*)pBuf, nLen); + if (!pTempBuf) + { + if (pBuf != NULL) + free(pBuf); + va_end (arguments); + return; + } + pBuf = pTempBuf; + +#if _MSC_VER >= 1400 + uTotal = _vsntprintf_s(pBuf, nChars, nChars - 1, lpszFormat, arguments); +#else + uTotal = _vsntprintf(pBuf, nChars - 1, lpszFormat, arguments); +#endif + + if (uTotal == -1 || (uTotal == nChars - 1) ) // for some implementations + { + pBuf[nChars - 1] = _T('\0'); + if (iCounter == 7) + break; + } + else + { + pBuf[uTotal] = _T('\0'); + break; + } + iCounter++; + + } while (true); + + va_end (arguments); + *this = pBuf; + free(pBuf); + } + +#if _MSC_VER >= 1300 + #pragma warning( pop ) +#endif + + void Insert( int nIndex, LPCTSTR pstr ){insert(nIndex, pstr, zslen(pstr));} + void Insert( int nIndex, TCHAR ch ) {insert(nIndex, 1, ch);} + int Delete( int nIndex, int nCount = 1 ) + { + int iSize = (int) size(); + int iToDelete = iSize < nIndex + nCount ? iSize - nIndex : nCount; + if (iToDelete > 0) + { + erase(nIndex, iToDelete); + iSize -= iToDelete; + } + return iSize; + } +#ifndef __MINGW32__ + void MakeLower() + { + std::transform(begin(),end(),begin(),tl); + } + void MakeUpper() + { + std::transform(begin(),end(),begin(),tu); + } +#else + void MakeLower() + { + std::transform(begin(),end(),begin(),tolower); + } + void MakeUpper() + { + std::transform(begin(),end(),begin(),toupper); + } +#endif + void MakeReverse() + { + std::reverse(begin(), end()); + + } + CZipString Left( int nCount ) const { return substr(0, nCount);} + CZipString Right( int nCount) const + { + nCount = (int)size() < nCount ? (int)size() : nCount; + return substr(size() - nCount); + } + CZipString Mid( int nFirst ) const {return substr(nFirst);} + CZipString Mid( int nFirst, int nCount ) const {return substr(nFirst, nCount);} + int Collate( LPCTSTR lpsz ) const + { +#if !defined __GNUC__ || defined __MINGW32__ + return _tcscoll(c_str(), lpsz); +#else + //return compare(lpsz); + return strcoll(c_str(), lpsz); +#endif + } + + int CollateNoCase( LPCTSTR lpsz ) const + { +#if !defined __GNUC__ || defined __MINGW32__ + return _tcsicoll(c_str(), lpsz); +#else + if (std::locale() == std::locale::classic()) + return strcasecmp(c_str(), lpsz); + else + // this may be not case-insensitive !!! + return strcoll(c_str(), lpsz); + //return stricoll(c_str(), lpsz); +#endif + } + + int Compare( LPCTSTR lpsz ) const + { + return compare(lpsz); + } + + int CompareNoCase( LPCTSTR lpsz ) const + { +#if !defined __GNUC__ || defined __MINGW32__ + return _tcsicmp(c_str(), lpsz); +#else + return strcasecmp(c_str(), lpsz); + //return stricmp(c_str(), lpsz); +#endif + } + + bool operator != (LPCTSTR lpsz) + { + return Compare(lpsz) != 0; + } + bool operator == (LPCTSTR lpsz) + { + return Compare(lpsz) == 0; + } + int Find( TCHAR ch, int nStart = 0) const + { + return (int) find(ch, nStart); + } + + int Find( LPCTSTR pstr, int nStart = 0) const + { + return (int) find(pstr, nStart); + } + + int Replace( TCHAR chOld, TCHAR chNew ) + { + int iCount = 0; + for (iterator it = begin(); it != end(); ++it) + if (*it == chOld) + { + *it = chNew; + iCount++; + } + return iCount; + } + +}; + +/** + A poiter type to point to CZipString to Collate or CollateNoCase + or Compare or CompareNoCase +*/ +typedef int (CZipString::*ZIPSTRINGCOMPARE)( LPCTSTR ) const; + +/** + return a pointer to the function in CZipString structure, + used to compare elements depending on the arguments +*/ + ZIP_API ZIPSTRINGCOMPARE GetCZipStrCompFunc(bool bCaseSensitive, bool bCollate = true); + + +#if _MSC_VER > 1000 + #pragma warning( pop) +#endif diff --git a/harbour/contrib/hbziparch/_features.h b/harbour/contrib/hbziparch/_features.h new file mode 100644 index 0000000000..f1bb739d96 --- /dev/null +++ b/harbour/contrib/hbziparch/_features.h @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file _features.h +* Contains definitions that enable or disable certain features in the ZipArchive Library. +* +*/ + +#if !defined(ZIPARCHIVE_FEATURES_DOT_H) +/// @cond +#define ZIPARCHIVE_FEATURES_DOT_H +/// @endcond + +#if _MSC_VER > 1000 +#pragma once +#endif + +#include "_platform.h" + +#ifdef __GNUC__ + +#ifndef __int64 + #define __int64 long long +#endif + +#endif + +/************ Feel free to adjust the definitions in the following block ************/ +/************************************ BLOCK START ***********************************/ + +/** + Make sure it is defined, if you use ZIP64. Comment this out otherwise. + + \see + 0610051629 +*/ +// #define _ZIP64 + +/** + Make sure it is defined, if you use AES. Comment this out otherwise. + + \see + 0610201627|aes +*/ +// #define _ZIP_AES + +/** + Make sure it is defined, if you use the BZIP2 algorithm for compression. Comment this out otherwise. + + \see + 0610231446|bzip2 +*/ +// #define _BZIP2 + +/** + Make sure it is defined, if you want to create seekable data. + + \see + 0711101739 + +*/ +// #define _ZIP_SEEK + +/** + Make sure it is defined, if you use the AES encryption in a multithreaded environment or archive sharing (CZipArchive::OpenFrom). Comment this out otherwise. + + \see + 0610201627|aes + \see + 0610241003|thread +*/ +// #define ZIP_ARCHIVE_USE_LOCKING + +#ifndef _ZIP64 +// Uncomment this to have the index and volume numbers types defined as WORD. Otherwise they are defined as int. +#define _ZIP_STRICT_U16 +#endif + + +/************************************* BLOCK END ***********************************/ +/***** The contents below this line are usually not intended for modification ******/ + + + +#endif // !defined(ZIPARCHIVE_FEATURES_DOT_H) diff --git a/harbour/contrib/hbziparch/_platform.h b/harbour/contrib/hbziparch/_platform.h new file mode 100644 index 0000000000..eb60e14390 --- /dev/null +++ b/harbour/contrib/hbziparch/_platform.h @@ -0,0 +1,76 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +/** +* \file _platform.h +* Contains definitions that determine the target compilation platform. +* +*/ + +#if !defined(ZIPARCHIVE_PLATFORM_DOT_H) +#define ZIPARCHIVE_PLATFORM_DOT_H + +#if _MSC_VER > 1000 +#pragma once +#endif + +/************ Feel free to adjust the definitions in the following block ************/ +/************************************ BLOCK START ***********************************/ + +//#define ZIP_ARCHIVE_MFC +//#define ZIP_ARCHIVE_LNX + +// simplified endianess detection +#ifdef __APPLE__ + #ifdef __LITTLE_ENDIAN__ + #define ZIP_ARCHIVE_LITTLE_ENDIAN + #endif +#else + #define ZIP_ARCHIVE_LITTLE_ENDIAN +#endif + +/************************************* BLOCK END ***********************************/ +/********* The contents below this line are not intended for modification **********/ + +#ifndef ZIP_ARCHIVE_MFC + #define ZIP_ARCHIVE_STL +#else + #ifdef ZIP_ARCHIVE_STL + #undef ZIP_ARCHIVE_STL + #endif +#endif + +#ifndef ZIP_ARCHIVE_LNX + #define ZIP_ARCHIVE_WIN +#else + #ifdef ZIP_ARCHIVE_WIN + #undef ZIP_ARCHIVE_WIN + #endif +#endif + +#ifndef ZIP_ARCHIVE_LITTLE_ENDIAN + #define ZIP_ARCHIVE_BIG_ENDIAN +#else + #ifdef ZIP_ARCHIVE_BIG_ENDIAN + #undef ZIP_ARCHIVE_BIG_ENDIAN + #endif +#endif + +#if defined (ZIP_ARCHIVE_LNX) && defined (ZIP_ARCHIVE_MFC) + #undef ZIP_ARCHIVE_MFC + #define ZIP_ARCHIVE_STL + #error Using MFC under a non-Windows platform is not supported +#endif + +#endif // !defined(ZIPARCHIVE_PLATFORM_DOT_H) diff --git a/harbour/contrib/hbziparch/std_mfc.h b/harbour/contrib/hbziparch/std_mfc.h new file mode 100644 index 0000000000..f0f0b6f72d --- /dev/null +++ b/harbour/contrib/hbziparch/std_mfc.h @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_STDAFX_DOT_H + #error Do not include this file directly. Include stdafx.h instead +#endif + +#if _MSC_VER > 1000 +#ifndef WINVER + #define WINVER 0x0400 +#endif +#pragma once +#endif + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#ifndef VC_EXTRALEAN + #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include +#include + +typedef BOOL ZBOOL; + +#if _MSC_VER >= 1300 || defined ZIP_FILE_USES_STL + #define ZIP_FILE_USIZE ULONGLONG + #define ZIP_FILE_SIZE LONGLONG + #define ZIP_FILE_SIZEMAX _I64_MAX +#else + #define ZIP_FILE_USIZE DWORD + #define ZIP_FILE_SIZE LONG + #define ZIP_FILE_SIZEMAX MAXLONG +#endif \ No newline at end of file diff --git a/harbour/contrib/hbziparch/std_stl.h b/harbour/contrib/hbziparch/std_stl.h new file mode 100644 index 0000000000..f5a67df59e --- /dev/null +++ b/harbour/contrib/hbziparch/std_stl.h @@ -0,0 +1,126 @@ +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// + +#ifndef ZIPARCHIVE_STDAFX_DOT_H + #error Do not include this file directly. Include stdafx.h instead +#endif + +#include "_features.h" + +#if _MSC_VER > 1000 + // STL warnings + #pragma warning (disable : 4710) // 'function' : function not inlined + #pragma warning (disable : 4514) // unreferenced inline/local function has been removed + #pragma warning (disable : 4786) // 'identifier' : identifier was truncated to 'number' characters in the debug information + #pragma warning (disable : 4702) // unreachable code +#endif + +#if defined (_UNICODE) && !defined (UNICODE) + #define UNICODE +#endif +#if defined (UNICODE) && !defined (_UNICODE) + #define _UNICODE +#endif + +#ifndef _WIN32 + #ifndef NULL + #define NULL 0 + #endif + + #include + typedef int HFILE; + typedef void* HANDLE; + typedef unsigned long DWORD; + typedef long LONG; + typedef int ZBOOL; /* to avoid conflicts when using Objective-C under Mac */ + typedef unsigned char BYTE; + typedef unsigned short WORD; + typedef unsigned int UINT; + + #ifndef FALSE + #define FALSE (int)0 + #endif + + #ifndef TRUE + #define TRUE (int)1 + #endif + + + typedef unsigned short WCHAR; // wc, 16-bit UNICODE character + typedef const WCHAR *LPCWSTR; + typedef const char *LPCSTR; + typedef WCHAR *LPWSTR; + typedef char *LPSTR; + + #ifdef _UNICODE + typedef wchar_t TCHAR; + typedef LPCWSTR LPCTSTR; + typedef LPWSTR LPTSTR; + #define _T(x) L ## x + #else /* _UNICODE */ // r_winnt + typedef char TCHAR; + typedef LPCSTR LPCTSTR; + typedef LPSTR LPTSTR; + #ifdef _T + #undef _T + #endif + #define _T(x) x + #endif /* _UNICODE */ // r_winnt + + typedef unsigned long long ULONGLONG; + typedef long long LONGLONG; + #define CP_ACP 0 + #define CP_OEMCP 1 + + #ifndef _I64_MAX + #ifdef LLONG_MAX + #define _I64_MAX LLONG_MAX + #else + #define _I64_MAX LONG_LONG_MAX + #endif + #endif + #ifndef _UI64_MAX + #ifdef ULLONG_MAX + #define _UI64_MAX ULLONG_MAX + #else + #define _UI64_MAX ULONG_LONG_MAX + #endif + #endif + #define _lseeki64 lseek64 +#else + #include + #include + #include + #ifndef STRICT + #define STRICT + #endif + typedef BOOL ZBOOL; + +#endif // #ifndef _WIN32 + +#ifndef ASSERT + #include + #define ASSERT(f) assert((f)) +#endif +#ifndef VERIFY + #ifdef _DEBUG + #define VERIFY(x) ASSERT((x)) + #else + #define VERIFY(x) x + #endif +#endif + +#define ZIP_FILE_USIZE ULONGLONG +#define ZIP_FILE_SIZE LONGLONG +#define ZIP_FILE_SIZEMAX _I64_MAX