diff options
Diffstat (limited to 'zip/ZipArchive/ZipFileHeader.cpp')
| -rw-r--r-- | zip/ZipArchive/ZipFileHeader.cpp | 1007 |
1 files changed, 731 insertions, 276 deletions
diff --git a/zip/ZipArchive/ZipFileHeader.cpp b/zip/ZipArchive/ZipFileHeader.cpp index e9bb080..6ab75d3 100644 --- a/zip/ZipArchive/ZipFileHeader.cpp +++ b/zip/ZipArchive/ZipFileHeader.cpp @@ -1,6 +1,6 @@ ////////////////////////////////////////////////////////////////////////////////
-// This source file is part of the ZipArchive library source distribution and
-// is Copyrighted 2000 - 2007 by Artpol Software - Tadeusz Dracz
+// This source file is part of the ZipArchive Library Open Source distribution
+// and is Copyrighted 2000 - 2022 by Artpol Software - Tadeusz Dracz
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
@@ -9,7 +9,7 @@ //
// For the licensing details refer to the License.txt file.
//
-// Web Site: http://www.artpol-software.com
+// Web Site: https://www.artpol-software.com
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
@@ -22,42 +22,63 @@ #include "ZipCrc32Cryptograph.h"
#include "BytesWriter.h"
+#include "zlib/zlib.h"
#define FILEHEADERSIZE 46
#define LOCALFILEHEADERSIZE 30
-#define ZIP_EXTRA_ZARCH_NAME_VER 1
+#ifdef _ZIP_UNICODE_CUSTOM
+ #define ZIP_EXTRA_ZARCH_NAME_VER 1
+#endif
+#define ZIP_EXTRA_NTFS_TAG 0x0001
using namespace ZipArchiveLib;
char CZipFileHeader::m_gszSignature[] = {0x50, 0x4b, 0x01, 0x02};
char CZipFileHeader::m_gszLocalSignature[] = {0x50, 0x4b, 0x03, 0x04};
+#pragma warning(suppress: 26495)
CZipFileHeader::CZipFileHeader()
{
+ Initialize(NULL);
+ SetSystemCompatibility(ZipPlatform::GetSystemID());
+}
+
+#pragma warning(suppress: 26495)
+CZipFileHeader::CZipFileHeader(CZipCentralDir* pCentralDir)
+{
+ Initialize(pCentralDir);
+}
+
+CZipFileHeader::~CZipFileHeader()
+{
+
+}
+
+void CZipFileHeader::Initialize(CZipCentralDir* pCentralDir)
+{
m_uExternalAttr = 0;//ZipPlatform::GetDefaultAttributes();
m_uModDate = m_uModTime = 0;
+ m_tModificationTime = m_tCreationTime = m_tLastAccessTime = (time_t)0;
m_uMethod = CZipCompressor::methodDeflate;
- m_uVersionMadeBy = 0;
+ 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_uLocalHeaderSize = 0;
m_uVolumeStart = 0;
- m_pszFileName = NULL;
m_uEncryptionMethod = CZipCryptograph::encNone;
m_bIgnoreCrc32 = false;
m_uFlag = 0;
+ m_pCentralDir = pCentralDir;
+ m_state = sfNone;
}
-CZipFileHeader::~CZipFileHeader()
+bool CZipFileHeader::Read(bool bReadSignature)
{
- if (m_pszFileName != NULL)
- delete m_pszFileName;
-}
+ m_state = sfNone;
-bool CZipFileHeader::Read(CZipCentralDir& centralDir, bool bReadSignature)
-{
- CZipStorage *pStorage = centralDir.m_pStorage;
+ CZipStorage *pStorage = m_pCentralDir->GetStorage();
WORD uFileNameSize, uCommentSize, uExtraFieldSize;
CZipAutoBuffer buf(FILEHEADERSIZE);
if (bReadSignature)
@@ -69,7 +90,8 @@ bool CZipFileHeader::Read(CZipCentralDir& centralDir, bool bReadSignature) else
pStorage->Read((char*)buf + 4, FILEHEADERSIZE - 4, true);
- CBytesWriter::ReadBytes(m_uVersionMadeBy, buf + 4);
+ WORD uVersionMadeBy;
+ CBytesWriter::ReadBytes(uVersionMadeBy, buf + 4);
CBytesWriter::ReadBytes(m_uVersionNeeded, buf + 6);
CBytesWriter::ReadBytes(m_uFlag, buf + 8);
CBytesWriter::ReadBytes(m_uMethod, buf + 10);
@@ -87,96 +109,137 @@ bool CZipFileHeader::Read(CZipCentralDir& centralDir, bool bReadSignature) CBytesWriter::ReadBytes(m_uOffset, buf + 42, 4);
buf.Release();
+ m_uVersionMadeBy = uVersionMadeBy & 0xFF;
+ SetSystemCompatibility((uVersionMadeBy & 0xFF00) >> 8);
+
// 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);
+ ZIP_VOLUME_TYPE uCurDsk = pStorage->GetCurrentVolume();
+ m_fileName.m_buffer.Allocate(uFileNameSize); // don't add NULL at the end
+ pStorage->Read(m_fileName.m_buffer, uFileNameSize, true);
+
+#ifdef _ZIP_UNICODE_CUSTOM
+ const CZipStringStoreSettings& stringStoreSettings = m_pCentralDir->GetStringStoreSettings();
- if (centralDir.m_pStringSettings->IsStandardNameCodePage())
+ if (stringStoreSettings.IsStandardNameCodePage())
m_stringSettings.SetDefaultNameCodePage(GetSystemCompatibility());
else
- m_stringSettings.m_uNameCodePage = centralDir.m_pStringSettings->m_uNameCodePage;
+ m_stringSettings.m_uNameCodePage = stringStoreSettings.m_uNameCodePage;
- if (!centralDir.m_pStringSettings->IsStandardCommentCodePage())
- m_stringSettings.m_uCommentCodePage = centralDir.m_pStringSettings->m_uCommentCodePage;
+ if (!stringStoreSettings.IsStandardCommentCodePage())
+ m_stringSettings.m_uCommentCodePage = stringStoreSettings.m_uCommentCodePage;
+#endif
- if (!m_aCentralExtraData.Read(pStorage, uExtraFieldSize))
+ if (!m_aCentralExtraData.Read(pStorage, uExtraFieldSize) && m_pCentralDir->IsConsistencyCheckOn(CZipArchive::checkInvalidExtraData))
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
+ CZipExtraData* pExtra = m_aCentralExtraData.Lookup(ZIP_EXTRA_NTFS);
+ if (pExtra != NULL && pExtra->m_data.GetSize() >= 32)
+ {
+ WORD temp;
+ CBytesWriter::ReadBytes(temp, pExtra->m_data + 4);
+ if (temp == ZIP_EXTRA_NTFS_TAG)
{
- offset++;
- if (offset > uExtraDataSize)
- return false;
- BYTE flag = pExtra->m_data[1];
- bool bReadCommentCp = (flag & 4) != 0;
- if ((flag & 1) != 0)
+ CBytesWriter::ReadBytes(temp, pExtra->m_data + 6);
+ if (temp == 24)
{
- // 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;
+ m_tModificationTime = ReadFileTime(pExtra->m_data + 8);
+ m_tCreationTime = ReadFileTime(pExtra->m_data + 16);
+ m_tLastAccessTime = ReadFileTime(pExtra->m_data + 24);
}
+ }
+ }
- 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)
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state == sfNone)
+ {
+ pExtra = m_aCentralExtraData.Lookup(ZIP_EXTRA_ZARCH_NAME);
+ if (pExtra != NULL)
+ {
+ m_state = sfCustomUnicode;
+
+ 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
{
- // code page present
- if (offset + 4 > uExtraDataSize)
+ offset++;
+ if (offset > uExtraDataSize)
return false;
- DWORD temp;
- CBytesWriter::ReadBytes(temp, pExtra->m_data + offset);
- m_stringSettings.m_uCommentCodePage = temp;
- // offset += 4;
- }
+ 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;
+ // just in case
+ m_fileName.ClearString();
+ m_fileName.m_buffer.Allocate(iFileNameSize);
+ memcpy(m_fileName.m_buffer, pExtra->m_data + offset, iFileNameSize);
+ offset += iFileNameSize;
+ }
+ 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;
+ }
+ }
+ }
+ else if ((m_pCentralDir->GetUnicodeMode() & CZipArchive::umCustom) != 0)
+ {
+ m_state = sfCustomUnicode;
}
}
+#endif
+
if (uCommentSize)
{
- m_pszComment.Allocate(uCommentSize);
- pStorage->Read(m_pszComment, uCommentSize, true);
+ m_comment.m_buffer.Allocate(uCommentSize);
+ pStorage->Read(m_comment.m_buffer, uCommentSize, true);
}
-
- return pStorage->GetCurrentVolume() == uCurDsk; // check that the whole header is in one volume
+
+ m_aCentralExtraData.RemoveInternalHeaders();
+
+ return pStorage->GetCurrentVolume() == uCurDsk || pStorage->IsBinarySplit(); // check that the whole header is in one volume
}
-time_t CZipFileHeader::GetTime()const
+time_t CZipFileHeader::GetModificationTime()const
{
+ if (m_tModificationTime != (time_t) 0)
+ {
+ return m_tModificationTime;
+ }
struct tm atm;
atm.tm_sec = (m_uModTime & ~0xFFE0) << 1;
atm.tm_min = (m_uModTime & ~0xF800) >> 5;
@@ -189,95 +252,214 @@ time_t CZipFileHeader::GetTime()const return mktime(&atm);
}
+void CZipFileHeader::SetModificationTime(const time_t& ttime, bool bFullResolution, bool bUseUtcTime)
+{
+ if (bFullResolution)
+ {
+ m_tModificationTime = ttime;
+ }
+ else
+ {
+ m_tModificationTime = m_tCreationTime = m_tLastAccessTime = (time_t)0;
+ }
+#if _MSC_VER >= 1400
+ tm gts;
+ tm* gt = >s;
+ if (bUseUtcTime)
+ {
+ gmtime_s(gt, &ttime);
+ }
+ else
+ {
+ localtime_s(gt, &ttime);
+ }
+#else
+ tm* gt;
+ if (bUseUtcTime)
+ {
+ gt = gmtime(&ttime);
+ }
+ else
+ {
+ 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::WriteFileTime(const time_t& ttime, char* buffer, bool bUseUtcTime)
+{
+
+ time_t tFileTime;
+ if (bUseUtcTime)
+ {
+#if _MSC_VER >= 1400
+ tm gts;
+ tm* gt = >s;
+ gmtime_s(gt, &ttime);
+#else
+ tm* gt = gmtime(&ttime);
+#endif
+ gt->tm_isdst = -1;
+ tFileTime = mktime(gt);
+ }
+ else
+ {
+ tFileTime = ttime;
+ }
+ ZFILETIME ft;
+ ZipPlatform::ConvertTimeToFileTime(tFileTime, ft);
+ CBytesWriter::WriteBytes(buffer, ft.dwLowDateTime);
+ CBytesWriter::WriteBytes(buffer + 4, ft.dwHighDateTime);
+}
+
+time_t CZipFileHeader::ReadFileTime(const char* buffer)
+{
+ ZFILETIME ft = {0};
+ CBytesWriter::ReadBytes(ft.dwLowDateTime, buffer);
+ CBytesWriter::ReadBytes(ft.dwHighDateTime, buffer + 4);
+ time_t ret;
+ return ZipPlatform::ConvertFileTimeToTime(ft, ret) ? ret : (time_t)0;
+}
+
+
// write the header to the central dir
-DWORD CZipFileHeader::Write(CZipStorage *pStorage)
+DWORD CZipFileHeader::Write(CZipCentralDir* pCentralDir)
{
+ CZipStorage* pStorage = pCentralDir->GetStorage();
m_aCentralExtraData.RemoveInternalHeaders();
+ if (m_tModificationTime != (time_t)0 || m_tCreationTime != (time_t)0 || m_tLastAccessTime != (time_t)0)
+ {
+ CZipExtraData* pExtra = m_aCentralExtraData.CreateNew(ZIP_EXTRA_NTFS);
+ CZipAutoBuffer& buf = pExtra->m_data;
+ buf.Allocate(32, true);
+ // first 4 bytes are reserved
+ WORD temp = ZIP_EXTRA_NTFS_TAG; // tag for the attribute
+ CBytesWriter::WriteBytes((char*)(buf + 4), temp);
+ temp = 3 * 8; // the size of the attribute
+ CBytesWriter::WriteBytes((char*)(buf + 6), temp);
+
+ bool bUseUtc = pCentralDir->GetArchive()->IsUseUtcFileTimes();
+ WriteFileTime(m_tModificationTime, (char*)(buf + 8), bUseUtc);
+ WriteFileTime(m_tCreationTime, (char*)(buf + 16), bUseUtc);
+ WriteFileTime(m_tLastAccessTime, (char*)(buf + 24), bUseUtc);
+ }
+ ZIP_SIZE_TYPE uComprSize = m_uComprSize;
WORD uMethod = m_uMethod;
+ PrepareStringBuffers();
+
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))
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state == sfCustomUnicode)
{
- 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 (!m_fileName.HasString() && m_fileName.HasBuffer())
+ GetFileName(false); // don't clear the buffer, it will be needed in a moment
+ ASSERT(m_fileName.HasString());
+ ASSERT(m_fileName.HasBuffer());
+ if (m_fileName.GetString().GetLength() == 0)
+ m_stringSettings.m_bStoreNameInExtraData = false;
}
- if (bWriteCommentCp)
+ if (!m_stringSettings.IsStandard(GetSystemCompatibility()))
{
- if (!pExtra->m_data.IsAllocated())
+ CZipExtraData* pExtra = m_aCentralExtraData.CreateNew(ZIP_EXTRA_ZARCH_NAME);
+ bool bWriteCommentCp = !m_stringSettings.IsStandardCommentCodePage(GetSystemCompatibility());
+
+ BYTE flag = 0;
+ int offset = 2;
+ char* data = NULL;
+ if (m_stringSettings.m_bStoreNameInExtraData)
{
- pExtra->m_data.Allocate(2 + 4);
+ CZipAutoBuffer buffer;
+ // m_fileName.m_buffer contains CP_ACP page, we don't check if the current page is CP_ACP - too large dependency on PrepareStringBuffers
+ ZipCompatibility::ConvertStringToBuffer(m_fileName.GetString(), 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(GetSystemCompatibility()))
+ {
+ 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;
}
- ASSERT(data);
- CBytesWriter::WriteBytes(data + offset, (DWORD)m_stringSettings.m_uCommentCodePage);
- flag |= 4;
- }
- data[0] = ZIP_EXTRA_ZARCH_NAME_VER;
- data[1] = flag;
+ 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;
+ }
+ if (data != NULL) // just in case
+ {
+ data[0] = ZIP_EXTRA_ZARCH_NAME_VER;
+ data[1] = flag;
+ }
+ }
}
+#endif
- WORD uFileNameSize = (WORD)m_pszFileNameBuffer.GetSize(), uCommentSize = (WORD)GetCommentSize(),
+ WORD uFileNameSize = (WORD)m_fileName.GetBufferSize(), uCommentSize = m_comment.GetBufferSize(),
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);
+ WORD uVersionMadeBy = (int)m_uVersionMadeBy & 0xFF;
+ uVersionMadeBy |= (WORD)(m_iSystemCompatibility << 8);
+ CBytesWriter::WriteBytes(dest + 4, 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 + 20, CBytesWriter::WriteSafeU32(uComprSize));
CBytesWriter::WriteBytes(dest + 24, CBytesWriter::WriteSafeU32(m_uUncomprSize));
CBytesWriter::WriteBytes(dest + 28, uFileNameSize);
CBytesWriter::WriteBytes(dest + 30, uExtraFieldSize);
@@ -287,13 +469,13 @@ DWORD CZipFileHeader::Write(CZipStorage *pStorage) CBytesWriter::WriteBytes(dest + 38, m_uExternalAttr);
CBytesWriter::WriteBytes(dest + 42, CBytesWriter::WriteSafeU32(m_uOffset));
- memcpy(dest + 46, m_pszFileNameBuffer, uFileNameSize);
+ memcpy(dest + 46, m_fileName.m_buffer, uFileNameSize);
if (uExtraFieldSize)
m_aCentralExtraData.Write(dest + 46 + uFileNameSize);
if (uCommentSize)
- memcpy(dest + 46 + uFileNameSize + uExtraFieldSize, m_pszComment, uCommentSize);
+ memcpy(dest + 46 + uFileNameSize + uExtraFieldSize, m_comment.m_buffer, uCommentSize);
pStorage->Write(dest, uSize, true);
@@ -303,10 +485,18 @@ DWORD CZipFileHeader::Write(CZipStorage *pStorage) return uSize;
}
-bool CZipFileHeader::ReadLocal(CZipCentralDir& centralDir)
-{
+bool CZipFileHeader::ReadLocal(CZipCentralDir* pCentralDir)
+{
+ CZipStorage* pStorage = pCentralDir->GetStorage();
+ pStorage->ChangeVolume(m_uVolumeStart);
+ bool isBinary = pStorage->IsBinarySplit();
+ if (isBinary)
+ pStorage->SeekInBinary(m_uOffset, true);
+ else
+ pStorage->Seek(m_uOffset);
+
char buf[LOCALFILEHEADERSIZE];
- CZipStorage* pStorage = centralDir.m_pStorage;
+
pStorage->Read(buf, LOCALFILEHEADERSIZE, true);
if (memcmp(buf, m_gszLocalSignature, 4) != 0)
return false;
@@ -317,7 +507,7 @@ bool CZipFileHeader::ReadLocal(CZipCentralDir& centralDir) 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)
+ if (pCentralDir->IsConsistencyCheckOn(CZipArchive::checkLocalFlag)
&& (uTemp & 0xf) != (m_uFlag & 0xf))
return false;
@@ -331,98 +521,135 @@ bool CZipFileHeader::ReadLocal(CZipCentralDir& centralDir) 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))
+
+ if (isBinary)
+ pStorage->SeekInBinary(m_uLocalFileNameSize);
+ else
+ pStorage->m_pFile->Seek(m_uLocalFileNameSize, CZipAbstractFile::current);
+
+ m_uLocalHeaderSize = LOCALFILEHEADERSIZE + m_uLocalFileNameSize + uExtraFieldSize;
+ if (!m_aLocalExtraData.Read(pStorage, uExtraFieldSize) && pCentralDir->IsConsistencyCheckOn(CZipArchive::checkInvalidExtraData))
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)
+ if (pCentralDir->IsConsistencyCheckOn(CZipArchive::checkLocalMethod)
&& uMethod != m_uMethod )
return false;
- if (!bIsDataDescr && centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalCRC | CZipArchive::checkLocalSizes))
+ if (!bIsDataDescr && pCentralDir->IsConsistencyCheckOn(CZipArchive::checkLocalCRC | CZipArchive::checkLocalSizes))
{
- // read all at once - probably overally faster than checking and reading separately
+ // read all at once - probably faster than checking and reading separately
DWORD uCrc32;
CBytesWriter::ReadBytes(uCrc32, buf + 14);
- if (centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalCRC)
+ if (pCentralDir->IsConsistencyCheckOn(CZipArchive::checkLocalCRC)
&& uCrc32 != m_uCrc32)
- return false;
+ return false;
- if (centralDir.IsConsistencyCheckOn( CZipArchive::checkLocalSizes)
+ if (pCentralDir->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
+ && ( (m_uLocalComprSize != 0 && m_uLocalComprSize != m_uComprSize) || m_uLocalUncomprSize != m_uUncomprSize))
+ return false;
+ }
+ return pStorage->GetCurrentVolume() == uCurDsk || isBinary; // 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);
+void CZipFileHeader::ConvertFileName(CZipAutoBuffer& buffer) const
+{
+ if (!m_fileName.HasString())
+ return;
+ CZipString temp = m_fileName.GetString();
+ ZipCompatibility::SlashBackslashChg(temp, false);
+ UINT codePage;
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state.IsSetAny(sfCustomUnicode))
+ {
+ if (m_stringSettings.m_bStoreNameInExtraData)
+ {
+ codePage = GetDefaultFileNameCodePage();
+
+ }
+ else
+ {
+ codePage = m_stringSettings.m_uNameCodePage;
+ }
+ }
+ else
#endif
- WORD year, month, day, hour, min, sec;
- if (gt == NULL)
{
- year = 0;
- month = day = 1;
- hour = min = sec = 0;
+ codePage = GetDefaultFileNameCodePage();
+ }
+
+ ZipCompatibility::ConvertStringToBuffer(temp, buffer, codePage);
+}
+
+void CZipFileHeader::ConvertFileName(CZipString& szFileName) const
+{
+ if (!m_fileName.HasBuffer())
+ return;
+ UINT codePage;
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state.IsSetAny(sfCustomUnicode))
+ {
+ codePage = m_stringSettings.m_uNameCodePage;
}
else
+#endif
{
- 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;
+ codePage = GetDefaultFileNameCodePage();
}
-
- m_uModDate = (WORD) (day + ( month << 5) + (year << 9));
- m_uModTime = (WORD) ((sec >> 1) + (min << 5) + (hour << 11));
+ ZipCompatibility::ConvertBufferToString(szFileName, m_fileName.m_buffer, codePage);
+ // some archives may have an invalid path separator stored
+ ZipCompatibility::NormalizePathSeparators(szFileName);
}
-void CZipFileHeader::ConvertFileName(CZipAutoBuffer& buffer) const
+void CZipFileHeader::ConvertComment(CZipAutoBuffer& buffer) const
{
- if (m_pszFileName == NULL)
+ if (!m_comment.HasString())
return;
- CZipString temp = *m_pszFileName;
- ZipCompatibility::SlashBackslashChg(temp, false);
- if (m_stringSettings.m_bStoreNameInExtraData)
- ZipCompatibility::ConvertStringToBuffer(temp, buffer, m_stringSettings.GetDefaultNameCodePage(GetSystemCompatibility()));
+ UINT codePage;
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state.IsSetAny(sfCustomUnicode))
+ {
+ codePage = m_stringSettings.m_uCommentCodePage;
+ }
else
- ZipCompatibility::ConvertStringToBuffer(temp, buffer, m_stringSettings.m_uNameCodePage);
+#endif
+ {
+ codePage = GetDefaultCommentCodePage();
+ }
+
+ ZipCompatibility::ConvertStringToBuffer(m_comment.GetString(), buffer, codePage);
}
-void CZipFileHeader::ConvertFileName(CZipString& szFileName) const
+void CZipFileHeader::ConvertComment(CZipString& szComment) const
{
- if (!m_pszFileNameBuffer.IsAllocated() || m_pszFileNameBuffer.GetSize() == 0)
+ if (!m_comment.HasBuffer())
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);
+ UINT codePage;
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state.IsSetAny(sfCustomUnicode))
+ {
+ codePage = m_stringSettings.m_uCommentCodePage;
+ }
+ else
+#endif
+ {
+ codePage = GetDefaultCommentCodePage();
+ }
+ ZipCompatibility::ConvertBufferToString(szComment, m_comment.m_buffer, codePage);
}
// write the local header
void CZipFileHeader::WriteLocal(CZipStorage *pStorage)
{
+ m_aLocalExtraData.RemoveInternalLocalHeaders();
if (IsDataDescriptor())
{
m_uLocalComprSize = 0;
@@ -434,16 +661,18 @@ void CZipFileHeader::WriteLocal(CZipStorage *pStorage) }
else
{
- m_uLocalComprSize = GetDataSize(true, false);
}
WORD uMethod = m_uMethod;
- PrepareFileName();
- m_uLocalFileNameSize = (WORD)m_pszFileNameBuffer.GetSize();
+ PrepareStringBuffers();
+ // this check was already performed, if a file was replaced
+ if (!CheckLengths(true))
+ m_pCentralDir->ThrowError(CZipException::tooLongData);
+ m_uLocalFileNameSize = (WORD)m_fileName.GetBufferSize();
DWORD uExtraFieldSize = m_aLocalExtraData.GetTotalSize();
- DWORD iLocalSize = LOCALFILEHEADERSIZE + uExtraFieldSize + m_uLocalFileNameSize;
- CZipAutoBuffer buf(iLocalSize);
+ m_uLocalHeaderSize = LOCALFILEHEADERSIZE + uExtraFieldSize + m_uLocalFileNameSize;
+ CZipAutoBuffer buf(m_uLocalHeaderSize);
char* dest = (char*) buf;
memcpy(dest, m_gszLocalSignature, 4);
@@ -455,20 +684,23 @@ void CZipFileHeader::WriteLocal(CZipStorage *pStorage) WriteSmallDataDescriptor(dest + 14);
CBytesWriter::WriteBytes(dest + 26, m_uLocalFileNameSize);
CBytesWriter::WriteBytes(dest + 28, (WORD)uExtraFieldSize);
- memcpy(dest + 30, m_pszFileNameBuffer, m_uLocalFileNameSize);
+ memcpy(dest + 30, m_fileName.m_buffer, 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);
+ pStorage->Write(dest, m_uLocalHeaderSize, true);
- m_uVolumeStart = pStorage->GetCurrentVolume();
- m_uOffset = pStorage->GetPosition() - iLocalSize;
+ m_uVolumeStart = pStorage->IsBinarySplit() ? 0 : pStorage->GetCurrentVolume();
+ m_uOffset = pStorage->GetPosition() - m_uLocalHeaderSize;
+
+ m_aLocalExtraData.RemoveInternalLocalHeaders();
ClearFileName();
}
+
WORD CZipFileHeader::GetDataDescriptorSize(bool bConsiderSignature) const
{
if (IsDataDescriptor())
@@ -488,22 +720,21 @@ bool CZipFileHeader::NeedsDataDescriptor() const 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
+ // could be == 1, but the way below it works for PredictMaximumFileSizeInArchive when used on an existing segmented archive
m_uInternalAttr = 0;
// version made by
- SetVersion((WORD)(0x14));
+ m_uVersionMadeBy = (unsigned char)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:
@@ -517,9 +748,12 @@ void CZipFileHeader::PrepareData(int iLevel, bool bSegm) m_uFlag |= 2;
break;
}
+ }
UpdateFlag(bSegm);
+ AdjustLocalComprSize();
+
m_uVersionNeeded = 0;
if (m_uVersionNeeded == 0)
m_uVersionNeeded = IsDirectory() ? 0xa : 0x14; // 1.0 or 2.0
@@ -569,48 +803,86 @@ bool CZipFileHeader::CheckDataDescriptor(CZipStorage* pStorage) const DWORD CZipFileHeader::GetSize()const
{
- DWORD uSize = FILEHEADERSIZE + PredictFileNameSize() + GetCommentSize();
+ DWORD uSize = FILEHEADERSIZE + PredictFileNameSize() + PredictCommentSize();
uSize += m_aCentralExtraData.GetTotalSize();
- if (m_stringSettings.m_bStoreNameInExtraData)
+
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state.IsSetAny(sfCustomUnicode))
{
- CZipString temp;
- if (m_pszFileName != NULL)
- temp = *m_pszFileName;
- else
- ConvertFileName(temp);
- if (temp.GetLength() > 0)
+ if (m_stringSettings.m_bStoreNameInExtraData)
{
- 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;
+ CZipString temp;
+ if (m_fileName.HasString())
+ temp = m_fileName.GetString();
+ 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(GetSystemCompatibility()))
+ uSize += 4;
+ }
}
}
+#endif
return uSize;
}
DWORD CZipFileHeader::GetLocalSize(bool bReal)const
{
- DWORD uSize = LOCALFILEHEADERSIZE + m_aLocalExtraData.GetTotalSize();
if (bReal)
- uSize += m_uLocalFileNameSize;
- else
- uSize += PredictFileNameSize();
+ return m_uLocalHeaderSize;
+
+ DWORD uSize = LOCALFILEHEADERSIZE + m_aLocalExtraData.GetTotalSize() + PredictFileNameSize();
return uSize;
}
-void CZipFileHeader::SetComment(LPCTSTR lpszComment)
+bool CZipFileHeader::SetComment(LPCTSTR lpszComment)
{
- ZipCompatibility::ConvertStringToBuffer(lpszComment, m_pszComment, m_stringSettings.m_uCommentCodePage);
+ if (m_pCentralDir)
+ {
+ // update the lpszFileName to make sure the renaming is necessary
+ GetComment();
+ CZipString newComment(lpszComment);
+ if (!UpdateCommentFlags(&newComment))
+ {
+ if (m_comment.GetString().Collate(newComment) == 0)
+ return true;
+ }
+ // just in case
+ m_comment.ClearBuffer();
+
+ bool ret;
+ CZipString oldComment= m_comment.GetString();
+ m_comment.SetString(lpszComment);
+ ret = m_pCentralDir->OnFileCentralChange();
+ if (!ret)
+ m_comment.SetString(oldComment);
+
+ return ret;
+ }
+ else
+ {
+ m_comment.ClearBuffer();
+ m_comment.SetString(lpszComment);
+ return true;
+ }
}
-CZipString CZipFileHeader::GetComment() const
+const CZipString& CZipFileHeader::GetComment(bool bClearBuffer)
{
- CZipString temp;
- ZipCompatibility::ConvertBufferToString(temp, m_pszComment, m_stringSettings.m_uCommentCodePage);
- return temp;
+ if (m_comment.HasString())
+ {
+ return m_comment.GetString();
+ }
+ m_comment.AllocateString();
+ ConvertComment(m_comment.GetString());
+ if (bClearBuffer)
+ m_comment.ClearBuffer();
+ return m_comment.GetString();
}
int CZipFileHeader::GetCompressionLevel() const
@@ -627,25 +899,92 @@ int CZipFileHeader::GetCompressionLevel() const return CZipCompressor::levelDefault;
}
-void CZipFileHeader::SetFileName(LPCTSTR lpszFileName)
+bool CZipFileHeader::SetFileName(LPCTSTR lpszFileName, bool bInCentralOnly)
{
- if (m_pszFileName == NULL)
- m_pszFileName = new CZipString(lpszFileName);
+ CZipString newFileName(lpszFileName);
+ if (!IsDirectory() || newFileName.GetLength() != 1 || !CZipPathComponent::IsSeparator(newFileName[0]))
+ // do not remove from directories where only path separator is present
+ CZipPathComponent::RemoveSeparatorsLeft(newFileName);
+ if (m_pCentralDir)
+ {
+ // update the lpszFileName to make sure the renaming is necessary
+ GetFileName();
+
+ if (!UpdateFileNameFlags(&newFileName, true))
+ {
+ if (IsDirectory())
+ CZipPathComponent::AppendSeparator(newFileName);
+ else
+ CZipPathComponent::RemoveSeparators(newFileName);
+
+ if (m_fileName.GetString().Collate(newFileName) == 0)
+ return true;
+ }
+ // just in case
+ m_fileName.ClearBuffer();
+
+ bool ret;
+ CZipString oldFileName = m_fileName.GetString();
+ m_fileName.SetString(lpszFileName);
+ ret = m_pCentralDir->OnFileNameChange(this, bInCentralOnly);
+ if (!bInCentralOnly)
+ {
+ if (ret)
+ SetModified();
+ else
+ m_fileName.SetString(oldFileName);
+ }
+
+ return ret;
+ }
else
- *m_pszFileName = lpszFileName;
- m_pszFileNameBuffer.Release();
+ {
+ m_fileName.ClearBuffer();
+ m_fileName.SetString(newFileName);
+ return true;
+ }
}
-CZipString& CZipFileHeader::GetFileName(bool bClearBuffer)
+const CZipString& CZipFileHeader::GetFileName(bool bClearBuffer)
{
- if (m_pszFileName != NULL)
- return *m_pszFileName;
- m_pszFileName = new CZipString(_T(""));
- ConvertFileName(*m_pszFileName);
+ if (m_fileName.HasString())
+ {
+ return m_fileName.GetString();
+ }
+ m_fileName.AllocateString();
+ ConvertFileName(m_fileName.GetString());
// don't keep it in memory
if (bClearBuffer)
- m_pszFileNameBuffer.Release();
- return *m_pszFileName;
+ {
+ m_fileName.ClearBuffer();
+ }
+ return m_fileName.GetString();
+}
+
+CZipString CZipFileHeader::GetFileTitle(bool bLowerCase, bool bClearBuffer)
+{
+ CZipString sz = GetFileName(bClearBuffer);
+ CZipPathComponent::RemoveSeparators(sz);
+ CZipPathComponent zpc(sz);
+ CZipString ret = zpc.GetFileTitle();
+ if (bLowerCase)
+ {
+ ret.MakeLower();
+ }
+ return ret;
+}
+
+CZipString CZipFileHeader::GetFileExtension(bool bLowerCase, bool bClearBuffer)
+{
+ CZipString sz = GetFileName(bClearBuffer);
+ CZipPathComponent::RemoveSeparators(sz);
+ CZipPathComponent zpc(sz);
+ CZipString ret = zpc.GetFileExt();
+ if (bLowerCase)
+ {
+ ret.MakeLower();
+ }
+ return ret;
}
bool CZipFileHeader::IsDirectory()
@@ -655,76 +994,96 @@ bool CZipFileHeader::IsDirectory() 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
+ if (ZipCompatibility::IsPlatformSupported(GetSystemCompatibility()))
+ {
+ DWORD uAttr = GetSystemCompatibility() == ZipCompatibility::zcUnix ? (m_uExternalAttr >> 16) : (m_uExternalAttr & 0xFFFF);
+ DWORD uConvertedAttr = ZipCompatibility::ConvertToSystem(uAttr, GetSystemCompatibility(), ZipPlatform::GetSystemID());
+ // some zip files seem to report size greater than 0 for folders
+ if ((m_uComprSize == 0 || m_uExternalAttr == 0) && !ZipPlatform::IsDirectory(uConvertedAttr) && CZipPathComponent::HasEndingSeparator(GetFileName()))
+ {
+ // can happen, a folder can have attributes set and no dir attribute (Python modules)
+ // TODO: [postponed] fix and cache after reading from central dir, but avoid calling GetFileName() there to keep lazy name conversion
+ // We convert again as uConvertedAttr were treated as a file during ZipCompatibility::ConvertToSystem above
+ DWORD uSystemDirAttributes = ZipCompatibility::ConvertToSystem(ZipPlatform::GetDefaultDirAttributes(), ZipPlatform::GetSystemID(), GetSystemCompatibility());
+ return ZipCompatibility::ConvertToSystem(uAttr | uSystemDirAttributes, GetSystemCompatibility(), ZipPlatform::GetSystemID());
+ }
else
- {
- uAttr = ZipCompatibility::ConvertToSystem(uAttr, iSystemComp, ZipPlatform::GetSystemID());
-#ifdef ZIP_ARCHIVE_LNX
+ {
+#ifdef _ZIP_SYSTEM_LINUX
// converting from Windows attributes may create a not readable linux directory
- if (iSystemComp != ZipCompatibility::zcUnix && ZipPlatform::IsDirectory(uAttr))
+ if (GetSystemCompatibility() != ZipCompatibility::zcUnix && ZipPlatform::IsDirectory(uConvertedAttr))
return ZipPlatform::GetDefaultDirAttributes();
#endif
- return uAttr;
+ return uConvertedAttr;
}
}
else
return CZipPathComponent::HasEndingSeparator(GetFileName()) ? ZipPlatform::GetDefaultDirAttributes() : ZipPlatform::GetDefaultAttributes();
}
-void CZipFileHeader::SetSystemAttr(DWORD uAttr)
+bool 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;
+ DWORD uNewAtrr = ZipCompatibility::ConvertToSystem(uAttr, ZipPlatform::GetSystemID(), GetSystemCompatibility());
+ if (GetSystemCompatibility() == ZipCompatibility::zcUnix)
+ {
+ uNewAtrr <<= 16;
if (ZipPlatform::IsDirectory(uAttr))
- m_uExternalAttr |= 0x10; // make it recognizable under other systems (all use 0x10 for directory)
+ uNewAtrr |= 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);
+ uNewAtrr |= (ZipCompatibility::ConvertToSystem(uAttr, ZipPlatform::GetSystemID(), ZipCompatibility::zcUnix) << 16);
+
+ if (uNewAtrr != m_uExternalAttr)
+ {
+ if (m_pCentralDir)
+ {
+ if (!m_pCentralDir->OnFileCentralChange())
+ {
+ return false;
+ }
+ }
+ m_uExternalAttr = uNewAtrr;
+ }
+ return true;
}
CZipFileHeader& CZipFileHeader::operator=(const CZipFileHeader& header)
{
m_uVersionMadeBy = header.m_uVersionMadeBy;
m_uVersionNeeded = header.m_uVersionNeeded;
+ m_iSystemCompatibility = header.m_iSystemCompatibility;
m_uFlag = header.m_uFlag;
m_uMethod = header.m_uMethod;
m_uModTime = header.m_uModTime;
m_uModDate = header.m_uModDate;
+ m_tModificationTime = header.m_tModificationTime;
+ m_tCreationTime = header.m_tCreationTime;
+ m_tLastAccessTime = header.m_tLastAccessTime;
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_uLocalHeaderSize = header.m_uLocalHeaderSize;
+ m_uLocalUncomprSize = header.m_uLocalUncomprSize;
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;
+ m_fileName = header.m_fileName;
+ m_comment = header.m_comment;
+ m_state = header.m_state;
- 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;
+#ifdef _ZIP_UNICODE_CUSTOM
m_stringSettings = header.m_stringSettings;
-
+#endif
+ m_pCentralDir = header.m_pCentralDir;
+
return *this;
}
@@ -767,7 +1126,7 @@ void CZipFileHeader::WriteDataDescriptor(CZipStorage* pStorage) void CZipFileHeader::UpdateLocalHeader(CZipStorage* pStorage)
{
- if (pStorage->IsSegmented() != 0 || IsDataDescriptor())
+ if (pStorage->IsSegmented() || IsDataDescriptor())
// there is nothing to fix
return;
pStorage->Flush();
@@ -775,13 +1134,13 @@ void CZipFileHeader::UpdateLocalHeader(CZipStorage* pStorage) // 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);
+ 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);
+ pStorage->m_pFile->SafeSeek(uPos);
}
void CZipFileHeader::WriteCrc32(char* pBuf) const
@@ -790,3 +1149,99 @@ void CZipFileHeader::WriteCrc32(char* pBuf) const CBytesWriter::WriteBytes(pBuf, uCrc);
}
+
+void CZipFileHeader::ClearFileName()
+{
+#ifdef _ZIP_UNICODE_CUSTOM
+ if (m_state.IsSetAny(sfCustomUnicode) && m_stringSettings.m_bStoreNameInExtraData)
+ // we are keeping m_pszFileName, clear the buffer, we need the original, when writing extra header in central directory (can happen many times - better performance)
+ // and when accessing the filename
+ m_fileName.ClearBuffer();
+ else
+#endif
+ m_fileName.ClearString();
+}
+
+bool CZipFileHeader::UpdateFileNameFlags(const CZipString* szNewFileName, bool bAllowRemoveCDir)
+{
+#if defined _ZIP_UNICODE || defined _ZIP_UNICODE_CUSTOM
+ CBitFlag iMode = m_pCentralDir->GetUnicodeMode();
+#endif
+ // move the buffer to the name, to ensure it is converted properly now
+ GetComment();
+ bool centralDirChanged = false;
+ bool changed = false;
+#ifdef _ZIP_UNICODE_CUSTOM
+ bool isCustom = iMode.IsSetAny(CZipArchive::umCustom);
+ const CZipStringStoreSettings& stringStoreSettings = m_pCentralDir->GetStringStoreSettings();
+ if (m_state.ChangeWithCheck(sfCustomUnicode, isCustom))
+ {
+ // the mode changed
+ if (isCustom)
+ {
+ // changed to custom
+ m_stringSettings.m_bStoreNameInExtraData = stringStoreSettings.m_bStoreNameInExtraData;
+ m_stringSettings.m_uNameCodePage = stringStoreSettings.m_uNameCodePage;
+ if (!m_stringSettings.m_bStoreNameInExtraData && m_stringSettings.m_uNameCodePage != GetDefaultFileNameCodePage())
+ // the local filename needs to be rewritten, the name code page has changed
+ changed = true;
+ }
+ else
+ {
+ // changed from custom
+ if (!m_stringSettings.m_bStoreNameInExtraData && m_stringSettings.m_uNameCodePage != GetDefaultFileNameCodePage())
+ changed = true;
+
+ m_stringSettings.m_bStoreNameInExtraData = stringStoreSettings.m_bStoreNameInExtraData;
+ m_stringSettings.m_uNameCodePage = stringStoreSettings.m_uNameCodePage;
+ }
+ centralDirChanged = true;
+ }
+ else if (isCustom)
+ {
+ if (stringStoreSettings.m_bStoreNameInExtraData != m_stringSettings.m_bStoreNameInExtraData)
+ {
+ if (m_stringSettings.m_bStoreNameInExtraData)
+ {
+ changed |= (stringStoreSettings.m_uNameCodePage == GetDefaultFileNameCodePage());
+ }
+ else
+ {
+ changed |= (m_stringSettings.m_uNameCodePage == GetDefaultFileNameCodePage());
+ }
+ }
+ else if (!m_stringSettings.m_bStoreNameInExtraData)
+ changed |= (stringStoreSettings.m_uNameCodePage != m_stringSettings.m_uNameCodePage);
+
+ m_stringSettings.m_bStoreNameInExtraData = stringStoreSettings.m_bStoreNameInExtraData;
+ m_stringSettings.m_uNameCodePage = stringStoreSettings.m_uNameCodePage;
+ }
+#endif
+ if (changed || centralDirChanged)
+ {
+ m_comment.ClearBuffer();
+ }
+ // remove the central directory in case the filename did not changed, but the comment flags changed
+ if (!changed && centralDirChanged && bAllowRemoveCDir && m_pCentralDir && m_comment.HasString())
+ m_pCentralDir->OnFileCentralChange();
+ return changed;
+}
+
+bool CZipFileHeader::UpdateCommentFlags(const CZipString* szNewComment)
+{
+#if defined _ZIP_UNICODE || defined _ZIP_UNICODE_CUSTOM
+ CBitFlag iMode = m_pCentralDir->GetUnicodeMode();
+#endif
+ bool changed = false;
+#ifdef _ZIP_UNICODE_CUSTOM
+ bool isCustom = iMode.IsSetAny(CZipArchive::umCustom);
+ changed |= m_state.ChangeWithCheck(sfCustomUnicode, isCustom);
+ if (isCustom)
+ {
+ const CZipStringStoreSettings& stringStoreSettings = m_pCentralDir->GetStringStoreSettings();
+ changed |= (m_stringSettings.m_uCommentCodePage != stringStoreSettings.m_uCommentCodePage);
+ m_stringSettings.m_uCommentCodePage = stringStoreSettings.m_uCommentCodePage;
+ }
+#endif
+ return changed;
+}
|
