1 // OpenArchive.h
2 
3 #ifndef __OPEN_ARCHIVE_H
4 #define __OPEN_ARCHIVE_H
5 
6 #include "../../../Windows/PropVariant.h"
7 
8 #include "ArchiveOpenCallback.h"
9 #include "LoadCodecs.h"
10 #include "Property.h"
11 
12 #ifndef _SFX
13 
14 #define SUPPORT_ALT_STREAMS
15 
16 #endif
17 
18 HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw();
19 HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw();
20 HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw();
21 HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw();
22 HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw();
23 
24 #ifdef SUPPORT_ALT_STREAMS
25 int FindAltStreamColon_in_Path(const wchar_t *path);
26 #endif
27 
28 /*
29 struct COptionalOpenProperties
30 {
31   UString FormatName;
32   CObjectVector<CProperty> Props;
33 };
34 */
35 
36 #ifdef _SFX
37 #define OPEN_PROPS_DECL
38 #else
39 #define OPEN_PROPS_DECL const CObjectVector<CProperty> *props;
40 // #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *props
41 #endif
42 
43 struct COpenSpecFlags
44 {
45   // bool CanReturnFull;
46   bool CanReturnFrontal;
47   bool CanReturnTail;
48   bool CanReturnMid;
49 
CanReturn_NonStartCOpenSpecFlags50   bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; }
51 
COpenSpecFlagsCOpenSpecFlags52   COpenSpecFlags():
53     // CanReturnFull(true),
54     CanReturnFrontal(false),
55     CanReturnTail(false),
56     CanReturnMid(false)
57     {}
58 };
59 
60 struct COpenType
61 {
62   int FormatIndex;
63 
64   COpenSpecFlags SpecForcedType;
65   COpenSpecFlags SpecMainType;
66   COpenSpecFlags SpecWrongExt;
67   COpenSpecFlags SpecUnknownExt;
68 
69   bool Recursive;
70 
71   bool CanReturnArc;
72   bool CanReturnParser;
73   bool IsHashType;
74   bool EachPos;
75 
76   // bool SkipSfxStub;
77   // bool ExeAsUnknown;
78 
79   bool ZerosTailIsAllowed;
80 
81   bool MaxStartOffset_Defined;
82   UInt64 MaxStartOffset;
83 
GetSpecCOpenType84   const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const
85   {
86     return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt));
87   }
88 
COpenTypeCOpenType89   COpenType():
90       FormatIndex(-1),
91       Recursive(true),
92       CanReturnArc(true),
93       CanReturnParser(false),
94       IsHashType(false),
95       EachPos(false),
96       // SkipSfxStub(true),
97       // ExeAsUnknown(true),
98       ZerosTailIsAllowed(false),
99       MaxStartOffset_Defined(false),
100       MaxStartOffset(0)
101   {
102     SpecForcedType.CanReturnFrontal = true;
103     SpecForcedType.CanReturnTail = true;
104     SpecForcedType.CanReturnMid = true;
105 
106     SpecMainType.CanReturnFrontal = true;
107 
108     SpecUnknownExt.CanReturnTail = true; // for sfx
109     SpecUnknownExt.CanReturnMid = true;
110     SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad
111 
112     // ZerosTailIsAllowed = true;
113   }
114 };
115 
116 struct COpenOptions
117 {
118   CCodecs *codecs;
119   COpenType openType;
120   const CObjectVector<COpenType> *types;
121   const CIntVector *excludedFormats;
122 
123   IInStream *stream;
124   ISequentialInStream *seqStream;
125   IArchiveOpenCallback *callback;
126   COpenCallbackImp *callbackSpec; // it's used for SFX only
127   OPEN_PROPS_DECL
128   // bool openOnlySpecifiedByExtension,
129 
130   bool stdInMode;
131   UString filePath;
132 
COpenOptionsCOpenOptions133   COpenOptions():
134       codecs(NULL),
135       types(NULL),
136       excludedFormats(NULL),
137       stream(NULL),
138       seqStream(NULL),
139       callback(NULL),
140       callbackSpec(NULL),
141       stdInMode(false)
142     {}
143 
144 };
145 
146 UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL);
147 
148 struct CArcErrorInfo
149 {
150   bool ThereIsTail;
151   bool UnexpecedEnd;
152   bool IgnoreTail; // all are zeros
153   // bool NonZerosTail;
154   bool ErrorFlags_Defined;
155   UInt32 ErrorFlags;
156   UInt32 WarningFlags;
157   int ErrorFormatIndex; // - 1 means no Error.
158                         // if FormatIndex == ErrorFormatIndex, the archive is open with offset
159   UInt64 TailSize;
160 
161   /* if CArc is Open OK with some format:
162         - ErrorFormatIndex shows error format index, if extension is incorrect
163         - other variables show message and warnings of archive that is open */
164 
165   UString ErrorMessage;
166   UString WarningMessage;
167 
168   // call IsArc_After_NonOpen only if Open returns S_FALSE
IsArc_After_NonOpenCArcErrorInfo169   bool IsArc_After_NonOpen() const
170   {
171     return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0);
172   }
173 
174 
CArcErrorInfoCArcErrorInfo175   CArcErrorInfo():
176       ThereIsTail(false),
177       UnexpecedEnd(false),
178       IgnoreTail(false),
179       // NonZerosTail(false),
180       ErrorFlags_Defined(false),
181       ErrorFlags(0),
182       WarningFlags(0),
183       ErrorFormatIndex(-1),
184       TailSize(0)
185     {}
186 
187   void ClearErrors();
188 
ClearErrors_FullCArcErrorInfo189   void ClearErrors_Full()
190   {
191     ErrorFormatIndex = -1;
192     ClearErrors();
193   }
194 
IsThereErrorOrWarningCArcErrorInfo195   bool IsThereErrorOrWarning() const
196   {
197     return ErrorFlags != 0
198         || WarningFlags != 0
199         || NeedTailWarning()
200         || UnexpecedEnd
201         || !ErrorMessage.IsEmpty()
202         || !WarningMessage.IsEmpty();
203   }
204 
AreThereErrorsCArcErrorInfo205   bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; }
AreThereWarningsCArcErrorInfo206   bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); }
207 
NeedTailWarningCArcErrorInfo208   bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; }
209 
GetWarningFlagsCArcErrorInfo210   UInt32 GetWarningFlags() const
211   {
212     UInt32 a = WarningFlags;
213     if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0)
214       a |= kpv_ErrorFlags_DataAfterEnd;
215     return a;
216   }
217 
GetErrorFlagsCArcErrorInfo218   UInt32 GetErrorFlags() const
219   {
220     UInt32 a = ErrorFlags;
221     if (UnexpecedEnd)
222       a |= kpv_ErrorFlags_UnexpectedEnd;
223     return a;
224   }
225 };
226 
227 struct CReadArcItem
228 {
229   UString Path;            // Path from root (including alt stream name, if alt stream)
230   UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode
231 
232   #ifdef SUPPORT_ALT_STREAMS
233   UString MainPath;
234                 /* MainPath = Path for non-AltStream,
235                    MainPath = Path of parent, if there is parent for AltStream. */
236   UString AltStreamName;
237   bool IsAltStream;
238   bool WriteToAltStreamIfColon;
239   #endif
240 
241   bool IsDir;
242   bool MainIsDir;
243   UInt32 ParentIndex; // use it, if IsAltStream
244 
245   #ifndef _SFX
246   bool _use_baseParentFolder_mode;
247   int _baseParentFolder;
248   #endif
249 
CReadArcItemCReadArcItem250   CReadArcItem()
251   {
252     #ifdef SUPPORT_ALT_STREAMS
253     WriteToAltStreamIfColon = false;
254     #endif
255 
256     #ifndef _SFX
257     _use_baseParentFolder_mode = false;
258     _baseParentFolder = -1;
259     #endif
260   }
261 };
262 
263 class CArc
264 {
265   HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);
266   HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset);
267   HRESULT OpenStream2(const COpenOptions &options);
268 
269   #ifndef _SFX
270   // parts.Back() can contain alt stream name "nams:AltName"
271   HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;
272   #endif
273 
274 public:
275   CMyComPtr<IInArchive> Archive;
276   CMyComPtr<IInStream> InStream;
277           // we use InStream in 2 cases (ArcStreamOffset != 0):
278           // 1) if we use additional cache stream
279           // 2) we reopen sfx archive with CTailInStream
280 
281   CMyComPtr<IArchiveGetRawProps> GetRawProps;
282   CMyComPtr<IArchiveGetRootProps> GetRootProps;
283 
284   CArcErrorInfo ErrorInfo; // for OK archives
285   CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN)
286 
287   UString Path;
288   UString filePath;
289   UString DefaultName;
290   int FormatIndex;     // -1 means Parser
291   UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile
292   FILETIME MTime;
293   bool MTimeDefined;
294 
295   Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler
296   UInt64 PhySize;
297   // UInt64 OkPhySize;
298   bool PhySizeDefined;
299   // bool OkPhySize_Defined;
300   UInt64 FileSize;
301   UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file
302   // bool offsetDefined;
303 
GetEstmatedPhySize()304   UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; }
305 
306   UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler
GetGlobalOffset()307   Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive
308 
309   // AString ErrorFlagsText;
310 
311   bool IsParseArc;
312 
313   bool IsTree;
314   bool IsReadOnly;
315 
316   bool Ask_Deleted;
317   bool Ask_AltStream;
318   bool Ask_Aux;
319   bool Ask_INode;
320 
321   bool IgnoreSplit; // don't try split handler
322 
323   // void Set_ErrorFlagsText();
324 
CArc()325   CArc():
326     MTimeDefined(false),
327     IsTree(false),
328     IsReadOnly(false),
329     Ask_Deleted(false),
330     Ask_AltStream(false),
331     Ask_Aux(false),
332     Ask_INode(false),
333     IgnoreSplit(false)
334     {}
335 
336   HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes);
337 
338   // ~CArc();
339 
Close()340   HRESULT Close()
341   {
342     InStream.Release();
343     return Archive->Close();
344   }
345 
346   HRESULT GetItemPath(UInt32 index, UString &result) const;
347   HRESULT GetDefaultItemPath(UInt32 index, UString &result) const;
348 
349   // GetItemPath2 adds [DELETED] dir prefix for deleted items.
350   HRESULT GetItemPath2(UInt32 index, UString &result) const;
351 
352   HRESULT GetItem(UInt32 index, CReadArcItem &item) const;
353 
354   HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const;
355   HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const;
IsItemAnti(UInt32 index,bool & result)356   HRESULT IsItemAnti(UInt32 index, bool &result) const
357     { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); }
358 
359 
360   HRESULT OpenStream(const COpenOptions &options);
361   HRESULT OpenStreamOrFile(COpenOptions &options);
362 
363   HRESULT ReOpen(const COpenOptions &options, IArchiveOpenCallback *openCallback_Additional);
364 
365   HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream);
366 
IsHashHandler(const COpenOptions & options)367   bool IsHashHandler(const COpenOptions &options) const
368   {
369     if (FormatIndex < 0)
370       return false;
371     return options.codecs->Formats[(unsigned)FormatIndex].Flags_HashHandler();
372   }
373 };
374 
375 struct CArchiveLink
376 {
377   CObjectVector<CArc> Arcs;
378   UStringVector VolumePaths;
379   UInt64 VolumesSize;
380   bool IsOpen;
381 
382   bool PasswordWasAsked;
383   // UString Password;
384 
385   // int NonOpenErrorFormatIndex; // - 1 means no Error.
386   UString NonOpen_ArcPath;
387 
388   CArcErrorInfo NonOpen_ErrorInfo;
389 
390   // UString ErrorsText;
391   // void Set_ErrorsText();
392 
CArchiveLinkCArchiveLink393   CArchiveLink():
394       VolumesSize(0),
395       IsOpen(false),
396       PasswordWasAsked(false)
397       {}
398 
399   void KeepModeForNextOpen();
400   HRESULT Close();
401   void Release();
~CArchiveLinkCArchiveLink402   ~CArchiveLink() { Release(); }
403 
GetArcCArchiveLink404   const CArc *GetArc() const { return &Arcs.Back(); }
GetArchiveCArchiveLink405   IInArchive *GetArchive() const { return Arcs.Back().Archive; }
GetArchiveGetRawPropsCArchiveLink406   IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; }
GetArchiveGetRootPropsCArchiveLink407   IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; }
408 
409   /*
410   Open() opens archive and COpenOptions::callback
411   Open2() uses COpenCallbackImp that implements Volumes and password callback
412   Open3() calls Open2() and callbackUI->Open_Finished();
413   Open_Strict() returns S_FALSE also in case, if there is non-open expected nested archive.
414   */
415 
416   HRESULT Open(COpenOptions &options);
417   HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI);
418   HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI);
419 
Open_StrictCArchiveLink420   HRESULT Open_Strict(COpenOptions &options, IOpenCallbackUI *callbackUI)
421   {
422     HRESULT result = Open3(options, callbackUI);
423     if (result == S_OK && NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
424       result = S_FALSE;
425     return result;
426   }
427 
428   HRESULT ReOpen(COpenOptions &options);
429 };
430 
431 bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types);
432 
433 // bool IsHashType(const CObjectVector<COpenType> &types);
434 
435 
436 struct CDirPathSortPair
437 {
438   unsigned Len;
439   unsigned Index;
440 
441   void SetNumSlashes(const FChar *s);
442 
CompareCDirPathSortPair443   int Compare(const CDirPathSortPair &a) const
444   {
445     // We need sorting order where parent items will be after child items
446     if (Len < a.Len) return 1;
447     if (Len > a.Len) return -1;
448     if (Index < a.Index) return -1;
449     if (Index > a.Index) return 1;
450     return 0;
451   }
452 };
453 
454 #endif
455