xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Zip/ZipItem.h (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Archive/ZipItem.h
2 
3 #ifndef ZIP7_INC_ARCHIVE_ZIP_ITEM_H
4 #define ZIP7_INC_ARCHIVE_ZIP_ITEM_H
5 
6 #include "../../../../C/CpuArch.h"
7 
8 #include "../../../Common/MyBuffer.h"
9 #include "../../../Common/MyString.h"
10 #include "../../../Common/UTFConvert.h"
11 
12 #include "ZipHeader.h"
13 
14 namespace NArchive {
15 namespace NZip {
16 
17 /*
18 extern const char *k_SpecName_NTFS_STREAM;
19 extern const char *k_SpecName_MAC_RESOURCE_FORK;
20 */
21 
22 struct CVersion
23 {
24   Byte Version;
25   Byte HostOS;
26 };
27 
28 struct CExtraSubBlock
29 {
30   UInt32 ID;
31   CByteBuffer Data;
32 
33   bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
34   bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const;
35   bool Extract_Unix01_Time(unsigned index, UInt32 &res) const;
36   // bool Extract_Unix_Time(unsigned index, UInt32 &res) const;
37 
38   bool CheckIzUnicode(const AString &s) const;
39 
40   void PrintInfo(AString &s) const;
41 };
42 
43 const unsigned k_WzAesExtra_Size = 7;
44 
45 struct CWzAesExtra
46 {
47   UInt16 VendorVersion; // 1: AE-1, 2: AE-2,
48   // UInt16 VendorId; // 'A' 'E'
49   Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit
50   UInt16 Method;
51 
CWzAesExtraCWzAesExtra52   CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {}
53 
NeedCrcCWzAesExtra54   bool NeedCrc() const { return (VendorVersion == 1); }
55 
ParseFromSubBlockCWzAesExtra56   bool ParseFromSubBlock(const CExtraSubBlock &sb)
57   {
58     if (sb.ID != NFileHeader::NExtraID::kWzAES)
59       return false;
60     if (sb.Data.Size() < k_WzAesExtra_Size)
61       return false;
62     const Byte *p = (const Byte *)sb.Data;
63     VendorVersion = GetUi16(p);
64     if (p[2] != 'A' || p[3] != 'E')
65       return false;
66     Strength = p[4];
67     // 9.31: The BUG was fixed:
68     Method = GetUi16(p + 5);
69     return true;
70   }
71 
SetSubBlockCWzAesExtra72   void SetSubBlock(CExtraSubBlock &sb) const
73   {
74     sb.Data.Alloc(k_WzAesExtra_Size);
75     sb.ID = NFileHeader::NExtraID::kWzAES;
76     Byte *p = (Byte *)sb.Data;
77     p[0] = (Byte)VendorVersion;
78     p[1] = (Byte)(VendorVersion >> 8);
79     p[2] = 'A';
80     p[3] = 'E';
81     p[4] = Strength;
82     p[5] = (Byte)Method;
83     p[6] = (Byte)(Method >> 8);
84   }
85 };
86 
87 namespace NStrongCrypto_AlgId
88 {
89   const UInt16 kDES = 0x6601;
90   const UInt16 kRC2old = 0x6602;
91   const UInt16 k3DES168 = 0x6603;
92   const UInt16 k3DES112 = 0x6609;
93   const UInt16 kAES128 = 0x660E;
94   const UInt16 kAES192 = 0x660F;
95   const UInt16 kAES256 = 0x6610;
96   const UInt16 kRC2 = 0x6702;
97   const UInt16 kBlowfish = 0x6720;
98   const UInt16 kTwofish = 0x6721;
99   const UInt16 kRC4 = 0x6801;
100 }
101 
102 struct CStrongCryptoExtra
103 {
104   UInt16 Format;
105   UInt16 AlgId;
106   UInt16 BitLen;
107   UInt16 Flags;
108 
ParseFromSubBlockCStrongCryptoExtra109   bool ParseFromSubBlock(const CExtraSubBlock &sb)
110   {
111     if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt)
112       return false;
113     const Byte *p = (const Byte *)sb.Data;
114     if (sb.Data.Size() < 8)
115       return false;
116     Format = GetUi16(p + 0);
117     AlgId  = GetUi16(p + 2);
118     BitLen = GetUi16(p + 4);
119     Flags  = GetUi16(p + 6);
120     return (Format == 2);
121   }
122 
CertificateIsUsedCStrongCryptoExtra123   bool CertificateIsUsed() const { return (Flags > 0x0001); }
124 };
125 
126 
127 struct CExtraBlock
128 {
129   CObjectVector<CExtraSubBlock> SubBlocks;
130   bool Error;
131   bool MinorError;
132   bool IsZip64;
133   bool IsZip64_Error;
134 
CExtraBlockCExtraBlock135   CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {}
136 
ClearCExtraBlock137   void Clear()
138   {
139     SubBlocks.Clear();
140     IsZip64 = false;
141   }
142 
GetSizeCExtraBlock143   size_t GetSize() const
144   {
145     size_t res = 0;
146     FOR_VECTOR (i, SubBlocks)
147       res += SubBlocks[i].Data.Size() + 2 + 2;
148     return res;
149   }
150 
GetWzAesCExtraBlock151   bool GetWzAes(CWzAesExtra &e) const
152   {
153     FOR_VECTOR (i, SubBlocks)
154       if (e.ParseFromSubBlock(SubBlocks[i]))
155         return true;
156     return false;
157   }
158 
HasWzAesCExtraBlock159   bool HasWzAes() const
160   {
161     CWzAesExtra e;
162     return GetWzAes(e);
163   }
164 
GetStrongCryptoCExtraBlock165   bool GetStrongCrypto(CStrongCryptoExtra &e) const
166   {
167     FOR_VECTOR (i, SubBlocks)
168       if (e.ParseFromSubBlock(SubBlocks[i]))
169         return true;
170     return false;
171   }
172 
173   /*
174   bool HasStrongCrypto() const
175   {
176     CStrongCryptoExtra e;
177     return GetStrongCrypto(e);
178   }
179   */
180 
181   bool GetNtfsTime(unsigned index, FILETIME &ft) const;
182   bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
183 
184   void PrintInfo(AString &s) const;
185 
RemoveUnknownSubBlocksCExtraBlock186   void RemoveUnknownSubBlocks()
187   {
188     for (unsigned i = SubBlocks.Size(); i != 0;)
189     {
190       i--;
191       switch (SubBlocks[i].ID)
192       {
193         case NFileHeader::NExtraID::kStrongEncrypt:
194         case NFileHeader::NExtraID::kWzAES:
195           break;
196         default:
197           SubBlocks.Delete(i);
198       }
199     }
200   }
201 };
202 
203 
204 class CLocalItem
205 {
206 public:
207   UInt16 Flags;
208   UInt16 Method;
209 
210   /*
211     Zip specification doesn't mention that ExtractVersion field uses HostOS subfield.
212     18.06: 7-Zip now doesn't use ExtractVersion::HostOS to detect codePage
213   */
214 
215   CVersion ExtractVersion;
216 
217   UInt64 Size;
218   UInt64 PackSize;
219   UInt32 Time;
220   UInt32 Crc;
221 
222   UInt32 Disk;
223 
224   AString Name;
225 
226   CExtraBlock LocalExtra;
227 
GetDescriptorSize()228   unsigned GetDescriptorSize() const { return LocalExtra.IsZip64 ? kDataDescriptorSize64 : kDataDescriptorSize32; }
229 
GetPackSizeWithDescriptor()230   UInt64 GetPackSizeWithDescriptor() const
231     { return PackSize + (HasDescriptor() ? GetDescriptorSize() : 0); }
232 
IsUtf8()233   bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; }
IsEncrypted()234   bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; }
IsStrongEncrypted()235   bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; }
IsAesEncrypted()236   bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); }
IsLzmaEOS()237   bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; }
HasDescriptor()238   bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
239   // bool IsAltStream() const { return (Flags & NFileHeader::NFlags::kAltStream) != 0; }
240 
GetDeflateLevel()241   unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; }
242 
243   bool IsDir() const;
244 
245   /*
246   void GetUnicodeString(const AString &s, UString &res) const
247   {
248     bool isUtf8 = IsUtf8();
249     if (isUtf8)
250       if (ConvertUTF8ToUnicode(s, res))
251         return;
252     MultiByteToUnicodeString2(res, s, GetCodePage());
253   }
254   */
255 
256 private:
257 
SetFlag(unsigned bitMask,bool enable)258   void SetFlag(unsigned bitMask, bool enable)
259   {
260     if (enable)
261       Flags = (UInt16)(Flags | bitMask);
262     else
263       Flags = (UInt16)(Flags & ~bitMask);
264   }
265 
266 public:
267 
ClearFlags()268   void ClearFlags() { Flags = 0; }
SetEncrypted(bool encrypted)269   void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); }
SetUtf8(bool isUtf8)270   void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); }
271   // void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); }
SetDescriptorMode(bool useDescriptor)272   void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); }
273 
GetCodePage()274   UINT GetCodePage() const
275   {
276     if (IsUtf8())
277       return CP_UTF8;
278     return CP_OEMCP;
279   }
280 };
281 
282 
283 class CItem: public CLocalItem
284 {
285 public:
286   CVersion MadeByVersion;
287   UInt16 InternalAttrib;
288   UInt32 ExternalAttrib;
289 
290   UInt64 LocalHeaderPos;
291 
292   CExtraBlock CentralExtra;
293   CByteBuffer Comment;
294 
295   bool FromLocal;
296   bool FromCentral;
297 
298   // CItem can be used as CLocalItem. So we must clear unused fields
CItem()299   CItem():
300       InternalAttrib(0),
301       ExternalAttrib(0),
302       FromLocal(false),
303       FromCentral(false)
304   {
305     MadeByVersion.Version = 0;
306     MadeByVersion.HostOS = 0;
307   }
308 
GetMainExtra()309   const CExtraBlock &GetMainExtra() const { return *(FromCentral ? &CentralExtra : &LocalExtra); }
310 
311   bool IsDir() const;
312   UInt32 GetWinAttrib() const;
313   bool GetPosixAttrib(UInt32 &attrib) const;
314 
315   // 18.06: 0 instead of ExtractVersion.HostOS for local item
GetHostOS()316   Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : (Byte)0; }
317 
318   void GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const;
319 
IsThereCrc()320   bool IsThereCrc() const
321   {
322     if (Method == NFileHeader::NCompressionMethod::kWzAES)
323     {
324       CWzAesExtra aesField;
325       if (GetMainExtra().GetWzAes(aesField))
326         return aesField.NeedCrc();
327     }
328     return (Crc != 0 || !IsDir());
329   }
330 
Is_MadeBy_Unix()331   bool Is_MadeBy_Unix() const
332   {
333     if (!FromCentral)
334       return false;
335     return (MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix);
336   }
337 
GetCodePage()338   UINT GetCodePage() const
339   {
340     // 18.06: now we use HostOS only from Central::MadeByVersion
341     if (IsUtf8())
342       return CP_UTF8;
343     if (!FromCentral)
344       return CP_OEMCP;
345     Byte hostOS = MadeByVersion.HostOS;
346     return (UINT)((
347            hostOS == NFileHeader::NHostOS::kFAT
348         || hostOS == NFileHeader::NHostOS::kNTFS
349         || hostOS == NFileHeader::NHostOS::kUnix // do we need it?
350         ) ? CP_OEMCP : CP_ACP);
351   }
352 };
353 
354 }}
355 
356 #endif
357