diff options
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipOut.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Zip/ZipOut.cpp | 331 |
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) { |