1 // Rar5Handler.h
2 
3 #ifndef __RAR5_HANDLER_H
4 #define __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 
53 namespace NLocatorFlags
54 {
55   const unsigned kQuickOpen  = 1 << 0;
56   const unsigned kRecovery   = 1 << 1;
57 }
58 
59 namespace NFileFlags
60 {
61   const unsigned kIsDir    = 1 << 0;
62   const unsigned kUnixTime = 1 << 1;
63   const unsigned kCrc32    = 1 << 2;
64   const unsigned kUnknownSize = 1 << 3;
65 }
66 
67 namespace NMethodFlags
68 {
69   // const unsigned kVersionMask = 0x3F;
70   const unsigned kSolid = 1 << 6;
71 }
72 
73 namespace NArcEndFlags
74 {
75   const unsigned kMoreVols = 1 << 0;
76 }
77 
78 enum EHostOS
79 {
80   kHost_Windows = 0,
81   kHost_Unix
82 };
83 
84 
85 
86 // ---------- Extra ----------
87 
88 namespace NExtraID
89 {
90   enum
91   {
92     kCrypto = 1,
93     kHash,
94     kTime,
95     kVersion,
96     kLink,
97     kUnixOwner,
98     kSubdata
99   };
100 }
101 
102 const unsigned kCryptoAlgo_AES = 0;
103 
104 namespace NCryptoFlags
105 {
106   const unsigned kPswCheck = 1 << 0;
107   const unsigned kUseMAC   = 1 << 1;
108 }
109 
110 struct CCryptoInfo
111 {
112   UInt64 Algo;
113   UInt64 Flags;
114   Byte Cnt;
115 
UseMACCCryptoInfo116   bool UseMAC()       const { return (Flags & NCryptoFlags::kUseMAC) != 0; }
IsThereCheckCCryptoInfo117   bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; }
118   bool Parse(const Byte *p, size_t size);
119 };
120 
121 const unsigned kHashID_Blake2sp = 0;
122 
123 namespace NTimeRecord
124 {
125   enum
126   {
127     k_Index_MTime = 0,
128     k_Index_CTime,
129     k_Index_ATime
130   };
131 
132   namespace NFlags
133   {
134     const unsigned kUnixTime = 1 << 0;
135     const unsigned kMTime    = 1 << 1;
136     const unsigned kCTime    = 1 << 2;
137     const unsigned kATime    = 1 << 3;
138     const unsigned kUnixNs   = 1 << 4;
139   }
140 }
141 
142 namespace NLinkType
143 {
144   enum
145   {
146     kUnixSymLink = 1,
147     kWinSymLink,
148     kWinJunction,
149     kHardLink,
150     kFileCopy
151   };
152 }
153 
154 namespace NLinkFlags
155 {
156   const unsigned kTargetIsDir = 1 << 0;
157 }
158 
159 
160 struct CLinkInfo
161 {
162   UInt64 Type;
163   UInt64 Flags;
164   unsigned NameOffset;
165   unsigned NameLen;
166 
167   bool Parse(const Byte *p, unsigned size);
168 };
169 
170 
171 struct CItem
172 {
173   UInt32 CommonFlags;
174   UInt32 Flags;
175 
176   Byte RecordType;
177   bool Version_Defined;
178 
179   int ACL;
180 
181   AString Name;
182 
183   int VolIndex;
184   int NextItem;
185 
186   UInt32 UnixMTime;
187   UInt32 CRC;
188   UInt32 Attrib;
189   UInt32 Method;
190 
191   CByteBuffer Extra;
192 
193   UInt64 Size;
194   UInt64 PackSize;
195   UInt64 HostOS;
196 
197   UInt64 DataPos;
198   UInt64 Version;
199 
CItemCItem200   CItem() { Clear(); }
201 
ClearCItem202   void Clear()
203   {
204     CommonFlags = 0;
205     Flags = 0;
206 
207     VolIndex = 0;
208     NextItem = -1;
209 
210     Version_Defined = false;
211     Version = 0;
212 
213     Name.Empty();
214     Extra.Free();
215     ACL = -1;
216   }
217 
IsSplitBeforeCItem218   bool IsSplitBefore()  const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; }
IsSplitAfterCItem219   bool IsSplitAfter()   const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; }
IsSplitCItem220   bool IsSplit()        const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; }
221 
IsDirCItem222   bool IsDir()          const { return (Flags & NFileFlags::kIsDir) != 0; }
Has_UnixMTimeCItem223   bool Has_UnixMTime()  const { return (Flags & NFileFlags::kUnixTime) != 0; }
Has_CRCCItem224   bool Has_CRC()        const { return (Flags & NFileFlags::kCrc32) != 0; }
Is_UnknownSizeCItem225   bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; }
226 
IsNextForItemCItem227   bool IsNextForItem(const CItem &prev) const
228   {
229     return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name);
230       // && false;
231   }
232 
IsSolidCItem233   bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; }
GetAlgoVersionCItem234   unsigned GetAlgoVersion() const { return (unsigned)Method & 0x3F; }
GetMethodCItem235   unsigned GetMethod() const { return ((unsigned)Method >> 7) & 0x7; }
GetDictSizeCItem236   UInt32 GetDictSize() const { return (((UInt32)Method >> 10) & 0xF); }
237 
IsServiceCItem238   bool IsService() const { return RecordType == NHeaderType::kService; }
239 
Is_STMCItem240   bool Is_STM() const { return IsService() && Name == "STM"; }
Is_CMTCItem241   bool Is_CMT() const { return IsService() && Name == "CMT"; }
Is_ACLCItem242   bool Is_ACL() const { return IsService() && Name == "ACL"; }
243   // bool Is_QO()  const { return IsService() && Name == "QO"; }
244 
245   int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
246   void PrintInfo(AString &s) const;
247 
248 
IsEncryptedCItem249   bool IsEncrypted() const
250   {
251     unsigned size;
252     return FindExtra(NExtraID::kCrypto, size) >= 0;
253   }
254 
FindExtra_BlakeCItem255   int FindExtra_Blake() const
256   {
257     unsigned size = 0;
258     int offset = FindExtra(NExtraID::kHash, size);
259     if (offset >= 0
260         && size == BLAKE2S_DIGEST_SIZE + 1
261         && Extra[(unsigned)offset] == kHashID_Blake2sp)
262       return offset + 1;
263     return -1;
264   }
265 
266   bool FindExtra_Version(UInt64 &version) const;
267 
268   bool FindExtra_Link(CLinkInfo &link) const;
269   void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const;
270   bool Is_CopyLink() const;
271   bool Is_HardLink() const;
272   bool Is_CopyLink_or_HardLink() const;
273 
NeedUse_as_CopyLinkCItem274   bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); }
NeedUse_as_HardLinkCItem275   bool NeedUse_as_HardLink() const { return PackSize == 0 && Is_HardLink(); }
NeedUse_as_CopyLink_or_HardLinkCItem276   bool NeedUse_as_CopyLink_or_HardLink() const { return PackSize == 0 && Is_CopyLink_or_HardLink(); }
277 
278   bool GetAltStreamName(AString &name) const;
279 
GetWinAttribCItem280   UInt32 GetWinAttrib() const
281   {
282     UInt32 a;
283     switch (HostOS)
284     {
285       case kHost_Windows: a = Attrib; break;
286       case kHost_Unix: a = (Attrib << 16); break;
287       default: a = 0;
288     }
289     // if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY;
290     return a;
291   }
292 
GetDataPositionCItem293   UInt64 GetDataPosition() const { return DataPos; }
294 };
295 
296 
297 struct CInArcInfo
298 {
299   UInt64 Flags;
300   UInt64 VolNumber;
301   UInt64 StartPos;
302   UInt64 EndPos;
303 
304   UInt64 EndFlags;
305   bool EndOfArchive_was_Read;
306 
307   bool IsEncrypted;
308 
309   // CByteBuffer Extra;
310 
311   /*
312   struct CLocator
313   {
314     UInt64 Flags;
315     UInt64 QuickOpen;
316     UInt64 Recovery;
317 
318     bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; }
319     bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; }
320   };
321 
322   int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
323   bool FindExtra_Locator(CLocator &locator) const;
324   */
325 
CInArcInfoCInArcInfo326   CInArcInfo():
327     Flags(0),
328     VolNumber(0),
329     StartPos(0),
330     EndPos(0),
331     EndFlags(0),
332     EndOfArchive_was_Read(false),
333     IsEncrypted(false)
334       {}
335 
336   /*
337   void Clear()
338   {
339     Flags = 0;
340     VolNumber = 0;
341     StartPos = 0;
342     EndPos = 0;
343     EndFlags = 0;
344     EndOfArchive_was_Read = false;
345     Extra.Free();
346   }
347   */
348 
GetPhySizeCInArcInfo349   UInt64 GetPhySize() const { return EndPos - StartPos; }
350 
AreMoreVolumesCInArcInfo351   bool AreMoreVolumes()  const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; }
352 
IsVolumeCInArcInfo353   bool IsVolume()             const { return (Flags & NArcFlags::kVol) != 0; }
IsSolidCInArcInfo354   bool IsSolid()              const { return (Flags & NArcFlags::kSolid) != 0; }
Is_VolNumber_DefinedCInArcInfo355   bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; }
356 
GetVolIndexCInArcInfo357   UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; }
358 };
359 
360 
361 struct CRefItem
362 {
363   unsigned Item;
364   unsigned Last;
365   int Parent;
366   int Link;
367 };
368 
369 
370 struct CArc
371 {
372   CMyComPtr<IInStream> Stream;
373   CInArcInfo Info;
374 };
375 
376 
377 class CHandler:
378   public IInArchive,
379   public IArchiveGetRawProps,
380   PUBLIC_ISetCompressCodecsInfo
381   public CMyUnknownImp
382 {
383 public:
384   CRecordVector<CRefItem> _refs;
385   CObjectVector<CItem> _items;
386 private:
387   CObjectVector<CArc> _arcs;
388   CObjectVector<CByteBuffer> _acls;
389 
390   UInt32 _errorFlags;
391   // UInt32 _warningFlags;
392   bool _isArc;
393   CByteBuffer _comment;
394   UString _missingVolName;
395 
396   DECL_EXTERNAL_CODECS_VARS
397 
398   UInt64 GetPackSize(unsigned refIndex) const;
399 
400   void FillLinks();
401 
402   HRESULT Open2(IInStream *stream,
403       const UInt64 *maxCheckStartPosition,
404       IArchiveOpenCallback *openCallback);
405 
406 public:
407   MY_QUERYINTERFACE_BEGIN2(IInArchive)
408   MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
409   QUERY_ENTRY_ISetCompressCodecsInfo
410   MY_QUERYINTERFACE_END
411   MY_ADDREF_RELEASE
412 
413   INTERFACE_IInArchive(;)
414   INTERFACE_IArchiveGetRawProps(;)
415 
416   DECL_ISetCompressCodecsInfo
417 };
418 
419 }}
420 
421 #endif
422