xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/Rar/Rar5Handler.h (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Rar5Handler.h
2 
3 #ifndef ZIP7_INC_RAR5_HANDLER_H
4 #define ZIP7_INC_RAR5_HANDLER_H
5 
6 #include "../../../../C/Blake2.h"
7 
8 #include "../../../Common/MyBuffer.h"
9 
10 #include "../../../Windows/PropVariant.h"
11 
12 #include "../../Common/CreateCoder.h"
13 
14 #include "../IArchive.h"
15 
16 namespace NArchive {
17 namespace NRar5 {
18 
19 namespace NHeaderFlags
20 {
21   const unsigned kExtra   = 1 << 0;
22   const unsigned kData    = 1 << 1;
23   // const unsigned kUnknown = 1 << 2;
24   const unsigned kPrevVol = 1 << 3;
25   const unsigned kNextVol = 1 << 4;
26   // const unsigned kIsChild = 1 << 5;
27   // const unsigned kPreserveChild = 1 << 6;
28 }
29 
30 namespace NHeaderType
31 {
32   enum
33   {
34     kArc = 1,
35     kFile,
36     kService,
37     kArcEncrypt,
38     kEndOfArc
39   };
40 }
41 
42 namespace NArcFlags
43 {
44   const unsigned kVol       = 1 << 0;
45   const unsigned kVolNumber = 1 << 1;
46   const unsigned kSolid     = 1 << 2;
47   // const unsigned kRecovery  = 1 << 3;
48   // const unsigned kLocked    = 1 << 4;
49 }
50 
51 const unsigned kArcExtraRecordType_Locator  = 1;
52 const unsigned kArcExtraRecordType_Metadata = 2;
53 
54 namespace NLocatorFlags
55 {
56   const unsigned kQuickOpen  = 1 << 0;
57   const unsigned kRecovery   = 1 << 1;
58 }
59 
60 namespace NMetadataFlags
61 {
62   const unsigned kArcName   = 1 << 0;
63   const unsigned kCTime     = 1 << 1;
64   const unsigned kUnixTime  = 1 << 2;
65   const unsigned kNanoSec   = 1 << 3;
66 }
67 
68 namespace NFileFlags
69 {
70   const unsigned kIsDir    = 1 << 0;
71   const unsigned kUnixTime = 1 << 1;
72   const unsigned kCrc32    = 1 << 2;
73   const unsigned kUnknownSize = 1 << 3;
74 }
75 
76 namespace NMethodFlags
77 {
78   // const unsigned kVersionMask = 0x3F;
79   const unsigned kSolid = 1 << 6;
80   const unsigned kRar5_Compat = 1u << 20;
81 }
82 
83 namespace NArcEndFlags
84 {
85   const unsigned kMoreVols = 1 << 0;
86 }
87 
88 enum EHostOS
89 {
90   kHost_Windows = 0,
91   kHost_Unix
92 };
93 
94 
95 
96 // ---------- Extra ----------
97 
98 namespace NExtraID
99 {
100   enum
101   {
102     kCrypto = 1,
103     kHash,
104     kTime,
105     kVersion,
106     kLink,
107     kUnixOwner,
108     kSubdata
109   };
110 }
111 
112 const unsigned kCryptoAlgo_AES = 0;
113 
114 namespace NCryptoFlags
115 {
116   const unsigned kPswCheck = 1 << 0;
117   const unsigned kUseMAC   = 1 << 1;
118 }
119 
120 struct CCryptoInfo
121 {
122   UInt64 Algo;
123   UInt64 Flags;
124   Byte Cnt;
125 
UseMACCCryptoInfo126   bool UseMAC()       const { return (Flags & NCryptoFlags::kUseMAC) != 0; }
IsThereCheckCCryptoInfo127   bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; }
128   bool Parse(const Byte *p, size_t size);
129 };
130 
131 const unsigned kHashID_Blake2sp = 0;
132 
133 namespace NTimeRecord
134 {
135   enum
136   {
137     k_Index_MTime = 0,
138     k_Index_CTime,
139     k_Index_ATime
140   };
141 
142   namespace NFlags
143   {
144     const unsigned kUnixTime = 1 << 0;
145     const unsigned kMTime    = 1 << 1;
146     const unsigned kCTime    = 1 << 2;
147     const unsigned kATime    = 1 << 3;
148     const unsigned kUnixNs   = 1 << 4;
149   }
150 }
151 
152 namespace NLinkType
153 {
154   enum
155   {
156     kUnixSymLink = 1,
157     kWinSymLink,
158     kWinJunction,
159     kHardLink,
160     kFileCopy
161   };
162 }
163 
164 namespace NLinkFlags
165 {
166   const unsigned kTargetIsDir = 1 << 0;
167 }
168 
169 
170 struct CLinkInfo
171 {
172   UInt64 Type;
173   UInt64 Flags;
174   unsigned NameOffset;
175   unsigned NameLen;
176 
177   bool Parse(const Byte *p, unsigned size);
178 };
179 
180 
181 struct CItem
182 {
183   UInt32 CommonFlags;
184   UInt32 Flags;
185 
186   Byte RecordType;
187   bool Version_Defined;
188 
189   int ACL;
190 
191   AString Name;
192 
193   unsigned VolIndex;
194   int NextItem;        // in _items{}
195 
196   UInt32 UnixMTime;
197   UInt32 CRC;
198   UInt32 Attrib;
199   UInt32 Method;
200 
201   CByteBuffer Extra;
202 
203   UInt64 Size;
204   UInt64 PackSize;
205   UInt64 HostOS;
206 
207   UInt64 DataPos;
208   UInt64 Version;
209 
CItemCItem210   CItem() { Clear(); }
211 
ClearCItem212   void Clear()
213   {
214     // CommonFlags = 0;
215     // Flags = 0;
216 
217     // UnixMTime = 0;
218     // CRC = 0;
219 
220     VolIndex = 0;
221     NextItem = -1;
222 
223     Version_Defined = false;
224     Version = 0;
225 
226     Name.Empty();
227     Extra.Free();
228     ACL = -1;
229   }
230 
IsSplitBeforeCItem231   bool IsSplitBefore()  const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; }
IsSplitAfterCItem232   bool IsSplitAfter()   const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; }
IsSplitCItem233   bool IsSplit()        const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; }
234 
IsDirCItem235   bool IsDir()          const { return (Flags & NFileFlags::kIsDir) != 0; }
Has_UnixMTimeCItem236   bool Has_UnixMTime()  const { return (Flags & NFileFlags::kUnixTime) != 0; }
Has_CRCCItem237   bool Has_CRC()        const { return (Flags & NFileFlags::kCrc32) != 0; }
Is_UnknownSizeCItem238   bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; }
239 
IsNextForItemCItem240   bool IsNextForItem(const CItem &prev) const
241   {
242     return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name);
243       // && false;
244   }
245 
246   // rar docs: Solid flag can be set only for file headers and is never set for service headers.
IsSolidCItem247   bool IsSolid()        const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; }
Is_Rar5_CompatCItem248   bool Is_Rar5_Compat() const { return ((UInt32)Method & NMethodFlags::kRar5_Compat) != 0; }
Get_Rar5_CompatBitCItem249   unsigned Get_Rar5_CompatBit() const { return ((UInt32)Method >> 20) & 1; }
250 
Get_AlgoVersion_RawBitsCItem251   unsigned Get_AlgoVersion_RawBits() const { return (unsigned)Method & 0x3F; }
Get_AlgoVersion_HuffRevCItem252   unsigned Get_AlgoVersion_HuffRev() const
253   {
254     unsigned w = (unsigned)Method & 0x3F;
255     if (w == 1 && Is_Rar5_Compat())
256       w = 0;
257     return w;
258   }
Get_MethodCItem259   unsigned Get_Method() const { return ((unsigned)Method >> 7) & 0x7; }
260 
Get_DictSize_MainCItem261   unsigned Get_DictSize_Main() const
262     { return ((UInt32)Method >> 10) & (Get_AlgoVersion_RawBits() == 0 ? 0xf : 0x1f); }
Get_DictSize_FracCItem263   unsigned Get_DictSize_Frac() const
264   {
265     // original-unrar ignores Frac, if (algo==0) (rar5):
266     if (Get_AlgoVersion_RawBits() == 0)
267       return 0;
268     return ((UInt32)Method >> 15) & 0x1f;
269   }
Get_DictSize64CItem270   UInt64 Get_DictSize64() const
271   {
272     // ver 6.* check
273     // return (((UInt32)Method >> 10) & 0xF);
274     UInt64 winSize = 0;
275     const unsigned algo = Get_AlgoVersion_RawBits();
276     if (algo <= 1)
277     {
278       UInt32 w = 32;
279       if (algo == 1)
280         w += Get_DictSize_Frac();
281       winSize = (UInt64)w << (12 + Get_DictSize_Main());
282     }
283     return winSize;
284   }
285 
286 
IsServiceCItem287   bool IsService() const { return RecordType == NHeaderType::kService; }
288 
Is_STMCItem289   bool Is_STM() const { return IsService() && Name == "STM"; }
Is_CMTCItem290   bool Is_CMT() const { return IsService() && Name == "CMT"; }
Is_ACLCItem291   bool Is_ACL() const { return IsService() && Name == "ACL"; }
292   // bool Is_QO()  const { return IsService() && Name == "QO"; }
293 
294   int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
295   void PrintInfo(AString &s) const;
296 
297 
IsEncryptedCItem298   bool IsEncrypted() const
299   {
300     unsigned size;
301     return FindExtra(NExtraID::kCrypto, size) >= 0;
302   }
303 
FindExtra_BlakeCItem304   int FindExtra_Blake() const
305   {
306     unsigned size = 0;
307     const int offset = FindExtra(NExtraID::kHash, size);
308     if (offset >= 0
309         && size == Z7_BLAKE2S_DIGEST_SIZE + 1
310         && Extra[(unsigned)offset] == kHashID_Blake2sp)
311       return offset + 1;
312     return -1;
313   }
314 
315   bool FindExtra_Version(UInt64 &version) const;
316 
317   bool FindExtra_Link(CLinkInfo &link) const;
318   void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const;
319   bool Is_CopyLink() const;
320   bool Is_HardLink() const;
321   bool Is_CopyLink_or_HardLink() const;
322 
NeedUse_as_CopyLinkCItem323   bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); }
NeedUse_as_HardLinkCItem324   bool NeedUse_as_HardLink() const { return PackSize == 0 && Is_HardLink(); }
NeedUse_as_CopyLink_or_HardLinkCItem325   bool NeedUse_as_CopyLink_or_HardLink() const { return PackSize == 0 && Is_CopyLink_or_HardLink(); }
326 
327   bool GetAltStreamName(AString &name) const;
328 
GetWinAttribCItem329   UInt32 GetWinAttrib() const
330   {
331     UInt32 a;
332     switch (HostOS)
333     {
334       case kHost_Windows:
335           a = Attrib;
336           break;
337       case kHost_Unix:
338           a = Attrib << 16;
339           a |= 0x8000; // add posix mode marker
340           break;
341       default:
342           a = 0;
343     }
344     if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY;
345     return a;
346   }
347 
GetDataPositionCItem348   UInt64 GetDataPosition() const { return DataPos; }
349 };
350 
351 
352 struct CInArcInfo
353 {
354   UInt64 Flags;
355   UInt64 VolNumber;
356   UInt64 StartPos;
357   UInt64 EndPos;
358 
359   UInt64 EndFlags;
360   bool EndOfArchive_was_Read;
361 
362   bool IsEncrypted;
363   bool Locator_Defined;
364   bool Locator_Error;
365   bool Metadata_Defined;
366   bool Metadata_Error;
367   bool UnknownExtraRecord;
368   bool Extra_Error;
369   bool UnsupportedFeature;
370 
371   struct CLocator
372   {
373     UInt64 Flags;
374     UInt64 QuickOpen;
375     UInt64 Recovery;
376 
Is_QuickOpenCInArcInfo::CLocator377     bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; }
Is_RecoveryCInArcInfo::CLocator378     bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; }
379 
380     bool Parse(const Byte *p, size_t size);
CLocatorCInArcInfo::CLocator381     CLocator():
382       Flags(0),
383       QuickOpen(0),
384       Recovery(0)
385       {}
386   };
387 
388   struct CMetadata
389   {
390     UInt64 Flags;
391     UInt64 CTime;
392     AString ArcName;
393 
394     bool Parse(const Byte *p, size_t size);
CMetadataCInArcInfo::CMetadata395     CMetadata():
396       Flags(0),
397       CTime(0)
398       {}
399   };
400 
401   CLocator Locator;
402   CMetadata Metadata;
403 
404   bool ParseExtra(const Byte *p, size_t size);
405 
CInArcInfoCInArcInfo406   CInArcInfo():
407     Flags(0),
408     VolNumber(0),
409     StartPos(0),
410     EndPos(0),
411     EndFlags(0),
412     EndOfArchive_was_Read(false),
413     IsEncrypted(false),
414     Locator_Defined(false),
415     Locator_Error(false),
416     Metadata_Defined(false),
417     Metadata_Error(false),
418     UnknownExtraRecord(false),
419     Extra_Error(false),
420     UnsupportedFeature(false)
421       {}
422 
423   /*
424   void Clear()
425   {
426     Flags = 0;
427     VolNumber = 0;
428     StartPos = 0;
429     EndPos = 0;
430     EndFlags = 0;
431     EndOfArchive_was_Read = false;
432   }
433   */
434 
GetPhySizeCInArcInfo435   UInt64 GetPhySize() const { return EndPos - StartPos; }
436 
AreMoreVolumesCInArcInfo437   bool AreMoreVolumes()  const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; }
438 
IsVolumeCInArcInfo439   bool IsVolume()             const { return (Flags & NArcFlags::kVol) != 0; }
IsSolidCInArcInfo440   bool IsSolid()              const { return (Flags & NArcFlags::kSolid) != 0; }
Is_VolNumber_DefinedCInArcInfo441   bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; }
442 
GetVolIndexCInArcInfo443   UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; }
444 };
445 
446 
447 struct CRefItem
448 {
449   unsigned Item;   // First item in _items[]
450   unsigned Last;   // Last  item in _items[]
451   int Parent;      // in _refs[], if alternate stream
452   int Link;        // in _refs[]
453 };
454 
455 
456 struct CArc
457 {
458   CMyComPtr<IInStream> Stream;
459   CInArcInfo Info;
460 };
461 
462 
463 class CHandler Z7_final:
464   public IInArchive,
465   public IArchiveGetRawProps,
466   public ISetProperties,
467   Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
468   public CMyUnknownImp
469 {
470   Z7_COM_QI_BEGIN2(IInArchive)
471   Z7_COM_QI_ENTRY(IArchiveGetRawProps)
472   Z7_COM_QI_ENTRY(ISetProperties)
473   Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
474   Z7_COM_QI_END
475   Z7_COM_ADDREF_RELEASE
476 
477   Z7_IFACE_COM7_IMP(IInArchive)
478   Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
479   Z7_IFACE_COM7_IMP(ISetProperties)
480   DECL_ISetCompressCodecsInfo
481 
482   void InitDefaults();
483 
484   bool _isArc;
485   bool _needChecksumCheck;
486   bool _memUsage_WasSet;
487   bool _comment_WasUsedInArc;
488   bool _acl_Used;
489   bool _error_in_ACL;
490   bool _split_Error;
491 public:
492   CRecordVector<CRefItem> _refs;
493   CObjectVector<CItem> _items;
494 
495   CHandler();
496 private:
497   CObjectVector<CArc> _arcs;
498   CObjectVector<CByteBuffer> _acls;
499 
500   UInt32 _errorFlags;
501   // UInt32 _warningFlags;
502 
503   UInt32 _numBlocks;
504   unsigned _rar5comapt_mask;
505   unsigned _methodMasks[2];
506   UInt64 _algo_Mask;
507   UInt64 _dictMaxSizes[2];
508 
509   CByteBuffer _comment;
510   UString _missingVolName;
511 
512   UInt64 _memUsage_Decompress;
513 
514   DECL_EXTERNAL_CODECS_VARS
515 
516   UInt64 GetPackSize(unsigned refIndex) const;
517 
518   void FillLinks();
519 
520   HRESULT Open2(IInStream *stream,
521       const UInt64 *maxCheckStartPosition,
522       IArchiveOpenCallback *openCallback);
523 };
524 
525 }}
526 
527 #endif
528