5 #include "../../Common/OffsetStream.h"
\r
12 void COutArchive::Create(IOutStream *outStream)
\r
14 if (!m_OutBuffer.Create(1 << 16))
\r
15 throw CSystemException(E_OUTOFMEMORY);
\r
16 m_Stream = outStream;
\r
17 m_OutBuffer.SetStream(outStream);
\r
22 void COutArchive::MoveBasePosition(UInt64 distanceToMove)
\r
24 m_BasePosition += distanceToMove; // test overflow
\r
27 void COutArchive::PrepareWriteCompressedDataZip64(UInt16 fileNameLength, bool isZip64, bool aesEncryption)
\r
29 m_IsZip64 = isZip64;
\r
30 m_ExtraSize = isZip64 ? (4 + 8 + 8) : 0;
\r
32 m_ExtraSize += 4 + 7;
\r
33 m_LocalFileHeaderSize = 4 + NFileHeader::kLocalBlockSize + fileNameLength + m_ExtraSize;
\r
36 void COutArchive::PrepareWriteCompressedData(UInt16 fileNameLength, UInt64 unPackSize, bool aesEncryption)
\r
38 // We test it to 0xF8000000 to support case when compressed size
\r
39 // can be larger than uncompressed size.
\r
40 PrepareWriteCompressedDataZip64(fileNameLength, unPackSize >= 0xF8000000, aesEncryption);
\r
43 void COutArchive::PrepareWriteCompressedData2(UInt16 fileNameLength, UInt64 unPackSize, UInt64 packSize, bool aesEncryption)
\r
45 bool isUnPack64 = unPackSize >= 0xFFFFFFFF;
\r
46 bool isPack64 = packSize >= 0xFFFFFFFF;
\r
47 bool isZip64 = isPack64 || isUnPack64;
\r
48 PrepareWriteCompressedDataZip64(fileNameLength, isZip64, aesEncryption);
\r
51 void COutArchive::WriteBytes(const void *buffer, UInt32 size)
\r
53 m_OutBuffer.WriteBytes(buffer, size);
\r
54 m_BasePosition += size;
\r
57 void COutArchive::WriteByte(Byte b)
\r
62 void COutArchive::WriteUInt16(UInt16 value)
\r
64 for (int i = 0; i < 2; i++)
\r
66 WriteByte((Byte)value);
\r
71 void COutArchive::WriteUInt32(UInt32 value)
\r
73 for (int i = 0; i < 4; i++)
\r
75 WriteByte((Byte)value);
\r
80 void COutArchive::WriteUInt64(UInt64 value)
\r
82 for (int i = 0; i < 8; i++)
\r
84 WriteByte((Byte)value);
\r
89 void COutArchive::WriteExtra(const CExtraBlock &extra)
\r
91 if (extra.SubBlocks.Size() != 0)
\r
93 for (int i = 0; i < extra.SubBlocks.Size(); i++)
\r
95 const CExtraSubBlock &subBlock = extra.SubBlocks[i];
\r
96 WriteUInt16(subBlock.ID);
\r
97 WriteUInt16((UInt16)subBlock.Data.GetCapacity());
\r
98 WriteBytes(subBlock.Data, (UInt32)subBlock.Data.GetCapacity());
\r
103 void COutArchive::SeekTo(UInt64 offset)
\r
105 HRESULT res = m_Stream->Seek(offset, STREAM_SEEK_SET, NULL);
\r
107 throw CSystemException(res);
\r
110 void COutArchive::WriteLocalHeader(const CLocalItem &item)
\r
112 SeekTo(m_BasePosition);
\r
114 bool isZip64 = m_IsZip64 || item.PackSize >= 0xFFFFFFFF || item.UnPackSize >= 0xFFFFFFFF;
\r
116 WriteUInt32(NSignature::kLocalFileHeader);
\r
118 Byte ver = item.ExtractVersion.Version;
\r
119 if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
\r
120 ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
\r
123 WriteByte(item.ExtractVersion.HostOS);
\r
124 WriteUInt16(item.Flags);
\r
125 WriteUInt16(item.CompressionMethod);
\r
126 WriteUInt32(item.Time);
\r
127 WriteUInt32(item.FileCRC);
\r
128 WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
\r
129 WriteUInt32(isZip64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
\r
130 WriteUInt16((UInt16)item.Name.Length());
\r
132 UInt16 localExtraSize = (UInt16)((isZip64 ? (4 + 16): 0) + item.LocalExtra.GetSize());
\r
133 if (localExtraSize > m_ExtraSize)
\r
134 throw CSystemException(E_FAIL);
\r
136 WriteUInt16((UInt16)m_ExtraSize); // test it;
\r
137 WriteBytes((const char *)item.Name, item.Name.Length());
\r
139 UInt32 extraPos = 0;
\r
142 extraPos += 4 + 16;
\r
143 WriteUInt16(NFileHeader::NExtraID::kZip64);
\r
145 WriteUInt64(item.UnPackSize);
\r
146 WriteUInt64(item.PackSize);
\r
149 WriteExtra(item.LocalExtra);
\r
150 extraPos += (UInt32)item.LocalExtra.GetSize();
\r
151 for (; extraPos < m_ExtraSize; extraPos++)
\r
154 m_OutBuffer.FlushWithCheck();
\r
155 MoveBasePosition(item.PackSize);
\r
156 SeekTo(m_BasePosition);
\r
159 void COutArchive::WriteCentralHeader(const CItem &item)
\r
161 bool isUnPack64 = item.UnPackSize >= 0xFFFFFFFF;
\r
162 bool isPack64 = item.PackSize >= 0xFFFFFFFF;
\r
163 bool isPosition64 = item.LocalHeaderPosition >= 0xFFFFFFFF;
\r
164 bool isZip64 = isPack64 || isUnPack64 || isPosition64;
\r
166 WriteUInt32(NSignature::kCentralFileHeader);
\r
167 WriteByte(item.MadeByVersion.Version);
\r
168 WriteByte(item.MadeByVersion.HostOS);
\r
170 Byte ver = item.ExtractVersion.Version;
\r
171 if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
\r
172 ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
\r
175 WriteByte(item.ExtractVersion.HostOS);
\r
176 WriteUInt16(item.Flags);
\r
177 WriteUInt16(item.CompressionMethod);
\r
178 WriteUInt32(item.Time);
\r
179 WriteUInt32(item.FileCRC);
\r
180 WriteUInt32(isPack64 ? 0xFFFFFFFF: (UInt32)item.PackSize);
\r
181 WriteUInt32(isUnPack64 ? 0xFFFFFFFF: (UInt32)item.UnPackSize);
\r
182 WriteUInt16((UInt16)item.Name.Length());
\r
183 UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
\r
184 const UInt16 kNtfsExtraSize = 4 + 2 + 2 + (3 * 8);
\r
185 UInt16 centralExtraSize = (UInt16)(isZip64 ? (4 + zip64ExtraSize) : 0) + (item.NtfsTimeIsDefined ? (4 + kNtfsExtraSize) : 0);
\r
186 centralExtraSize = (UInt16)(centralExtraSize + item.CentralExtra.GetSize());
\r
187 WriteUInt16(centralExtraSize); // test it;
\r
188 WriteUInt16((UInt16)item.Comment.GetCapacity());
\r
189 WriteUInt16(0); // DiskNumberStart;
\r
190 WriteUInt16(item.InternalAttributes);
\r
191 WriteUInt32(item.ExternalAttributes);
\r
192 WriteUInt32(isPosition64 ? 0xFFFFFFFF: (UInt32)item.LocalHeaderPosition);
\r
193 WriteBytes((const char *)item.Name, item.Name.Length());
\r
196 WriteUInt16(NFileHeader::NExtraID::kZip64);
\r
197 WriteUInt16(zip64ExtraSize);
\r
199 WriteUInt64(item.UnPackSize);
\r
201 WriteUInt64(item.PackSize);
\r
203 WriteUInt64(item.LocalHeaderPosition);
\r
205 if (item.NtfsTimeIsDefined)
\r
207 WriteUInt16(NFileHeader::NExtraID::kNTFS);
\r
208 WriteUInt16(kNtfsExtraSize);
\r
209 WriteUInt32(0); // reserved
\r
210 WriteUInt16(NFileHeader::NNtfsExtra::kTagTime);
\r
211 WriteUInt16(8 * 3);
\r
212 WriteUInt32(item.NtfsMTime.dwLowDateTime);
\r
213 WriteUInt32(item.NtfsMTime.dwHighDateTime);
\r
214 WriteUInt32(item.NtfsATime.dwLowDateTime);
\r
215 WriteUInt32(item.NtfsATime.dwHighDateTime);
\r
216 WriteUInt32(item.NtfsCTime.dwLowDateTime);
\r
217 WriteUInt32(item.NtfsCTime.dwHighDateTime);
\r
219 WriteExtra(item.CentralExtra);
\r
220 if (item.Comment.GetCapacity() > 0)
\r
221 WriteBytes(item.Comment, (UInt32)item.Comment.GetCapacity());
\r
224 void COutArchive::WriteCentralDir(const CObjectVector<CItem> &items, const CByteBuffer *comment)
\r
226 SeekTo(m_BasePosition);
\r
228 UInt64 cdOffset = GetCurrentPosition();
\r
229 for(int i = 0; i < items.Size(); i++)
\r
230 WriteCentralHeader(items[i]);
\r
231 UInt64 cd64EndOffset = GetCurrentPosition();
\r
232 UInt64 cdSize = cd64EndOffset - cdOffset;
\r
233 bool cdOffset64 = cdOffset >= 0xFFFFFFFF;
\r
234 bool cdSize64 = cdSize >= 0xFFFFFFFF;
\r
235 bool items64 = items.Size() >= 0xFFFF;
\r
236 bool isZip64 = (cdOffset64 || cdSize64 || items64);
\r
240 WriteUInt32(NSignature::kZip64EndOfCentralDir);
\r
241 WriteUInt64(kZip64EcdSize); // ThisDiskNumber = 0;
\r
242 WriteUInt16(45); // version
\r
243 WriteUInt16(45); // version
\r
244 WriteUInt32(0); // ThisDiskNumber = 0;
\r
245 WriteUInt32(0); // StartCentralDirectoryDiskNumber;;
\r
246 WriteUInt64((UInt64)items.Size());
\r
247 WriteUInt64((UInt64)items.Size());
\r
248 WriteUInt64((UInt64)cdSize);
\r
249 WriteUInt64((UInt64)cdOffset);
\r
251 WriteUInt32(NSignature::kZip64EndOfCentralDirLocator);
\r
252 WriteUInt32(0); // number of the disk with the start of the zip64 end of central directory
\r
253 WriteUInt64(cd64EndOffset);
\r
254 WriteUInt32(1); // total number of disks
\r
256 WriteUInt32(NSignature::kEndOfCentralDir);
\r
257 WriteUInt16(0); // ThisDiskNumber = 0;
\r
258 WriteUInt16(0); // StartCentralDirectoryDiskNumber;
\r
259 WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
\r
260 WriteUInt16((UInt16)(items64 ? 0xFFFF: items.Size()));
\r
261 WriteUInt32(cdSize64 ? 0xFFFFFFFF: (UInt32)cdSize);
\r
262 WriteUInt32(cdOffset64 ? 0xFFFFFFFF: (UInt32)cdOffset);
\r
263 UInt32 commentSize = (UInt32)(comment ? comment->GetCapacity() : 0);
\r
264 WriteUInt16((UInt16)commentSize);
\r
265 if (commentSize > 0)
\r
266 WriteBytes((const Byte *)*comment, commentSize);
\r
267 m_OutBuffer.FlushWithCheck();
\r
270 void COutArchive::CreateStreamForCompressing(IOutStream **outStream)
\r
272 COffsetOutStream *streamSpec = new COffsetOutStream;
\r
273 CMyComPtr<IOutStream> tempStream(streamSpec);
\r
274 streamSpec->Init(m_Stream, m_BasePosition + m_LocalFileHeaderSize);
\r
275 *outStream = tempStream.Detach();
\r
278 void COutArchive::SeekToPackedDataPosition()
\r
280 SeekTo(m_BasePosition + m_LocalFileHeaderSize);
\r
283 void COutArchive::CreateStreamForCopying(ISequentialOutStream **outStream)
\r
285 CMyComPtr<ISequentialOutStream> tempStream(m_Stream);
\r
286 *outStream = tempStream.Detach();
\r