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