Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipOut.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Zip/ZipOut.cpp331
1 files changed, 177 insertions, 154 deletions
diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp
index aa82143e..2a1ba2c4 100755..100644
--- a/CPP/7zip/Archive/Zip/ZipOut.cpp
+++ b/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -9,80 +9,93 @@
namespace NArchive {
namespace NZip {
-void COutArchive::Create(IOutStream *outStream)
+HRESULT COutArchive::Create(IOutStream *outStream)
{
+ m_CurPos = 0;
if (!m_OutBuffer.Create(1 << 16))
- throw CSystemException(E_OUTOFMEMORY);
+ return E_OUTOFMEMORY;
m_Stream = outStream;
m_OutBuffer.SetStream(outStream);
m_OutBuffer.Init();
- m_BasePosition = 0;
+
+ return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base);
+}
+
+void COutArchive::MoveCurPos(UInt64 distanceToMove)
+{
+ m_CurPos += distanceToMove; // test overflow
}
-void COutArchive::MoveBasePosition(UInt64 distanceToMove)
+void COutArchive::SeekToRelatPos(UInt64 offset)
{
- m_BasePosition += distanceToMove; // test overflow
+ HRESULT res = m_Stream->Seek(m_Base + offset, STREAM_SEEK_SET, NULL);
+ if (res != S_OK)
+ throw CSystemException(res);
}
-void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption)
+void COutArchive::PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption)
{
m_IsZip64 = isZip64;
m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0;
if (aesEncryption)
- m_ExtraSize += 4 + 7;
- m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize;
+ m_ExtraSize += 4 + k_WzAesExtra_Size;
+ m_LocalFileHeaderSize = kLocalHeaderSize + fileNameLen + m_ExtraSize;
}
-void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption)
+void COutArchive::PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool aesEncryption)
{
- // We test it to 0xF8000000 to support case when compressed size
- // can be larger than uncompressed size.
- PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, aesEncryption);
+ // We use Zip64, if unPackSize size is larger than 0xF8000000 to support
+ // cases when compressed size can be about 3% larger than uncompressed size
+
+ PrepareWriteCompressedDataZip64(fileNameLen, unPackSize >= (UInt32)0xF8000000, aesEncryption);
}
-void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
+#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF)
+
+void COutArchive::PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
{
- bool isUnPack64 = unPackSize >= 0xFFFFFFFF;
- bool isPack64 = packSize >= 0xFFFFFFFF;
- bool isZip64 = isPack64 || isUnPack64;
- PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption);
+ bool isZip64 =
+ DOES_NEED_ZIP64(unPackSize) ||
+ DOES_NEED_ZIP64(packSize);
+ PrepareWriteCompressedDataZip64(fileNameLen, isZip64, aesEncryption);
}
void COutArchive::WriteBytes(const void *buffer, UInt32 size)
{
m_OutBuffer.WriteBytes(buffer, size);
- m_BasePosition += size;
+ m_CurPos += size;
}
-void COutArchive::WriteByte(Byte b)
+void COutArchive::Write8(Byte b)
{
- WriteBytes(&b, 1);
+ m_OutBuffer.WriteByte(b);
+ m_CurPos++;
}
-void COutArchive::WriteUInt16(UInt16 value)
+void COutArchive::Write16(UInt16 val)
{
for (int i = 0; i < 2; i++)
{
- WriteByte((Byte)value);
- value >>= 8;
+ Write8((Byte)val);
+ val >>= 8;
}
}
-void COutArchive::WriteUInt32(UInt32 value)
+void COutArchive::Write32(UInt32 val)
{
for (int i = 0; i < 4; i++)
{
- WriteByte((Byte)value);
- value >>= 8;
+ Write8((Byte)val);
+ val >>= 8;
}
}
-void COutArchive::WriteUInt64(UInt64 value)
+void COutArchive::Write64(UInt64 val)
{
for (int i = 0; i < 8; i++)
{
- WriteByte((Byte)value);
- value >>= 8;
+ Write8((Byte)val);
+ val >>= 8;
}
}
@@ -90,178 +103,181 @@ void COutArchive::WriteExtra(const CExtraBlock &extra)
{
if (extra.SubBlocks.Size() != 0)
{
- for (int i = 0; i < extra.SubBlocks.Size(); i++)
+ FOR_VECTOR (i, extra.SubBlocks)
{
const CExtraSubBlock &subBlock = extra.SubBlocks[i];
- WriteUInt16(subBlock.ID);
- WriteUInt16((UInt16)subBlock.Data.GetCapacity());
- WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity());
+ Write16(subBlock.ID);
+ Write16((UInt16)subBlock.Data.Size());
+ WriteBytes(subBlock.Data, (UInt32)subBlock.Data.Size());
}
}
}
-void COutArchive::SeekTo(UInt64 offset)
+void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64)
{
- HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
- if (res != S_OK)
- throw CSystemException(res);
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ Write8(ver);
+ }
+ Write8(item.ExtractVersion.HostOS);
+ Write16(item.Flags);
+ Write16(item.Method);
+ Write32(item.Time);
+ Write32(item.Crc);
}
+#define WRITE_32_VAL_SPEC(__v, __isZip64) Write32((__isZip64) ? 0xFFFFFFFF : (UInt32)(__v));
+
void COutArchive::WriteLocalHeader(const CLocalItem &item)
{
- SeekTo(m_BasePosition);
+ SeekToCurPos();
- bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
+ bool isZip64 = m_IsZip64 ||
+ DOES_NEED_ZIP64(item.PackSize) ||
+ DOES_NEED_ZIP64(item.Size);
- WriteUInt32(NSignature::kLocalFileHeader);
- {
- Byte ver = item.ExtractVersion.Version;
- if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
- ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
- WriteByte(ver);
- }
- WriteByte(item.ExtractVersion.HostOS);
- WriteUInt16(item.Flags);
- WriteUInt16(item.CompressionMethod);
- WriteUInt32(item.Time);
- WriteUInt32(item.FileCRC);
- WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
- WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
- WriteUInt16((UInt16)item.Name.Length());
+ Write32(NSignature::kLocalFileHeader);
+ WriteCommonItemInfo(item, isZip64);
+
+ WRITE_32_VAL_SPEC(item.PackSize, isZip64);
+ WRITE_32_VAL_SPEC(item.Size, isZip64);
+
+ Write16((UInt16)item.Name.Len());
{
- UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize());
- if (localExtraSize > m_ExtraSize)
+ UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize());
+ if (localExtraSize != m_ExtraSize)
throw CSystemException(E_FAIL);
}
- WriteUInt16((UInt16)m_ExtraSize); // test it;
- WriteBytes((const char *)item.Name, item.Name.Length());
+ Write16((UInt16)m_ExtraSize);
+ WriteBytes((const char *)item.Name, item.Name.Len());
- UInt32 extraPos = 0;
if (isZip64)
{
- extraPos += 4 + 16;
- WriteUInt16(NFileHeader::NExtraID::kZip64);
- WriteUInt16(16);
- WriteUInt64(item.UnPackSize);
- WriteUInt64(item.PackSize);
+ Write16(NFileHeader::NExtraID::kZip64);
+ Write16(8 + 8);
+ Write64(item.Size);
+ Write64(item.PackSize);
}
WriteExtra(item.LocalExtra);
- extraPos += (UInt32)item.LocalExtra.GetSize();
- for (; extraPos < m_ExtraSize; extraPos++)
- WriteByte(0);
+
+ // Why don't we write NTFS timestamps to local header?
+ // Probably we want to reduce size of archive?
m_OutBuffer.FlushWithCheck();
- MoveBasePosition(item.PackSize);
- SeekTo(m_BasePosition);
+ MoveCurPos(item.PackSize);
}
-void COutArchive::WriteCentralHeader(const CItem &item)
+void COutArchive::WriteCentralHeader(const CItemOut &item)
{
- bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
- bool isPack64 = item.PackSize >= 0xFFFFFFFF;
- bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
- bool isZip64 = isPack64 || isUnPack64 || isPosition64;
+ bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
+ bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
+ bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
+ bool isZip64 = isPack64 || isUnPack64 || isPosition64;
- WriteUInt32(NSignature::kCentralFileHeader);
- WriteByte(item.MadeByVersion.Version);
- WriteByte(item.MadeByVersion.HostOS);
- {
- Byte ver = item.ExtractVersion.Version;
- if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
- ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
- WriteByte(ver);
- }
- WriteByte(item.ExtractVersion.HostOS);
- WriteUInt16(item.Flags);
- WriteUInt16(item.CompressionMethod);
- WriteUInt32(item.Time);
- WriteUInt32(item.FileCRC);
- WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
- WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
- WriteUInt16((UInt16)item.Name.Length());
- UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
+ Write32(NSignature::kCentralFileHeader);
+ Write8(item.MadeByVersion.Version);
+ Write8(item.MadeByVersion.HostOS);
+
+ WriteCommonItemInfo(item, isZip64);
+
+ WRITE_32_VAL_SPEC(item.PackSize, isPack64);
+ WRITE_32_VAL_SPEC(item.Size, isUnPack64);
+
+ Write16((UInt16)item.Name.Len());
+
+ UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
- UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0);
- centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize());
- WriteUInt16(centralExtraSize); // test it;
- WriteUInt16((UInt16)item.Comment.GetCapacity());
- WriteUInt16(0); // DiskNumberStart;
- WriteUInt16(item.InternalAttributes);
- WriteUInt32(item.ExternalAttributes);
- WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
- WriteBytes((const char *)item.Name, item.Name.Length());
+ const UInt16 centralExtraSize = (UInt16)(
+ (isZip64 ? 4 + zip64ExtraSize : 0) +
+ (item.NtfsTimeIsDefined ? 4 + kNtfsExtraSize : 0) +
+ item.CentralExtra.GetSize());
+
+ Write16(centralExtraSize); // test it;
+ Write16((UInt16)item.Comment.Size());
+ Write16(0); // DiskNumberStart;
+ Write16(item.InternalAttrib);
+ Write32(item.ExternalAttrib);
+ WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64);
+ WriteBytes((const char *)item.Name, item.Name.Len());
+
if (isZip64)
{
- WriteUInt16(NFileHeader::NExtraID::kZip64);
- WriteUInt16(zip64ExtraSize);
- if(isUnPack64)
- WriteUInt64(item.UnPackSize);
- if(isPack64)
- WriteUInt64(item.PackSize);
- if(isPosition64)
- WriteUInt64(item.LocalHeaderPosition);
+ Write16(NFileHeader::NExtraID::kZip64);
+ Write16(zip64ExtraSize);
+ if (isUnPack64)
+ Write64(item.Size);
+ if (isPack64)
+ Write64(item.PackSize);
+ if (isPosition64)
+ Write64(item.LocalHeaderPos);
}
+
if (item.NtfsTimeIsDefined)
{
- WriteUInt16(NFileHeader::NExtraID::kNTFS);
- WriteUInt16(kNtfsExtraSize);
- WriteUInt32(0); // reserved
- WriteUInt16(NFileHeader::NNtfsExtra::kTagTime);
- WriteUInt16(8 * 3);
- WriteUInt32(item.NtfsMTime.dwLowDateTime);
- WriteUInt32(item.NtfsMTime.dwHighDateTime);
- WriteUInt32(item.NtfsATime.dwLowDateTime);
- WriteUInt32(item.NtfsATime.dwHighDateTime);
- WriteUInt32(item.NtfsCTime.dwLowDateTime);
- WriteUInt32(item.NtfsCTime.dwHighDateTime);
+ Write16(NFileHeader::NExtraID::kNTFS);
+ Write16(kNtfsExtraSize);
+ Write32(0); // reserved
+ Write16(NFileHeader::NNtfsExtra::kTagTime);
+ Write16(8 * 3);
+ WriteNtfsTime(item.Ntfs_MTime);
+ WriteNtfsTime(item.Ntfs_ATime);
+ WriteNtfsTime(item.Ntfs_CTime);
}
+
WriteExtra(item.CentralExtra);
- if (item.Comment.GetCapacity() > 0)
- WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity());
+ if (item.Comment.Size() > 0)
+ WriteBytes(item.Comment, (UInt32)item.Comment.Size());
}
-void COutArchive::WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment)
+void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
{
- SeekTo(m_BasePosition);
+ SeekToCurPos();
- UInt64 cdOffset = GetCurrentPosition();
- for(int i = 0; i < items.Size(); i++)
+ UInt64 cdOffset = GetCurPos();
+ FOR_VECTOR (i, items)
WriteCentralHeader(items[i]);
- UInt64 cd64EndOffset = GetCurrentPosition();
+ UInt64 cd64EndOffset = GetCurPos();
UInt64 cdSize = cd64EndOffset - cdOffset;
- bool cdOffset64 = cdOffset >= 0xFFFFFFFF;
- bool cdSize64 = cdSize >= 0xFFFFFFFF;
+ bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
+ bool cdSize64 = DOES_NEED_ZIP64(cdSize);
bool items64 = items.Size() >= 0xFFFF;
bool isZip64 = (cdOffset64 || cdSize64 || items64);
+
+ // isZip64 = true; // to test Zip64
if (isZip64)
{
- WriteUInt32(NSignature::kZip64EndOfCentralDir);
- WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0;
- WriteUInt16(45); // version
- WriteUInt16(45); // version
- WriteUInt32(0); // ThisDiskNumber = 0;
- WriteUInt32(0); // StartCentralDirectoryDiskNumber;;
- WriteUInt64((UInt64)items.Size());
- WriteUInt64((UInt64)items.Size());
- WriteUInt64((UInt64)cdSize);
- WriteUInt64((UInt64)cdOffset);
-
- WriteUInt32(NSignature::kZip64EndOfCentralDirLocator);
- WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory
- WriteUInt64(cd64EndOffset);
- WriteUInt32(1); // total number of disks
+ Write32(NSignature::kEcd64);
+ Write64(kEcd64_MainSize);
+ Write16(45); // made by version
+ Write16(45); // extract version
+ Write32(0); // ThisDiskNumber = 0;
+ Write32(0); // StartCentralDirectoryDiskNumber;;
+ Write64((UInt64)items.Size());
+ Write64((UInt64)items.Size());
+ Write64((UInt64)cdSize);
+ Write64((UInt64)cdOffset);
+
+ Write32(NSignature::kEcd64Locator);
+ Write32(0); // number of the disk with the start of the zip64 end of central directory
+ Write64(cd64EndOffset);
+ Write32(1); // total number of disks
}
- WriteUInt32(NSignature::kEndOfCentralDir);
- WriteUInt16(0); // ThisDiskNumber = 0;
- WriteUInt16(0); // StartCentralDirectoryDiskNumber;
- WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
- WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
- WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize);
- WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset);
- UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0);
- WriteUInt16((UInt16)commentSize);
+
+ Write32(NSignature::kEcd);
+ Write16(0); // ThisDiskNumber = 0;
+ Write16(0); // StartCentralDirectoryDiskNumber;
+ Write16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ Write16((UInt16)(items64 ? 0xFFFF: items.Size()));
+
+ WRITE_32_VAL_SPEC(cdSize, cdSize64);
+ WRITE_32_VAL_SPEC(cdOffset, cdOffset64);
+
+ UInt32 commentSize = (UInt32)(comment ? comment->Size() : 0);
+ Write16((UInt16)commentSize);
if (commentSize > 0)
WriteBytes((const Byte *)*comment, commentSize);
m_OutBuffer.FlushWithCheck();
@@ -271,14 +287,21 @@ void COutArchive::CreateStreamForCompressing(IOutStream **outStream)
{
COffsetOutStream *streamSpec = new COffsetOutStream;
CMyComPtr<IOutStream> tempStream(streamSpec);
- streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize);
+ streamSpec->Init(m_Stream, m_Base + m_CurPos + m_LocalFileHeaderSize);
*outStream = tempStream.Detach();
}
+/*
void COutArchive::SeekToPackedDataPosition()
{
SeekTo(m_BasePosition + m_LocalFileHeaderSize);
}
+*/
+
+void COutArchive::SeekToCurPos()
+{
+ SeekToRelatPos(m_CurPos);
+}
void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream)
{