xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Zip/ZipOut.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // ZipOut.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../../C/7zCrc.h"
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/TimeUtils.h"
8*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/OffsetStream.h"
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker #include "ZipOut.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
13*f6dc9357SAndroid Build Coastguard Worker namespace NZip {
14*f6dc9357SAndroid Build Coastguard Worker 
ClearRestriction()15*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::ClearRestriction()
16*f6dc9357SAndroid Build Coastguard Worker {
17*f6dc9357SAndroid Build Coastguard Worker   if (SetRestriction)
18*f6dc9357SAndroid Build Coastguard Worker     return SetRestriction->SetRestriction(0, 0);
19*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
20*f6dc9357SAndroid Build Coastguard Worker }
21*f6dc9357SAndroid Build Coastguard Worker 
SetRestrictionFromCurrent()22*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::SetRestrictionFromCurrent()
23*f6dc9357SAndroid Build Coastguard Worker {
24*f6dc9357SAndroid Build Coastguard Worker   if (SetRestriction)
25*f6dc9357SAndroid Build Coastguard Worker     return SetRestriction->SetRestriction(m_Base + m_CurPos, (UInt64)(Int64)-1);
26*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
27*f6dc9357SAndroid Build Coastguard Worker }
28*f6dc9357SAndroid Build Coastguard Worker 
Create(IOutStream * outStream)29*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::Create(IOutStream *outStream)
30*f6dc9357SAndroid Build Coastguard Worker {
31*f6dc9357SAndroid Build Coastguard Worker   m_CurPos = 0;
32*f6dc9357SAndroid Build Coastguard Worker   if (!m_OutBuffer.Create(1 << 16))
33*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
34*f6dc9357SAndroid Build Coastguard Worker   m_Stream = outStream;
35*f6dc9357SAndroid Build Coastguard Worker   m_OutBuffer.SetStream(outStream);
36*f6dc9357SAndroid Build Coastguard Worker   m_OutBuffer.Init();
37*f6dc9357SAndroid Build Coastguard Worker 
38*f6dc9357SAndroid Build Coastguard Worker   return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base);
39*f6dc9357SAndroid Build Coastguard Worker }
40*f6dc9357SAndroid Build Coastguard Worker 
SeekToCurPos()41*f6dc9357SAndroid Build Coastguard Worker void COutArchive::SeekToCurPos()
42*f6dc9357SAndroid Build Coastguard Worker {
43*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = m_Stream->Seek((Int64)(m_Base + m_CurPos), STREAM_SEEK_SET, NULL);
44*f6dc9357SAndroid Build Coastguard Worker   if (res != S_OK)
45*f6dc9357SAndroid Build Coastguard Worker     throw CSystemException(res);
46*f6dc9357SAndroid Build Coastguard Worker }
47*f6dc9357SAndroid Build Coastguard Worker 
48*f6dc9357SAndroid Build Coastguard Worker #define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF)
49*f6dc9357SAndroid Build Coastguard Worker // #define DOES_NEED_ZIP64(v) (v >= 0)
50*f6dc9357SAndroid Build Coastguard Worker 
51*f6dc9357SAndroid Build Coastguard Worker 
WriteBytes(const void * data,size_t size)52*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteBytes(const void *data, size_t size)
53*f6dc9357SAndroid Build Coastguard Worker {
54*f6dc9357SAndroid Build Coastguard Worker   m_OutBuffer.WriteBytes(data, size);
55*f6dc9357SAndroid Build Coastguard Worker   m_CurPos += size;
56*f6dc9357SAndroid Build Coastguard Worker }
57*f6dc9357SAndroid Build Coastguard Worker 
Write8(Byte b)58*f6dc9357SAndroid Build Coastguard Worker void COutArchive::Write8(Byte b)
59*f6dc9357SAndroid Build Coastguard Worker {
60*f6dc9357SAndroid Build Coastguard Worker   m_OutBuffer.WriteByte(b);
61*f6dc9357SAndroid Build Coastguard Worker   m_CurPos++;
62*f6dc9357SAndroid Build Coastguard Worker }
63*f6dc9357SAndroid Build Coastguard Worker 
Write16(UInt16 val)64*f6dc9357SAndroid Build Coastguard Worker void COutArchive::Write16(UInt16 val)
65*f6dc9357SAndroid Build Coastguard Worker {
66*f6dc9357SAndroid Build Coastguard Worker   Write8((Byte)val);
67*f6dc9357SAndroid Build Coastguard Worker   Write8((Byte)(val >> 8));
68*f6dc9357SAndroid Build Coastguard Worker }
69*f6dc9357SAndroid Build Coastguard Worker 
Write32(UInt32 val)70*f6dc9357SAndroid Build Coastguard Worker void COutArchive::Write32(UInt32 val)
71*f6dc9357SAndroid Build Coastguard Worker {
72*f6dc9357SAndroid Build Coastguard Worker   for (int i = 0; i < 4; i++)
73*f6dc9357SAndroid Build Coastguard Worker   {
74*f6dc9357SAndroid Build Coastguard Worker     Write8((Byte)val);
75*f6dc9357SAndroid Build Coastguard Worker     val >>= 8;
76*f6dc9357SAndroid Build Coastguard Worker   }
77*f6dc9357SAndroid Build Coastguard Worker }
78*f6dc9357SAndroid Build Coastguard Worker 
Write64(UInt64 val)79*f6dc9357SAndroid Build Coastguard Worker void COutArchive::Write64(UInt64 val)
80*f6dc9357SAndroid Build Coastguard Worker {
81*f6dc9357SAndroid Build Coastguard Worker   for (int i = 0; i < 8; i++)
82*f6dc9357SAndroid Build Coastguard Worker   {
83*f6dc9357SAndroid Build Coastguard Worker     Write8((Byte)val);
84*f6dc9357SAndroid Build Coastguard Worker     val >>= 8;
85*f6dc9357SAndroid Build Coastguard Worker   }
86*f6dc9357SAndroid Build Coastguard Worker }
87*f6dc9357SAndroid Build Coastguard Worker 
WriteExtra(const CExtraBlock & extra)88*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteExtra(const CExtraBlock &extra)
89*f6dc9357SAndroid Build Coastguard Worker {
90*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, extra.SubBlocks)
91*f6dc9357SAndroid Build Coastguard Worker   {
92*f6dc9357SAndroid Build Coastguard Worker     const CExtraSubBlock &subBlock = extra.SubBlocks[i];
93*f6dc9357SAndroid Build Coastguard Worker     Write16((UInt16)subBlock.ID);
94*f6dc9357SAndroid Build Coastguard Worker     Write16((UInt16)subBlock.Data.Size());
95*f6dc9357SAndroid Build Coastguard Worker     WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size());
96*f6dc9357SAndroid Build Coastguard Worker   }
97*f6dc9357SAndroid Build Coastguard Worker }
98*f6dc9357SAndroid Build Coastguard Worker 
WriteCommonItemInfo(const CLocalItem & item,bool isZip64)99*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64)
100*f6dc9357SAndroid Build Coastguard Worker {
101*f6dc9357SAndroid Build Coastguard Worker   {
102*f6dc9357SAndroid Build Coastguard Worker     Byte ver = item.ExtractVersion.Version;
103*f6dc9357SAndroid Build Coastguard Worker     if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
104*f6dc9357SAndroid Build Coastguard Worker       ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
105*f6dc9357SAndroid Build Coastguard Worker     Write8(ver);
106*f6dc9357SAndroid Build Coastguard Worker   }
107*f6dc9357SAndroid Build Coastguard Worker   Write8(item.ExtractVersion.HostOS);
108*f6dc9357SAndroid Build Coastguard Worker   Write16(item.Flags);
109*f6dc9357SAndroid Build Coastguard Worker   Write16(item.Method);
110*f6dc9357SAndroid Build Coastguard Worker   Write32(item.Time);
111*f6dc9357SAndroid Build Coastguard Worker }
112*f6dc9357SAndroid Build Coastguard Worker 
113*f6dc9357SAndroid Build Coastguard Worker 
114*f6dc9357SAndroid Build Coastguard Worker #define WRITE_32_VAL_SPEC(_v_, _isZip64_) Write32((_isZip64_) ? 0xFFFFFFFF : (UInt32)(_v_));
115*f6dc9357SAndroid Build Coastguard Worker 
116*f6dc9357SAndroid Build Coastguard Worker 
WriteUtfName(const CItemOut & item)117*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteUtfName(const CItemOut &item)
118*f6dc9357SAndroid Build Coastguard Worker {
119*f6dc9357SAndroid Build Coastguard Worker   if (item.Name_Utf.Size() == 0)
120*f6dc9357SAndroid Build Coastguard Worker     return;
121*f6dc9357SAndroid Build Coastguard Worker   Write16(NFileHeader::NExtraID::kIzUnicodeName);
122*f6dc9357SAndroid Build Coastguard Worker   Write16((UInt16)(5 + item.Name_Utf.Size()));
123*f6dc9357SAndroid Build Coastguard Worker   Write8(1); // (1 = version) of that extra field
124*f6dc9357SAndroid Build Coastguard Worker   Write32(CrcCalc(item.Name.Ptr(), item.Name.Len()));
125*f6dc9357SAndroid Build Coastguard Worker   WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size());
126*f6dc9357SAndroid Build Coastguard Worker }
127*f6dc9357SAndroid Build Coastguard Worker 
128*f6dc9357SAndroid Build Coastguard Worker 
129*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8);
130*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4);
131*f6dc9357SAndroid Build Coastguard Worker 
WriteTimeExtra(const CItemOut & item,bool writeNtfs)132*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
133*f6dc9357SAndroid Build Coastguard Worker {
134*f6dc9357SAndroid Build Coastguard Worker   if (writeNtfs)
135*f6dc9357SAndroid Build Coastguard Worker   {
136*f6dc9357SAndroid Build Coastguard Worker     // windows explorer ignores that extra
137*f6dc9357SAndroid Build Coastguard Worker     Write16(NFileHeader::NExtraID::kNTFS);
138*f6dc9357SAndroid Build Coastguard Worker     Write16(k_Ntfs_ExtraSize);
139*f6dc9357SAndroid Build Coastguard Worker     Write32(0); // reserved
140*f6dc9357SAndroid Build Coastguard Worker     Write16(NFileHeader::NNtfsExtra::kTagTime);
141*f6dc9357SAndroid Build Coastguard Worker     Write16(8 * 3);
142*f6dc9357SAndroid Build Coastguard Worker     WriteNtfsTime(item.Ntfs_MTime);
143*f6dc9357SAndroid Build Coastguard Worker     WriteNtfsTime(item.Ntfs_ATime);
144*f6dc9357SAndroid Build Coastguard Worker     WriteNtfsTime(item.Ntfs_CTime);
145*f6dc9357SAndroid Build Coastguard Worker   }
146*f6dc9357SAndroid Build Coastguard Worker 
147*f6dc9357SAndroid Build Coastguard Worker   if (item.Write_UnixTime)
148*f6dc9357SAndroid Build Coastguard Worker   {
149*f6dc9357SAndroid Build Coastguard Worker     // windows explorer ignores that extra
150*f6dc9357SAndroid Build Coastguard Worker     // by specification : should we write to local header also?
151*f6dc9357SAndroid Build Coastguard Worker     Write16(NFileHeader::NExtraID::kUnixTime);
152*f6dc9357SAndroid Build Coastguard Worker     Write16(k_UnixTime_ExtraSize);
153*f6dc9357SAndroid Build Coastguard Worker     const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime);
154*f6dc9357SAndroid Build Coastguard Worker     Write8(flags);
155*f6dc9357SAndroid Build Coastguard Worker     UInt32 unixTime;
156*f6dc9357SAndroid Build Coastguard Worker     NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime);
157*f6dc9357SAndroid Build Coastguard Worker     Write32(unixTime);
158*f6dc9357SAndroid Build Coastguard Worker   }
159*f6dc9357SAndroid Build Coastguard Worker }
160*f6dc9357SAndroid Build Coastguard Worker 
161*f6dc9357SAndroid Build Coastguard Worker 
WriteLocalHeader(CItemOut & item,bool needCheck)162*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
163*f6dc9357SAndroid Build Coastguard Worker {
164*f6dc9357SAndroid Build Coastguard Worker   m_LocalHeaderPos = m_CurPos;
165*f6dc9357SAndroid Build Coastguard Worker   item.LocalHeaderPos = m_CurPos;
166*f6dc9357SAndroid Build Coastguard Worker 
167*f6dc9357SAndroid Build Coastguard Worker   bool isZip64 =
168*f6dc9357SAndroid Build Coastguard Worker       DOES_NEED_ZIP64(item.PackSize) ||
169*f6dc9357SAndroid Build Coastguard Worker       DOES_NEED_ZIP64(item.Size);
170*f6dc9357SAndroid Build Coastguard Worker 
171*f6dc9357SAndroid Build Coastguard Worker   if (needCheck && m_IsZip64)
172*f6dc9357SAndroid Build Coastguard Worker     isZip64 = true;
173*f6dc9357SAndroid Build Coastguard Worker 
174*f6dc9357SAndroid Build Coastguard Worker   // Why don't we write NTFS timestamps to local header?
175*f6dc9357SAndroid Build Coastguard Worker   // Probably we want to reduce size of archive?
176*f6dc9357SAndroid Build Coastguard Worker   const bool writeNtfs = false; // do not write NTFS timestamp to local header
177*f6dc9357SAndroid Build Coastguard Worker   // const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header
178*f6dc9357SAndroid Build Coastguard Worker   const UInt32 localExtraSize = (UInt32)(
179*f6dc9357SAndroid Build Coastguard Worker       (isZip64 ? (4 + 8 + 8): 0)
180*f6dc9357SAndroid Build Coastguard Worker       + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
181*f6dc9357SAndroid Build Coastguard Worker       + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
182*f6dc9357SAndroid Build Coastguard Worker       + item.Get_UtfName_ExtraSize()
183*f6dc9357SAndroid Build Coastguard Worker       + item.LocalExtra.GetSize());
184*f6dc9357SAndroid Build Coastguard Worker   if ((UInt16)localExtraSize != localExtraSize)
185*f6dc9357SAndroid Build Coastguard Worker     throw CSystemException(E_FAIL);
186*f6dc9357SAndroid Build Coastguard Worker   if (needCheck && m_ExtraSize != localExtraSize)
187*f6dc9357SAndroid Build Coastguard Worker     throw CSystemException(E_FAIL);
188*f6dc9357SAndroid Build Coastguard Worker 
189*f6dc9357SAndroid Build Coastguard Worker   m_IsZip64 = isZip64;
190*f6dc9357SAndroid Build Coastguard Worker   m_ExtraSize = localExtraSize;
191*f6dc9357SAndroid Build Coastguard Worker 
192*f6dc9357SAndroid Build Coastguard Worker   item.LocalExtra.IsZip64 = isZip64;
193*f6dc9357SAndroid Build Coastguard Worker 
194*f6dc9357SAndroid Build Coastguard Worker   Write32(NSignature::kLocalFileHeader);
195*f6dc9357SAndroid Build Coastguard Worker 
196*f6dc9357SAndroid Build Coastguard Worker   WriteCommonItemInfo(item, isZip64);
197*f6dc9357SAndroid Build Coastguard Worker 
198*f6dc9357SAndroid Build Coastguard Worker   Write32(item.HasDescriptor() ? 0 : item.Crc);
199*f6dc9357SAndroid Build Coastguard Worker 
200*f6dc9357SAndroid Build Coastguard Worker   UInt64 packSize = item.PackSize;
201*f6dc9357SAndroid Build Coastguard Worker   UInt64 size = item.Size;
202*f6dc9357SAndroid Build Coastguard Worker 
203*f6dc9357SAndroid Build Coastguard Worker   if (item.HasDescriptor())
204*f6dc9357SAndroid Build Coastguard Worker   {
205*f6dc9357SAndroid Build Coastguard Worker     packSize = 0;
206*f6dc9357SAndroid Build Coastguard Worker     size = 0;
207*f6dc9357SAndroid Build Coastguard Worker   }
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker   WRITE_32_VAL_SPEC(packSize, isZip64)
210*f6dc9357SAndroid Build Coastguard Worker   WRITE_32_VAL_SPEC(size, isZip64)
211*f6dc9357SAndroid Build Coastguard Worker 
212*f6dc9357SAndroid Build Coastguard Worker   Write16((UInt16)item.Name.Len());
213*f6dc9357SAndroid Build Coastguard Worker 
214*f6dc9357SAndroid Build Coastguard Worker   Write16((UInt16)localExtraSize);
215*f6dc9357SAndroid Build Coastguard Worker 
216*f6dc9357SAndroid Build Coastguard Worker   WriteBytes((const char *)item.Name, (UInt16)item.Name.Len());
217*f6dc9357SAndroid Build Coastguard Worker 
218*f6dc9357SAndroid Build Coastguard Worker   if (isZip64)
219*f6dc9357SAndroid Build Coastguard Worker   {
220*f6dc9357SAndroid Build Coastguard Worker     Write16(NFileHeader::NExtraID::kZip64);
221*f6dc9357SAndroid Build Coastguard Worker     Write16(8 + 8);
222*f6dc9357SAndroid Build Coastguard Worker     Write64(size);
223*f6dc9357SAndroid Build Coastguard Worker     Write64(packSize);
224*f6dc9357SAndroid Build Coastguard Worker   }
225*f6dc9357SAndroid Build Coastguard Worker 
226*f6dc9357SAndroid Build Coastguard Worker   WriteTimeExtra(item, writeNtfs);
227*f6dc9357SAndroid Build Coastguard Worker 
228*f6dc9357SAndroid Build Coastguard Worker   WriteUtfName(item);
229*f6dc9357SAndroid Build Coastguard Worker 
230*f6dc9357SAndroid Build Coastguard Worker   WriteExtra(item.LocalExtra);
231*f6dc9357SAndroid Build Coastguard Worker 
232*f6dc9357SAndroid Build Coastguard Worker   const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
233*f6dc9357SAndroid Build Coastguard Worker   if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
234*f6dc9357SAndroid Build Coastguard Worker     throw CSystemException(E_FAIL);
235*f6dc9357SAndroid Build Coastguard Worker   m_LocalFileHeaderSize = localFileHeaderSize;
236*f6dc9357SAndroid Build Coastguard Worker 
237*f6dc9357SAndroid Build Coastguard Worker   m_OutBuffer.FlushWithCheck();
238*f6dc9357SAndroid Build Coastguard Worker }
239*f6dc9357SAndroid Build Coastguard Worker 
240*f6dc9357SAndroid Build Coastguard Worker 
WriteLocalHeader_Replace(CItemOut & item)241*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteLocalHeader_Replace(CItemOut &item)
242*f6dc9357SAndroid Build Coastguard Worker {
243*f6dc9357SAndroid Build Coastguard Worker   m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize;
244*f6dc9357SAndroid Build Coastguard Worker 
245*f6dc9357SAndroid Build Coastguard Worker   if (item.HasDescriptor())
246*f6dc9357SAndroid Build Coastguard Worker   {
247*f6dc9357SAndroid Build Coastguard Worker     WriteDescriptor(item);
248*f6dc9357SAndroid Build Coastguard Worker     m_OutBuffer.FlushWithCheck();
249*f6dc9357SAndroid Build Coastguard Worker     return;
250*f6dc9357SAndroid Build Coastguard Worker     // we don't replace local header, if we write Descriptor.
251*f6dc9357SAndroid Build Coastguard Worker     // so local header with Descriptor flag must be written to local header before.
252*f6dc9357SAndroid Build Coastguard Worker   }
253*f6dc9357SAndroid Build Coastguard Worker 
254*f6dc9357SAndroid Build Coastguard Worker   const UInt64 nextPos = m_CurPos;
255*f6dc9357SAndroid Build Coastguard Worker   m_CurPos = m_LocalHeaderPos;
256*f6dc9357SAndroid Build Coastguard Worker   SeekToCurPos();
257*f6dc9357SAndroid Build Coastguard Worker   WriteLocalHeader(item, true);
258*f6dc9357SAndroid Build Coastguard Worker   m_CurPos = nextPos;
259*f6dc9357SAndroid Build Coastguard Worker   SeekToCurPos();
260*f6dc9357SAndroid Build Coastguard Worker }
261*f6dc9357SAndroid Build Coastguard Worker 
262*f6dc9357SAndroid Build Coastguard Worker 
WriteDescriptor(const CItemOut & item)263*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteDescriptor(const CItemOut &item)
264*f6dc9357SAndroid Build Coastguard Worker {
265*f6dc9357SAndroid Build Coastguard Worker   Byte buf[kDataDescriptorSize64];
266*f6dc9357SAndroid Build Coastguard Worker   SetUi32(buf, NSignature::kDataDescriptor)
267*f6dc9357SAndroid Build Coastguard Worker   SetUi32(buf + 4, item.Crc)
268*f6dc9357SAndroid Build Coastguard Worker   unsigned descriptorSize;
269*f6dc9357SAndroid Build Coastguard Worker   if (m_IsZip64)
270*f6dc9357SAndroid Build Coastguard Worker   {
271*f6dc9357SAndroid Build Coastguard Worker     SetUi64(buf + 8, item.PackSize)
272*f6dc9357SAndroid Build Coastguard Worker     SetUi64(buf + 16, item.Size)
273*f6dc9357SAndroid Build Coastguard Worker     descriptorSize = kDataDescriptorSize64;
274*f6dc9357SAndroid Build Coastguard Worker   }
275*f6dc9357SAndroid Build Coastguard Worker   else
276*f6dc9357SAndroid Build Coastguard Worker   {
277*f6dc9357SAndroid Build Coastguard Worker     SetUi32(buf + 8, (UInt32)item.PackSize)
278*f6dc9357SAndroid Build Coastguard Worker     SetUi32(buf + 12, (UInt32)item.Size)
279*f6dc9357SAndroid Build Coastguard Worker     descriptorSize = kDataDescriptorSize32;
280*f6dc9357SAndroid Build Coastguard Worker   }
281*f6dc9357SAndroid Build Coastguard Worker   WriteBytes(buf, descriptorSize);
282*f6dc9357SAndroid Build Coastguard Worker }
283*f6dc9357SAndroid Build Coastguard Worker 
284*f6dc9357SAndroid Build Coastguard Worker 
285*f6dc9357SAndroid Build Coastguard Worker 
WriteCentralHeader(const CItemOut & item)286*f6dc9357SAndroid Build Coastguard Worker void COutArchive::WriteCentralHeader(const CItemOut &item)
287*f6dc9357SAndroid Build Coastguard Worker {
288*f6dc9357SAndroid Build Coastguard Worker   const bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
289*f6dc9357SAndroid Build Coastguard Worker   const bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
290*f6dc9357SAndroid Build Coastguard Worker   const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
291*f6dc9357SAndroid Build Coastguard Worker   const bool isZip64 = isPack64 || isUnPack64 || isPosition64;
292*f6dc9357SAndroid Build Coastguard Worker 
293*f6dc9357SAndroid Build Coastguard Worker   Write32(NSignature::kCentralFileHeader);
294*f6dc9357SAndroid Build Coastguard Worker   Write8(item.MadeByVersion.Version);
295*f6dc9357SAndroid Build Coastguard Worker   Write8(item.MadeByVersion.HostOS);
296*f6dc9357SAndroid Build Coastguard Worker 
297*f6dc9357SAndroid Build Coastguard Worker   WriteCommonItemInfo(item, isZip64);
298*f6dc9357SAndroid Build Coastguard Worker   Write32(item.Crc);
299*f6dc9357SAndroid Build Coastguard Worker 
300*f6dc9357SAndroid Build Coastguard Worker   WRITE_32_VAL_SPEC(item.PackSize, isPack64)
301*f6dc9357SAndroid Build Coastguard Worker   WRITE_32_VAL_SPEC(item.Size, isUnPack64)
302*f6dc9357SAndroid Build Coastguard Worker 
303*f6dc9357SAndroid Build Coastguard Worker   Write16((UInt16)item.Name.Len());
304*f6dc9357SAndroid Build Coastguard Worker 
305*f6dc9357SAndroid Build Coastguard Worker   const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
306*f6dc9357SAndroid Build Coastguard Worker   const bool writeNtfs = item.Write_NtfsTime;
307*f6dc9357SAndroid Build Coastguard Worker   const size_t centralExtraSize =
308*f6dc9357SAndroid Build Coastguard Worker       (isZip64 ? 4 + zip64ExtraSize : 0)
309*f6dc9357SAndroid Build Coastguard Worker       + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
310*f6dc9357SAndroid Build Coastguard Worker       + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
311*f6dc9357SAndroid Build Coastguard Worker       + item.Get_UtfName_ExtraSize()
312*f6dc9357SAndroid Build Coastguard Worker       + item.CentralExtra.GetSize();
313*f6dc9357SAndroid Build Coastguard Worker 
314*f6dc9357SAndroid Build Coastguard Worker   const UInt16 centralExtraSize16 = (UInt16)centralExtraSize;
315*f6dc9357SAndroid Build Coastguard Worker   if (centralExtraSize16 != centralExtraSize)
316*f6dc9357SAndroid Build Coastguard Worker     throw CSystemException(E_FAIL);
317*f6dc9357SAndroid Build Coastguard Worker 
318*f6dc9357SAndroid Build Coastguard Worker   Write16(centralExtraSize16);
319*f6dc9357SAndroid Build Coastguard Worker 
320*f6dc9357SAndroid Build Coastguard Worker   const UInt16 commentSize = (UInt16)item.Comment.Size();
321*f6dc9357SAndroid Build Coastguard Worker 
322*f6dc9357SAndroid Build Coastguard Worker   Write16(commentSize);
323*f6dc9357SAndroid Build Coastguard Worker   Write16(0); // DiskNumberStart
324*f6dc9357SAndroid Build Coastguard Worker   Write16(item.InternalAttrib);
325*f6dc9357SAndroid Build Coastguard Worker   Write32(item.ExternalAttrib);
326*f6dc9357SAndroid Build Coastguard Worker   WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64)
327*f6dc9357SAndroid Build Coastguard Worker   WriteBytes((const char *)item.Name, item.Name.Len());
328*f6dc9357SAndroid Build Coastguard Worker 
329*f6dc9357SAndroid Build Coastguard Worker   if (isZip64)
330*f6dc9357SAndroid Build Coastguard Worker   {
331*f6dc9357SAndroid Build Coastguard Worker     Write16(NFileHeader::NExtraID::kZip64);
332*f6dc9357SAndroid Build Coastguard Worker     Write16(zip64ExtraSize);
333*f6dc9357SAndroid Build Coastguard Worker     if (isUnPack64)
334*f6dc9357SAndroid Build Coastguard Worker       Write64(item.Size);
335*f6dc9357SAndroid Build Coastguard Worker     if (isPack64)
336*f6dc9357SAndroid Build Coastguard Worker       Write64(item.PackSize);
337*f6dc9357SAndroid Build Coastguard Worker     if (isPosition64)
338*f6dc9357SAndroid Build Coastguard Worker       Write64(item.LocalHeaderPos);
339*f6dc9357SAndroid Build Coastguard Worker   }
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker   WriteTimeExtra(item, writeNtfs);
342*f6dc9357SAndroid Build Coastguard Worker   WriteUtfName(item);
343*f6dc9357SAndroid Build Coastguard Worker 
344*f6dc9357SAndroid Build Coastguard Worker   WriteExtra(item.CentralExtra);
345*f6dc9357SAndroid Build Coastguard Worker   if (commentSize != 0)
346*f6dc9357SAndroid Build Coastguard Worker     WriteBytes(item.Comment, commentSize);
347*f6dc9357SAndroid Build Coastguard Worker }
348*f6dc9357SAndroid Build Coastguard Worker 
WriteCentralDir(const CObjectVector<CItemOut> & items,const CByteBuffer * comment)349*f6dc9357SAndroid Build Coastguard Worker HRESULT COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
350*f6dc9357SAndroid Build Coastguard Worker {
351*f6dc9357SAndroid Build Coastguard Worker   RINOK(ClearRestriction())
352*f6dc9357SAndroid Build Coastguard Worker 
353*f6dc9357SAndroid Build Coastguard Worker   const UInt64 cdOffset = GetCurPos();
354*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, items)
355*f6dc9357SAndroid Build Coastguard Worker     WriteCentralHeader(items[i]);
356*f6dc9357SAndroid Build Coastguard Worker   const UInt64 cd64EndOffset = GetCurPos();
357*f6dc9357SAndroid Build Coastguard Worker   const UInt64 cdSize = cd64EndOffset - cdOffset;
358*f6dc9357SAndroid Build Coastguard Worker   const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
359*f6dc9357SAndroid Build Coastguard Worker   const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
360*f6dc9357SAndroid Build Coastguard Worker   const bool items64 = items.Size() >= 0xFFFF;
361*f6dc9357SAndroid Build Coastguard Worker   const bool isZip64 = (cdOffset64 || cdSize64 || items64);
362*f6dc9357SAndroid Build Coastguard Worker 
363*f6dc9357SAndroid Build Coastguard Worker   // isZip64 = true; // to test Zip64
364*f6dc9357SAndroid Build Coastguard Worker 
365*f6dc9357SAndroid Build Coastguard Worker   if (isZip64)
366*f6dc9357SAndroid Build Coastguard Worker   {
367*f6dc9357SAndroid Build Coastguard Worker     Write32(NSignature::kEcd64);
368*f6dc9357SAndroid Build Coastguard Worker     Write64(kEcd64_MainSize);
369*f6dc9357SAndroid Build Coastguard Worker 
370*f6dc9357SAndroid Build Coastguard Worker     // to test extra block:
371*f6dc9357SAndroid Build Coastguard Worker     // const UInt32 extraSize = 1 << 26;
372*f6dc9357SAndroid Build Coastguard Worker     // Write64(kEcd64_MainSize + extraSize);
373*f6dc9357SAndroid Build Coastguard Worker 
374*f6dc9357SAndroid Build Coastguard Worker     Write16(45); // made by version
375*f6dc9357SAndroid Build Coastguard Worker     Write16(45); // extract version
376*f6dc9357SAndroid Build Coastguard Worker     Write32(0); // ThisDiskNumber
377*f6dc9357SAndroid Build Coastguard Worker     Write32(0); // StartCentralDirectoryDiskNumber
378*f6dc9357SAndroid Build Coastguard Worker     Write64((UInt64)items.Size());
379*f6dc9357SAndroid Build Coastguard Worker     Write64((UInt64)items.Size());
380*f6dc9357SAndroid Build Coastguard Worker     Write64((UInt64)cdSize);
381*f6dc9357SAndroid Build Coastguard Worker     Write64((UInt64)cdOffset);
382*f6dc9357SAndroid Build Coastguard Worker 
383*f6dc9357SAndroid Build Coastguard Worker     // for (UInt32 iii = 0; iii < extraSize; iii++) Write8(1);
384*f6dc9357SAndroid Build Coastguard Worker 
385*f6dc9357SAndroid Build Coastguard Worker     Write32(NSignature::kEcd64Locator);
386*f6dc9357SAndroid Build Coastguard Worker     Write32(0); // number of the disk with the start of the zip64 end of central directory
387*f6dc9357SAndroid Build Coastguard Worker     Write64(cd64EndOffset);
388*f6dc9357SAndroid Build Coastguard Worker     Write32(1); // total number of disks
389*f6dc9357SAndroid Build Coastguard Worker   }
390*f6dc9357SAndroid Build Coastguard Worker 
391*f6dc9357SAndroid Build Coastguard Worker   Write32(NSignature::kEcd);
392*f6dc9357SAndroid Build Coastguard Worker   Write16(0); // ThisDiskNumber
393*f6dc9357SAndroid Build Coastguard Worker   Write16(0); // StartCentralDirectoryDiskNumber
394*f6dc9357SAndroid Build Coastguard Worker   Write16((UInt16)(items64 ? 0xFFFF: items.Size()));
395*f6dc9357SAndroid Build Coastguard Worker   Write16((UInt16)(items64 ? 0xFFFF: items.Size()));
396*f6dc9357SAndroid Build Coastguard Worker 
397*f6dc9357SAndroid Build Coastguard Worker   WRITE_32_VAL_SPEC(cdSize, cdSize64)
398*f6dc9357SAndroid Build Coastguard Worker   WRITE_32_VAL_SPEC(cdOffset, cdOffset64)
399*f6dc9357SAndroid Build Coastguard Worker 
400*f6dc9357SAndroid Build Coastguard Worker   const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0);
401*f6dc9357SAndroid Build Coastguard Worker   Write16((UInt16)commentSize);
402*f6dc9357SAndroid Build Coastguard Worker   if (commentSize != 0)
403*f6dc9357SAndroid Build Coastguard Worker     WriteBytes((const Byte *)*comment, commentSize);
404*f6dc9357SAndroid Build Coastguard Worker   m_OutBuffer.FlushWithCheck();
405*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
406*f6dc9357SAndroid Build Coastguard Worker }
407*f6dc9357SAndroid Build Coastguard Worker 
CreateStreamForCompressing(CMyComPtr<IOutStream> & outStream)408*f6dc9357SAndroid Build Coastguard Worker void COutArchive::CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream)
409*f6dc9357SAndroid Build Coastguard Worker {
410*f6dc9357SAndroid Build Coastguard Worker   COffsetOutStream *streamSpec = new COffsetOutStream;
411*f6dc9357SAndroid Build Coastguard Worker   outStream = streamSpec;
412*f6dc9357SAndroid Build Coastguard Worker   streamSpec->Init(m_Stream, m_Base + m_CurPos);
413*f6dc9357SAndroid Build Coastguard Worker }
414*f6dc9357SAndroid Build Coastguard Worker 
CreateStreamForCopying(CMyComPtr<ISequentialOutStream> & outStream)415*f6dc9357SAndroid Build Coastguard Worker void COutArchive::CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream)
416*f6dc9357SAndroid Build Coastguard Worker {
417*f6dc9357SAndroid Build Coastguard Worker   outStream = m_Stream;
418*f6dc9357SAndroid Build Coastguard Worker }
419*f6dc9357SAndroid Build Coastguard Worker 
420*f6dc9357SAndroid Build Coastguard Worker }}
421