xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Zip/ZipItem.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // Archive/ZipItem.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/CpuArch.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../../C/7zCrc.h"
7*f6dc9357SAndroid Build Coastguard Worker 
8*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/IntToString.h"
9*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/MyLinux.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../../../Common/StringConvert.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker #include "../../../Windows/PropVariantUtils.h"
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../Common/ItemNameUtils.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "ZipItem.h"
17*f6dc9357SAndroid Build Coastguard Worker 
18*f6dc9357SAndroid Build Coastguard Worker namespace NArchive {
19*f6dc9357SAndroid Build Coastguard Worker namespace NZip {
20*f6dc9357SAndroid Build Coastguard Worker 
21*f6dc9357SAndroid Build Coastguard Worker using namespace NFileHeader;
22*f6dc9357SAndroid Build Coastguard Worker 
23*f6dc9357SAndroid Build Coastguard Worker 
24*f6dc9357SAndroid Build Coastguard Worker /*
25*f6dc9357SAndroid Build Coastguard Worker const char *k_SpecName_NTFS_STREAM = "@@NTFS@STREAM@";
26*f6dc9357SAndroid Build Coastguard Worker const char *k_SpecName_MAC_RESOURCE_FORK = "@@MAC@RESOURCE-FORK@";
27*f6dc9357SAndroid Build Coastguard Worker */
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker static const CUInt32PCharPair g_ExtraTypes[] =
30*f6dc9357SAndroid Build Coastguard Worker {
31*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kZip64, "Zip64" },
32*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kNTFS, "NTFS" },
33*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kUnix0, "UNIX" },
34*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kStrongEncrypt, "StrongCrypto" },
35*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kUnixTime, "UT" },
36*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kUnix1, "UX" },
37*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kUnix2, "Ux" },
38*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kUnixN, "ux" },
39*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kIzUnicodeComment, "uc" },
40*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kIzUnicodeName, "up" },
41*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kIzNtSecurityDescriptor, "SD" },
42*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kWzAES, "WzAES" },
43*f6dc9357SAndroid Build Coastguard Worker   { NExtraID::kApkAlign, "ApkAlign" }
44*f6dc9357SAndroid Build Coastguard Worker };
45*f6dc9357SAndroid Build Coastguard Worker 
PrintInfo(AString & s) const46*f6dc9357SAndroid Build Coastguard Worker void CExtraSubBlock::PrintInfo(AString &s) const
47*f6dc9357SAndroid Build Coastguard Worker {
48*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTypes); i++)
49*f6dc9357SAndroid Build Coastguard Worker   {
50*f6dc9357SAndroid Build Coastguard Worker     const CUInt32PCharPair &pair = g_ExtraTypes[i];
51*f6dc9357SAndroid Build Coastguard Worker     if (pair.Value == ID)
52*f6dc9357SAndroid Build Coastguard Worker     {
53*f6dc9357SAndroid Build Coastguard Worker       s += pair.Name;
54*f6dc9357SAndroid Build Coastguard Worker       if (ID == NExtraID::kUnixTime)
55*f6dc9357SAndroid Build Coastguard Worker       {
56*f6dc9357SAndroid Build Coastguard Worker         if (Data.Size() >= 1)
57*f6dc9357SAndroid Build Coastguard Worker         {
58*f6dc9357SAndroid Build Coastguard Worker           s.Add_Colon();
59*f6dc9357SAndroid Build Coastguard Worker           const Byte flags = Data[0];
60*f6dc9357SAndroid Build Coastguard Worker           if (flags & 1) s.Add_Char('M');
61*f6dc9357SAndroid Build Coastguard Worker           if (flags & 2) s.Add_Char('A');
62*f6dc9357SAndroid Build Coastguard Worker           if (flags & 4) s.Add_Char('C');
63*f6dc9357SAndroid Build Coastguard Worker           const UInt32 size = (UInt32)(Data.Size()) - 1;
64*f6dc9357SAndroid Build Coastguard Worker           if (size % 4 == 0)
65*f6dc9357SAndroid Build Coastguard Worker           {
66*f6dc9357SAndroid Build Coastguard Worker             s.Add_Colon();
67*f6dc9357SAndroid Build Coastguard Worker             s.Add_UInt32(size / 4);
68*f6dc9357SAndroid Build Coastguard Worker           }
69*f6dc9357SAndroid Build Coastguard Worker         }
70*f6dc9357SAndroid Build Coastguard Worker       }
71*f6dc9357SAndroid Build Coastguard Worker       /*
72*f6dc9357SAndroid Build Coastguard Worker       if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
73*f6dc9357SAndroid Build Coastguard Worker       {
74*f6dc9357SAndroid Build Coastguard Worker         char sz[32];
75*f6dc9357SAndroid Build Coastguard Worker         sz[0] = ':';
76*f6dc9357SAndroid Build Coastguard Worker         ConvertUInt32ToHex(GetUi16(Data), sz + 1);
77*f6dc9357SAndroid Build Coastguard Worker         s += sz;
78*f6dc9357SAndroid Build Coastguard Worker         for (unsigned j = 2; j < Data.Size(); j++)
79*f6dc9357SAndroid Build Coastguard Worker         {
80*f6dc9357SAndroid Build Coastguard Worker           char sz[32];
81*f6dc9357SAndroid Build Coastguard Worker           sz[0] = '-';
82*f6dc9357SAndroid Build Coastguard Worker           ConvertUInt32ToHex(Data[j], sz + 1);
83*f6dc9357SAndroid Build Coastguard Worker           s += sz;
84*f6dc9357SAndroid Build Coastguard Worker         }
85*f6dc9357SAndroid Build Coastguard Worker       }
86*f6dc9357SAndroid Build Coastguard Worker       */
87*f6dc9357SAndroid Build Coastguard Worker       return;
88*f6dc9357SAndroid Build Coastguard Worker     }
89*f6dc9357SAndroid Build Coastguard Worker   }
90*f6dc9357SAndroid Build Coastguard Worker   {
91*f6dc9357SAndroid Build Coastguard Worker     char sz[16];
92*f6dc9357SAndroid Build Coastguard Worker     sz[0] = '0';
93*f6dc9357SAndroid Build Coastguard Worker     sz[1] = 'x';
94*f6dc9357SAndroid Build Coastguard Worker     ConvertUInt32ToHex(ID, sz + 2);
95*f6dc9357SAndroid Build Coastguard Worker     s += sz;
96*f6dc9357SAndroid Build Coastguard Worker   }
97*f6dc9357SAndroid Build Coastguard Worker }
98*f6dc9357SAndroid Build Coastguard Worker 
99*f6dc9357SAndroid Build Coastguard Worker 
PrintInfo(AString & s) const100*f6dc9357SAndroid Build Coastguard Worker void CExtraBlock::PrintInfo(AString &s) const
101*f6dc9357SAndroid Build Coastguard Worker {
102*f6dc9357SAndroid Build Coastguard Worker   if (Error)
103*f6dc9357SAndroid Build Coastguard Worker     s.Add_OptSpaced("Extra_ERROR");
104*f6dc9357SAndroid Build Coastguard Worker 
105*f6dc9357SAndroid Build Coastguard Worker   if (MinorError)
106*f6dc9357SAndroid Build Coastguard Worker     s.Add_OptSpaced("Minor_Extra_ERROR");
107*f6dc9357SAndroid Build Coastguard Worker 
108*f6dc9357SAndroid Build Coastguard Worker   if (IsZip64 || IsZip64_Error)
109*f6dc9357SAndroid Build Coastguard Worker   {
110*f6dc9357SAndroid Build Coastguard Worker     s.Add_OptSpaced("Zip64");
111*f6dc9357SAndroid Build Coastguard Worker     if (IsZip64_Error)
112*f6dc9357SAndroid Build Coastguard Worker       s += "_ERROR";
113*f6dc9357SAndroid Build Coastguard Worker   }
114*f6dc9357SAndroid Build Coastguard Worker 
115*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, SubBlocks)
116*f6dc9357SAndroid Build Coastguard Worker   {
117*f6dc9357SAndroid Build Coastguard Worker     s.Add_Space_if_NotEmpty();
118*f6dc9357SAndroid Build Coastguard Worker     SubBlocks[i].PrintInfo(s);
119*f6dc9357SAndroid Build Coastguard Worker   }
120*f6dc9357SAndroid Build Coastguard Worker }
121*f6dc9357SAndroid Build Coastguard Worker 
122*f6dc9357SAndroid Build Coastguard Worker 
ExtractNtfsTime(unsigned index,FILETIME & ft) const123*f6dc9357SAndroid Build Coastguard Worker bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
124*f6dc9357SAndroid Build Coastguard Worker {
125*f6dc9357SAndroid Build Coastguard Worker   ft.dwHighDateTime = ft.dwLowDateTime = 0;
126*f6dc9357SAndroid Build Coastguard Worker   UInt32 size = (UInt32)Data.Size();
127*f6dc9357SAndroid Build Coastguard Worker   if (ID != NExtraID::kNTFS || size < 32)
128*f6dc9357SAndroid Build Coastguard Worker     return false;
129*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = (const Byte *)Data;
130*f6dc9357SAndroid Build Coastguard Worker   p += 4; // for reserved
131*f6dc9357SAndroid Build Coastguard Worker   size -= 4;
132*f6dc9357SAndroid Build Coastguard Worker   while (size > 4)
133*f6dc9357SAndroid Build Coastguard Worker   {
134*f6dc9357SAndroid Build Coastguard Worker     UInt16 tag = GetUi16(p);
135*f6dc9357SAndroid Build Coastguard Worker     unsigned attrSize = GetUi16(p + 2);
136*f6dc9357SAndroid Build Coastguard Worker     p += 4;
137*f6dc9357SAndroid Build Coastguard Worker     size -= 4;
138*f6dc9357SAndroid Build Coastguard Worker     if (attrSize > size)
139*f6dc9357SAndroid Build Coastguard Worker       attrSize = size;
140*f6dc9357SAndroid Build Coastguard Worker 
141*f6dc9357SAndroid Build Coastguard Worker     if (tag == NNtfsExtra::kTagTime && attrSize >= 24)
142*f6dc9357SAndroid Build Coastguard Worker     {
143*f6dc9357SAndroid Build Coastguard Worker       p += 8 * index;
144*f6dc9357SAndroid Build Coastguard Worker       ft.dwLowDateTime = GetUi32(p);
145*f6dc9357SAndroid Build Coastguard Worker       ft.dwHighDateTime = GetUi32(p + 4);
146*f6dc9357SAndroid Build Coastguard Worker       return true;
147*f6dc9357SAndroid Build Coastguard Worker     }
148*f6dc9357SAndroid Build Coastguard Worker     p += attrSize;
149*f6dc9357SAndroid Build Coastguard Worker     size -= attrSize;
150*f6dc9357SAndroid Build Coastguard Worker   }
151*f6dc9357SAndroid Build Coastguard Worker   return false;
152*f6dc9357SAndroid Build Coastguard Worker }
153*f6dc9357SAndroid Build Coastguard Worker 
Extract_UnixTime(bool isCentral,unsigned index,UInt32 & res) const154*f6dc9357SAndroid Build Coastguard Worker bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const
155*f6dc9357SAndroid Build Coastguard Worker {
156*f6dc9357SAndroid Build Coastguard Worker   /* Info-Zip :
157*f6dc9357SAndroid Build Coastguard Worker      The central-header extra field contains the modification
158*f6dc9357SAndroid Build Coastguard Worker      time only, or no timestamp at all.
159*f6dc9357SAndroid Build Coastguard Worker      Size of Data is used to flag its presence or absence
160*f6dc9357SAndroid Build Coastguard Worker      If "Flags" indicates that Modtime is present in the local header
161*f6dc9357SAndroid Build Coastguard Worker      field, it MUST be present in the central header field, too
162*f6dc9357SAndroid Build Coastguard Worker   */
163*f6dc9357SAndroid Build Coastguard Worker 
164*f6dc9357SAndroid Build Coastguard Worker   res = 0;
165*f6dc9357SAndroid Build Coastguard Worker   UInt32 size = (UInt32)Data.Size();
166*f6dc9357SAndroid Build Coastguard Worker   if (ID != NExtraID::kUnixTime || size < 5)
167*f6dc9357SAndroid Build Coastguard Worker     return false;
168*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = (const Byte *)Data;
169*f6dc9357SAndroid Build Coastguard Worker   const Byte flags = *p++;
170*f6dc9357SAndroid Build Coastguard Worker   size--;
171*f6dc9357SAndroid Build Coastguard Worker   if (isCentral)
172*f6dc9357SAndroid Build Coastguard Worker   {
173*f6dc9357SAndroid Build Coastguard Worker     if (index != NUnixTime::kMTime ||
174*f6dc9357SAndroid Build Coastguard Worker         (flags & (1 << NUnixTime::kMTime)) == 0 ||
175*f6dc9357SAndroid Build Coastguard Worker         size < 4)
176*f6dc9357SAndroid Build Coastguard Worker       return false;
177*f6dc9357SAndroid Build Coastguard Worker     res = GetUi32(p);
178*f6dc9357SAndroid Build Coastguard Worker     return true;
179*f6dc9357SAndroid Build Coastguard Worker   }
180*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < 3; i++)
181*f6dc9357SAndroid Build Coastguard Worker     if ((flags & (1 << i)) != 0)
182*f6dc9357SAndroid Build Coastguard Worker     {
183*f6dc9357SAndroid Build Coastguard Worker       if (size < 4)
184*f6dc9357SAndroid Build Coastguard Worker         return false;
185*f6dc9357SAndroid Build Coastguard Worker       if (index == i)
186*f6dc9357SAndroid Build Coastguard Worker       {
187*f6dc9357SAndroid Build Coastguard Worker         res = GetUi32(p);
188*f6dc9357SAndroid Build Coastguard Worker         return true;
189*f6dc9357SAndroid Build Coastguard Worker       }
190*f6dc9357SAndroid Build Coastguard Worker       p += 4;
191*f6dc9357SAndroid Build Coastguard Worker       size -= 4;
192*f6dc9357SAndroid Build Coastguard Worker     }
193*f6dc9357SAndroid Build Coastguard Worker   return false;
194*f6dc9357SAndroid Build Coastguard Worker }
195*f6dc9357SAndroid Build Coastguard Worker 
196*f6dc9357SAndroid Build Coastguard Worker 
197*f6dc9357SAndroid Build Coastguard Worker // Info-ZIP's abandoned "Unix1 timestamps & owner ID info"
198*f6dc9357SAndroid Build Coastguard Worker 
Extract_Unix01_Time(unsigned index,UInt32 & res) const199*f6dc9357SAndroid Build Coastguard Worker bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const
200*f6dc9357SAndroid Build Coastguard Worker {
201*f6dc9357SAndroid Build Coastguard Worker   res = 0;
202*f6dc9357SAndroid Build Coastguard Worker   const unsigned offset = index * 4;
203*f6dc9357SAndroid Build Coastguard Worker   if (Data.Size() < offset + 4)
204*f6dc9357SAndroid Build Coastguard Worker     return false;
205*f6dc9357SAndroid Build Coastguard Worker   if (ID != NExtraID::kUnix0 &&
206*f6dc9357SAndroid Build Coastguard Worker       ID != NExtraID::kUnix1)
207*f6dc9357SAndroid Build Coastguard Worker     return false;
208*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = (const Byte *)Data + offset;
209*f6dc9357SAndroid Build Coastguard Worker   res = GetUi32(p);
210*f6dc9357SAndroid Build Coastguard Worker   return true;
211*f6dc9357SAndroid Build Coastguard Worker }
212*f6dc9357SAndroid Build Coastguard Worker 
213*f6dc9357SAndroid Build Coastguard Worker /*
214*f6dc9357SAndroid Build Coastguard Worker // PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps"
215*f6dc9357SAndroid Build Coastguard Worker bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const
216*f6dc9357SAndroid Build Coastguard Worker {
217*f6dc9357SAndroid Build Coastguard Worker   res = 0;
218*f6dc9357SAndroid Build Coastguard Worker   const unsigned offset = index * 4;
219*f6dc9357SAndroid Build Coastguard Worker   if (ID != NExtraID::kUnix0 || Data.Size() < offset)
220*f6dc9357SAndroid Build Coastguard Worker     return false;
221*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = (const Byte *)Data + offset;
222*f6dc9357SAndroid Build Coastguard Worker   res = GetUi32(p);
223*f6dc9357SAndroid Build Coastguard Worker   return true;
224*f6dc9357SAndroid Build Coastguard Worker }
225*f6dc9357SAndroid Build Coastguard Worker */
226*f6dc9357SAndroid Build Coastguard Worker 
GetNtfsTime(unsigned index,FILETIME & ft) const227*f6dc9357SAndroid Build Coastguard Worker bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
228*f6dc9357SAndroid Build Coastguard Worker {
229*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, SubBlocks)
230*f6dc9357SAndroid Build Coastguard Worker   {
231*f6dc9357SAndroid Build Coastguard Worker     const CExtraSubBlock &sb = SubBlocks[i];
232*f6dc9357SAndroid Build Coastguard Worker     if (sb.ID == NFileHeader::NExtraID::kNTFS)
233*f6dc9357SAndroid Build Coastguard Worker       return sb.ExtractNtfsTime(index, ft);
234*f6dc9357SAndroid Build Coastguard Worker   }
235*f6dc9357SAndroid Build Coastguard Worker   return false;
236*f6dc9357SAndroid Build Coastguard Worker }
237*f6dc9357SAndroid Build Coastguard Worker 
GetUnixTime(bool isCentral,unsigned index,UInt32 & res) const238*f6dc9357SAndroid Build Coastguard Worker bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
239*f6dc9357SAndroid Build Coastguard Worker {
240*f6dc9357SAndroid Build Coastguard Worker   {
241*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, SubBlocks)
242*f6dc9357SAndroid Build Coastguard Worker     {
243*f6dc9357SAndroid Build Coastguard Worker       const CExtraSubBlock &sb = SubBlocks[i];
244*f6dc9357SAndroid Build Coastguard Worker       if (sb.ID == NFileHeader::NExtraID::kUnixTime)
245*f6dc9357SAndroid Build Coastguard Worker         return sb.Extract_UnixTime(isCentral, index, res);
246*f6dc9357SAndroid Build Coastguard Worker     }
247*f6dc9357SAndroid Build Coastguard Worker   }
248*f6dc9357SAndroid Build Coastguard Worker 
249*f6dc9357SAndroid Build Coastguard Worker   switch (index)
250*f6dc9357SAndroid Build Coastguard Worker   {
251*f6dc9357SAndroid Build Coastguard Worker     case NUnixTime::kMTime: index = NUnixExtra::kMTime; break;
252*f6dc9357SAndroid Build Coastguard Worker     case NUnixTime::kATime: index = NUnixExtra::kATime; break;
253*f6dc9357SAndroid Build Coastguard Worker     default: return false;
254*f6dc9357SAndroid Build Coastguard Worker   }
255*f6dc9357SAndroid Build Coastguard Worker 
256*f6dc9357SAndroid Build Coastguard Worker   {
257*f6dc9357SAndroid Build Coastguard Worker     FOR_VECTOR (i, SubBlocks)
258*f6dc9357SAndroid Build Coastguard Worker     {
259*f6dc9357SAndroid Build Coastguard Worker       const CExtraSubBlock &sb = SubBlocks[i];
260*f6dc9357SAndroid Build Coastguard Worker       if (sb.ID == NFileHeader::NExtraID::kUnix0 ||
261*f6dc9357SAndroid Build Coastguard Worker           sb.ID == NFileHeader::NExtraID::kUnix1)
262*f6dc9357SAndroid Build Coastguard Worker         return sb.Extract_Unix01_Time(index, res);
263*f6dc9357SAndroid Build Coastguard Worker     }
264*f6dc9357SAndroid Build Coastguard Worker   }
265*f6dc9357SAndroid Build Coastguard Worker   return false;
266*f6dc9357SAndroid Build Coastguard Worker }
267*f6dc9357SAndroid Build Coastguard Worker 
268*f6dc9357SAndroid Build Coastguard Worker 
IsDir() const269*f6dc9357SAndroid Build Coastguard Worker bool CLocalItem::IsDir() const
270*f6dc9357SAndroid Build Coastguard Worker {
271*f6dc9357SAndroid Build Coastguard Worker   return NItemName::HasTailSlash(Name, GetCodePage());
272*f6dc9357SAndroid Build Coastguard Worker }
273*f6dc9357SAndroid Build Coastguard Worker 
IsDir() const274*f6dc9357SAndroid Build Coastguard Worker bool CItem::IsDir() const
275*f6dc9357SAndroid Build Coastguard Worker {
276*f6dc9357SAndroid Build Coastguard Worker   // FIXME: we can check InfoZip UTF-8 name at first.
277*f6dc9357SAndroid Build Coastguard Worker   if (NItemName::HasTailSlash(Name, GetCodePage()))
278*f6dc9357SAndroid Build Coastguard Worker     return true;
279*f6dc9357SAndroid Build Coastguard Worker 
280*f6dc9357SAndroid Build Coastguard Worker   Byte hostOS = GetHostOS();
281*f6dc9357SAndroid Build Coastguard Worker 
282*f6dc9357SAndroid Build Coastguard Worker   if (Size == 0 && PackSize == 0 && !Name.IsEmpty() && Name.Back() == '\\')
283*f6dc9357SAndroid Build Coastguard Worker   {
284*f6dc9357SAndroid Build Coastguard Worker     // do we need to use CharPrevExA?
285*f6dc9357SAndroid Build Coastguard Worker     // .NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers?
286*f6dc9357SAndroid Build Coastguard Worker     // so we support that case
287*f6dc9357SAndroid Build Coastguard Worker     switch (hostOS)
288*f6dc9357SAndroid Build Coastguard Worker     {
289*f6dc9357SAndroid Build Coastguard Worker       case NHostOS::kFAT:
290*f6dc9357SAndroid Build Coastguard Worker       case NHostOS::kNTFS:
291*f6dc9357SAndroid Build Coastguard Worker       case NHostOS::kHPFS:
292*f6dc9357SAndroid Build Coastguard Worker       case NHostOS::kVFAT:
293*f6dc9357SAndroid Build Coastguard Worker         return true;
294*f6dc9357SAndroid Build Coastguard Worker       default: break;
295*f6dc9357SAndroid Build Coastguard Worker     }
296*f6dc9357SAndroid Build Coastguard Worker   }
297*f6dc9357SAndroid Build Coastguard Worker 
298*f6dc9357SAndroid Build Coastguard Worker   if (!FromCentral)
299*f6dc9357SAndroid Build Coastguard Worker     return false;
300*f6dc9357SAndroid Build Coastguard Worker 
301*f6dc9357SAndroid Build Coastguard Worker   UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF);
302*f6dc9357SAndroid Build Coastguard Worker 
303*f6dc9357SAndroid Build Coastguard Worker   switch (hostOS)
304*f6dc9357SAndroid Build Coastguard Worker   {
305*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kAMIGA:
306*f6dc9357SAndroid Build Coastguard Worker       switch (highAttrib & NAmigaAttrib::kIFMT)
307*f6dc9357SAndroid Build Coastguard Worker       {
308*f6dc9357SAndroid Build Coastguard Worker         case NAmigaAttrib::kIFDIR: return true;
309*f6dc9357SAndroid Build Coastguard Worker         case NAmigaAttrib::kIFREG: return false;
310*f6dc9357SAndroid Build Coastguard Worker         default: return false; // change it throw kUnknownAttributes;
311*f6dc9357SAndroid Build Coastguard Worker       }
312*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kFAT:
313*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kNTFS:
314*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kHPFS:
315*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kVFAT:
316*f6dc9357SAndroid Build Coastguard Worker       return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
317*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kAtari:
318*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kMac:
319*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kVMS:
320*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kVM_CMS:
321*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kAcorn:
322*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kMVS:
323*f6dc9357SAndroid Build Coastguard Worker       return false; // change it throw kUnknownAttributes;
324*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kUnix:
325*f6dc9357SAndroid Build Coastguard Worker       return MY_LIN_S_ISDIR(highAttrib);
326*f6dc9357SAndroid Build Coastguard Worker     default:
327*f6dc9357SAndroid Build Coastguard Worker       return false;
328*f6dc9357SAndroid Build Coastguard Worker   }
329*f6dc9357SAndroid Build Coastguard Worker }
330*f6dc9357SAndroid Build Coastguard Worker 
GetWinAttrib() const331*f6dc9357SAndroid Build Coastguard Worker UInt32 CItem::GetWinAttrib() const
332*f6dc9357SAndroid Build Coastguard Worker {
333*f6dc9357SAndroid Build Coastguard Worker   UInt32 winAttrib = 0;
334*f6dc9357SAndroid Build Coastguard Worker   switch (GetHostOS())
335*f6dc9357SAndroid Build Coastguard Worker   {
336*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kFAT:
337*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kNTFS:
338*f6dc9357SAndroid Build Coastguard Worker       if (FromCentral)
339*f6dc9357SAndroid Build Coastguard Worker         winAttrib = ExternalAttrib;
340*f6dc9357SAndroid Build Coastguard Worker       break;
341*f6dc9357SAndroid Build Coastguard Worker     case NHostOS::kUnix:
342*f6dc9357SAndroid Build Coastguard Worker       // do we need to clear 16 low bits in this case?
343*f6dc9357SAndroid Build Coastguard Worker       if (FromCentral)
344*f6dc9357SAndroid Build Coastguard Worker       {
345*f6dc9357SAndroid Build Coastguard Worker         /*
346*f6dc9357SAndroid Build Coastguard Worker           Some programs write posix attributes in high 16 bits of ExternalAttrib
347*f6dc9357SAndroid Build Coastguard Worker           Also some programs can write additional marker flag:
348*f6dc9357SAndroid Build Coastguard Worker             0x8000 - p7zip
349*f6dc9357SAndroid Build Coastguard Worker             0x4000 - Zip in MacOS
350*f6dc9357SAndroid Build Coastguard Worker             no marker - Info-Zip
351*f6dc9357SAndroid Build Coastguard Worker 
352*f6dc9357SAndroid Build Coastguard Worker           Client code has two options to detect posix field:
353*f6dc9357SAndroid Build Coastguard Worker             1) check 0x8000 marker. In that case we must add 0x8000 marker here.
354*f6dc9357SAndroid Build Coastguard Worker             2) check that high 4 bits (file type bits in posix field) of attributes are not zero.
355*f6dc9357SAndroid Build Coastguard Worker         */
356*f6dc9357SAndroid Build Coastguard Worker 
357*f6dc9357SAndroid Build Coastguard Worker         winAttrib = ExternalAttrib & 0xFFFF0000;
358*f6dc9357SAndroid Build Coastguard Worker 
359*f6dc9357SAndroid Build Coastguard Worker         // #ifndef _WIN32
360*f6dc9357SAndroid Build Coastguard Worker         winAttrib |= 0x8000; // add posix mode marker
361*f6dc9357SAndroid Build Coastguard Worker         // #endif
362*f6dc9357SAndroid Build Coastguard Worker       }
363*f6dc9357SAndroid Build Coastguard Worker       break;
364*f6dc9357SAndroid Build Coastguard Worker     default: break;
365*f6dc9357SAndroid Build Coastguard Worker   }
366*f6dc9357SAndroid Build Coastguard Worker   if (IsDir()) // test it;
367*f6dc9357SAndroid Build Coastguard Worker     winAttrib |= FILE_ATTRIBUTE_DIRECTORY;
368*f6dc9357SAndroid Build Coastguard Worker   return winAttrib;
369*f6dc9357SAndroid Build Coastguard Worker }
370*f6dc9357SAndroid Build Coastguard Worker 
GetPosixAttrib(UInt32 & attrib) const371*f6dc9357SAndroid Build Coastguard Worker bool CItem::GetPosixAttrib(UInt32 &attrib) const
372*f6dc9357SAndroid Build Coastguard Worker {
373*f6dc9357SAndroid Build Coastguard Worker   // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT.
374*f6dc9357SAndroid Build Coastguard Worker   if (FromCentral && GetHostOS() == NHostOS::kUnix)
375*f6dc9357SAndroid Build Coastguard Worker   {
376*f6dc9357SAndroid Build Coastguard Worker     attrib = ExternalAttrib >> 16;
377*f6dc9357SAndroid Build Coastguard Worker     return (attrib != 0);
378*f6dc9357SAndroid Build Coastguard Worker   }
379*f6dc9357SAndroid Build Coastguard Worker   attrib = 0;
380*f6dc9357SAndroid Build Coastguard Worker   if (IsDir())
381*f6dc9357SAndroid Build Coastguard Worker     attrib = MY_LIN_S_IFDIR;
382*f6dc9357SAndroid Build Coastguard Worker   return false;
383*f6dc9357SAndroid Build Coastguard Worker }
384*f6dc9357SAndroid Build Coastguard Worker 
385*f6dc9357SAndroid Build Coastguard Worker 
CheckIzUnicode(const AString & s) const386*f6dc9357SAndroid Build Coastguard Worker bool CExtraSubBlock::CheckIzUnicode(const AString &s) const
387*f6dc9357SAndroid Build Coastguard Worker {
388*f6dc9357SAndroid Build Coastguard Worker   size_t size = Data.Size();
389*f6dc9357SAndroid Build Coastguard Worker   if (size < 1 + 4)
390*f6dc9357SAndroid Build Coastguard Worker     return false;
391*f6dc9357SAndroid Build Coastguard Worker   const Byte *p = (const Byte *)Data;
392*f6dc9357SAndroid Build Coastguard Worker   if (p[0] > 1)
393*f6dc9357SAndroid Build Coastguard Worker     return false;
394*f6dc9357SAndroid Build Coastguard Worker   if (CrcCalc(s, s.Len()) != GetUi32(p + 1))
395*f6dc9357SAndroid Build Coastguard Worker     return false;
396*f6dc9357SAndroid Build Coastguard Worker   size -= 5;
397*f6dc9357SAndroid Build Coastguard Worker   p += 5;
398*f6dc9357SAndroid Build Coastguard Worker   for (size_t i = 0; i < size; i++)
399*f6dc9357SAndroid Build Coastguard Worker     if (p[i] == 0)
400*f6dc9357SAndroid Build Coastguard Worker       return false;
401*f6dc9357SAndroid Build Coastguard Worker   return Check_UTF8_Buf((const char *)(const void *)p, size, false);
402*f6dc9357SAndroid Build Coastguard Worker }
403*f6dc9357SAndroid Build Coastguard Worker 
404*f6dc9357SAndroid Build Coastguard Worker 
GetUnicodeString(UString & res,const AString & s,bool isComment,bool useSpecifiedCodePage,UINT codePage) const405*f6dc9357SAndroid Build Coastguard Worker void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const
406*f6dc9357SAndroid Build Coastguard Worker {
407*f6dc9357SAndroid Build Coastguard Worker   bool isUtf8 = IsUtf8();
408*f6dc9357SAndroid Build Coastguard Worker   // bool ignore_Utf8_Errors = true;
409*f6dc9357SAndroid Build Coastguard Worker 
410*f6dc9357SAndroid Build Coastguard Worker   if (!isUtf8)
411*f6dc9357SAndroid Build Coastguard Worker   {
412*f6dc9357SAndroid Build Coastguard Worker     {
413*f6dc9357SAndroid Build Coastguard Worker       const unsigned id = isComment ?
414*f6dc9357SAndroid Build Coastguard Worker           NFileHeader::NExtraID::kIzUnicodeComment:
415*f6dc9357SAndroid Build Coastguard Worker           NFileHeader::NExtraID::kIzUnicodeName;
416*f6dc9357SAndroid Build Coastguard Worker       const CObjectVector<CExtraSubBlock> &subBlocks = GetMainExtra().SubBlocks;
417*f6dc9357SAndroid Build Coastguard Worker 
418*f6dc9357SAndroid Build Coastguard Worker       FOR_VECTOR (i, subBlocks)
419*f6dc9357SAndroid Build Coastguard Worker       {
420*f6dc9357SAndroid Build Coastguard Worker         const CExtraSubBlock &sb = subBlocks[i];
421*f6dc9357SAndroid Build Coastguard Worker         if (sb.ID == id)
422*f6dc9357SAndroid Build Coastguard Worker         {
423*f6dc9357SAndroid Build Coastguard Worker           if (sb.CheckIzUnicode(s))
424*f6dc9357SAndroid Build Coastguard Worker           {
425*f6dc9357SAndroid Build Coastguard Worker             // const unsigned kIzUnicodeHeaderSize = 5;
426*f6dc9357SAndroid Build Coastguard Worker             if (Convert_UTF8_Buf_To_Unicode(
427*f6dc9357SAndroid Build Coastguard Worker                 (const char *)(const void *)(const Byte *)sb.Data + 5,
428*f6dc9357SAndroid Build Coastguard Worker                 sb.Data.Size() - 5, res))
429*f6dc9357SAndroid Build Coastguard Worker               return;
430*f6dc9357SAndroid Build Coastguard Worker           }
431*f6dc9357SAndroid Build Coastguard Worker           break;
432*f6dc9357SAndroid Build Coastguard Worker         }
433*f6dc9357SAndroid Build Coastguard Worker       }
434*f6dc9357SAndroid Build Coastguard Worker     }
435*f6dc9357SAndroid Build Coastguard Worker 
436*f6dc9357SAndroid Build Coastguard Worker     if (useSpecifiedCodePage)
437*f6dc9357SAndroid Build Coastguard Worker       isUtf8 = (codePage == CP_UTF8);
438*f6dc9357SAndroid Build Coastguard Worker     #ifdef _WIN32
439*f6dc9357SAndroid Build Coastguard Worker     else if (GetHostOS() == NFileHeader::NHostOS::kUnix)
440*f6dc9357SAndroid Build Coastguard Worker     {
441*f6dc9357SAndroid Build Coastguard Worker       /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header.
442*f6dc9357SAndroid Build Coastguard Worker          We try to get name as UTF-8.
443*f6dc9357SAndroid Build Coastguard Worker          Do we need to do it in POSIX version also? */
444*f6dc9357SAndroid Build Coastguard Worker       isUtf8 = true;
445*f6dc9357SAndroid Build Coastguard Worker 
446*f6dc9357SAndroid Build Coastguard Worker       /* 21.02: we want to ignore UTF-8 errors to support file paths that are mixed
447*f6dc9357SAndroid Build Coastguard Worker           of UTF-8 and non-UTF-8 characters. */
448*f6dc9357SAndroid Build Coastguard Worker       // ignore_Utf8_Errors = false;
449*f6dc9357SAndroid Build Coastguard Worker       // ignore_Utf8_Errors = true;
450*f6dc9357SAndroid Build Coastguard Worker     }
451*f6dc9357SAndroid Build Coastguard Worker     #endif
452*f6dc9357SAndroid Build Coastguard Worker   }
453*f6dc9357SAndroid Build Coastguard Worker 
454*f6dc9357SAndroid Build Coastguard Worker 
455*f6dc9357SAndroid Build Coastguard Worker   if (isUtf8)
456*f6dc9357SAndroid Build Coastguard Worker   {
457*f6dc9357SAndroid Build Coastguard Worker     ConvertUTF8ToUnicode(s, res);
458*f6dc9357SAndroid Build Coastguard Worker     return;
459*f6dc9357SAndroid Build Coastguard Worker   }
460*f6dc9357SAndroid Build Coastguard Worker 
461*f6dc9357SAndroid Build Coastguard Worker   MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage());
462*f6dc9357SAndroid Build Coastguard Worker }
463*f6dc9357SAndroid Build Coastguard Worker 
464*f6dc9357SAndroid Build Coastguard Worker }}
465