diff options
Diffstat (limited to 'CPP/7zip/Archive/Zip/ZipOut.cpp')
-rw-r--r-- | CPP/7zip/Archive/Zip/ZipOut.cpp | 211 |
1 files changed, 122 insertions, 89 deletions
diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp index 2a1ba2c4..1fdc24f8 100644 --- a/CPP/7zip/Archive/Zip/ZipOut.cpp +++ b/CPP/7zip/Archive/Zip/ZipOut.cpp @@ -21,48 +21,20 @@ HRESULT COutArchive::Create(IOutStream *outStream) return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base); } -void COutArchive::MoveCurPos(UInt64 distanceToMove) -{ - m_CurPos += distanceToMove; // test overflow -} - -void COutArchive::SeekToRelatPos(UInt64 offset) +void COutArchive::SeekToCurPos() { - HRESULT res = m_Stream->Seek(m_Base + offset, STREAM_SEEK_SET, NULL); + HRESULT res = m_Stream->Seek(m_Base + m_CurPos, STREAM_SEEK_SET, NULL); if (res != S_OK) throw CSystemException(res); } -void COutArchive::PrepareWriteCompressedDataZip64(unsigned fileNameLen, bool isZip64, bool aesEncryption) -{ - m_IsZip64 = isZip64; - m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0; - if (aesEncryption) - m_ExtraSize += 4 + k_WzAesExtra_Size; - m_LocalFileHeaderSize = kLocalHeaderSize + fileNameLen + m_ExtraSize; -} - -void COutArchive::PrepareWriteCompressedData(unsigned fileNameLen, UInt64 unPackSize, bool 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); -} - #define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF) +// #define DOES_NEED_ZIP64(v) (v >= 0) -void COutArchive::PrepareWriteCompressedData2(unsigned fileNameLen, UInt64 unPackSize, UInt64 packSize, bool aesEncryption) -{ - bool isZip64 = - DOES_NEED_ZIP64(unPackSize) || - DOES_NEED_ZIP64(packSize); - PrepareWriteCompressedDataZip64(fileNameLen, isZip64, aesEncryption); -} -void COutArchive::WriteBytes(const void *buffer, UInt32 size) +void COutArchive::WriteBytes(const void *data, size_t size) { - m_OutBuffer.WriteBytes(buffer, size); + m_OutBuffer.WriteBytes(data, size); m_CurPos += size; } @@ -74,11 +46,8 @@ void COutArchive::Write8(Byte b) void COutArchive::Write16(UInt16 val) { - for (int i = 0; i < 2; i++) - { - Write8((Byte)val); - val >>= 8; - } + Write8((Byte)val); + Write8((Byte)(val >> 8)); } void COutArchive::Write32(UInt32 val) @@ -101,15 +70,12 @@ void COutArchive::Write64(UInt64 val) void COutArchive::WriteExtra(const CExtraBlock &extra) { - if (extra.SubBlocks.Size() != 0) + FOR_VECTOR (i, extra.SubBlocks) { - FOR_VECTOR (i, extra.SubBlocks) - { - const CExtraSubBlock &subBlock = extra.SubBlocks[i]; - Write16(subBlock.ID); - Write16((UInt16)subBlock.Data.Size()); - WriteBytes(subBlock.Data, (UInt32)subBlock.Data.Size()); - } + const CExtraSubBlock &subBlock = extra.SubBlocks[i]; + Write16((UInt16)subBlock.ID); + Write16((UInt16)subBlock.Data.Size()); + WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size()); } } @@ -125,40 +91,65 @@ void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64) 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) + +void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck) { - SeekToCurPos(); + m_LocalHeaderPos = m_CurPos; + item.LocalHeaderPos = m_CurPos; - bool isZip64 = m_IsZip64 || + bool isZip64 = DOES_NEED_ZIP64(item.PackSize) || DOES_NEED_ZIP64(item.Size); - + + if (needCheck && m_IsZip64) + isZip64 = true; + + const UInt32 localExtraSize = (UInt32)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize()); + if ((UInt16)localExtraSize != localExtraSize) + throw CSystemException(E_FAIL); + if (needCheck && m_ExtraSize != localExtraSize) + throw CSystemException(E_FAIL); + + m_IsZip64 = isZip64; + m_ExtraSize = localExtraSize; + + item.LocalExtra.IsZip64 = isZip64; + Write32(NSignature::kLocalFileHeader); + WriteCommonItemInfo(item, isZip64); + + Write32(item.HasDescriptor() ? 0 : item.Crc); - WRITE_32_VAL_SPEC(item.PackSize, isZip64); - WRITE_32_VAL_SPEC(item.Size, isZip64); - - Write16((UInt16)item.Name.Len()); + UInt64 packSize = item.PackSize; + UInt64 size = item.Size; + + if (item.HasDescriptor()) { - UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 8 + 8): 0) + item.LocalExtra.GetSize()); - if (localExtraSize != m_ExtraSize) - throw CSystemException(E_FAIL); + packSize = 0; + size = 0; } - Write16((UInt16)m_ExtraSize); - WriteBytes((const char *)item.Name, item.Name.Len()); + + WRITE_32_VAL_SPEC(packSize, isZip64); + WRITE_32_VAL_SPEC(size, isZip64); + + Write16((UInt16)item.Name.Len()); + + Write16((UInt16)localExtraSize); + + WriteBytes((const char *)item.Name, (UInt16)item.Name.Len()); if (isZip64) { Write16(NFileHeader::NExtraID::kZip64); Write16(8 + 8); - Write64(item.Size); - Write64(item.PackSize); + Write64(size); + Write64(packSize); } WriteExtra(item.LocalExtra); @@ -166,10 +157,57 @@ void COutArchive::WriteLocalHeader(const CLocalItem &item) // Why don't we write NTFS timestamps to local header? // Probably we want to reduce size of archive? + const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos); + if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize) + throw CSystemException(E_FAIL); + m_LocalFileHeaderSize = localFileHeaderSize; + m_OutBuffer.FlushWithCheck(); - MoveCurPos(item.PackSize); } + +void COutArchive::WriteLocalHeader_Replace(CItemOut &item) +{ + m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize; + + if (item.HasDescriptor()) + { + WriteDescriptor(item); + m_OutBuffer.FlushWithCheck(); + } + + const UInt64 nextPos = m_CurPos; + m_CurPos = m_LocalHeaderPos; + SeekToCurPos(); + WriteLocalHeader(item, true); + m_CurPos = nextPos; + SeekToCurPos(); +} + + +void COutArchive::WriteDescriptor(const CItemOut &item) +{ + Byte buf[kDataDescriptorSize64]; + SetUi32(buf, NSignature::kDataDescriptor); + SetUi32(buf + 4, item.Crc); + unsigned descriptorSize; + if (m_IsZip64) + { + SetUi64(buf + 8, item.PackSize); + SetUi64(buf + 16, item.Size); + descriptorSize = kDataDescriptorSize64; + } + else + { + SetUi32(buf + 8, (UInt32)item.PackSize); + SetUi32(buf + 12, (UInt32)item.Size); + descriptorSize = kDataDescriptorSize32; + } + WriteBytes(buf, descriptorSize); +} + + + void COutArchive::WriteCentralHeader(const CItemOut &item) { bool isUnPack64 = DOES_NEED_ZIP64(item.Size); @@ -182,6 +220,7 @@ void COutArchive::WriteCentralHeader(const CItemOut &item) Write8(item.MadeByVersion.HostOS); WriteCommonItemInfo(item, isZip64); + Write32(item.Crc); WRITE_32_VAL_SPEC(item.PackSize, isPack64); WRITE_32_VAL_SPEC(item.Size, isUnPack64); @@ -196,7 +235,10 @@ void COutArchive::WriteCentralHeader(const CItemOut &item) item.CentralExtra.GetSize()); Write16(centralExtraSize); // test it; - Write16((UInt16)item.Comment.Size()); + + const UInt16 commentSize = (UInt16)item.Comment.Size(); + + Write16(commentSize); Write16(0); // DiskNumberStart; Write16(item.InternalAttrib); Write32(item.ExternalAttrib); @@ -228,14 +270,12 @@ void COutArchive::WriteCentralHeader(const CItemOut &item) } WriteExtra(item.CentralExtra); - if (item.Comment.Size() > 0) - WriteBytes(item.Comment, (UInt32)item.Comment.Size()); + if (commentSize != 0) + WriteBytes(item.Comment, commentSize); } void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment) { - SeekToCurPos(); - UInt64 cdOffset = GetCurPos(); FOR_VECTOR (i, items) WriteCentralHeader(items[i]); @@ -252,6 +292,11 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB { Write32(NSignature::kEcd64); Write64(kEcd64_MainSize); + + // to test extra block: + // const UInt32 extraSize = 1 << 26; + // Write64(kEcd64_MainSize + extraSize); + Write16(45); // made by version Write16(45); // extract version Write32(0); // ThisDiskNumber = 0; @@ -261,6 +306,8 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB Write64((UInt64)cdSize); Write64((UInt64)cdOffset); + // for (UInt32 iii = 0; iii < extraSize; iii++) Write8(1); + Write32(NSignature::kEcd64Locator); Write32(0); // number of the disk with the start of the zip64 end of central directory Write64(cd64EndOffset); @@ -276,37 +323,23 @@ void COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CB WRITE_32_VAL_SPEC(cdSize, cdSize64); WRITE_32_VAL_SPEC(cdOffset, cdOffset64); - UInt32 commentSize = (UInt32)(comment ? comment->Size() : 0); + const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0); Write16((UInt16)commentSize); - if (commentSize > 0) + if (commentSize != 0) WriteBytes((const Byte *)*comment, commentSize); m_OutBuffer.FlushWithCheck(); } -void COutArchive::CreateStreamForCompressing(IOutStream **outStream) +void COutArchive::CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream) { COffsetOutStream *streamSpec = new COffsetOutStream; - CMyComPtr<IOutStream> tempStream(streamSpec); - 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); + outStream = streamSpec; + streamSpec->Init(m_Stream, m_Base + m_CurPos); } -void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream) +void COutArchive::CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream) { - CMyComPtr<ISequentialOutStream> tempStream(m_Stream); - *outStream = tempStream.Detach(); + outStream = m_Stream; } }} |