1// IArchive.h
2
3#ifndef __IARCHIVE_H
4#define __IARCHIVE_H
5
6#include "../IProgress.h"
7#include "../IStream.h"
8#include "../PropID.h"
9
10#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)
11#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
12
13namespace NFileTimeType
14{
15  enum EEnum
16  {
17    kWindows,
18    kUnix,
19    kDOS
20  };
21}
22
23namespace NArcInfoFlags
24{
25  const UInt32 kKeepName        = 1 << 0;  // keep name of file in archive name
26  const UInt32 kAltStreams      = 1 << 1;  // the handler supports alt streams
27  const UInt32 kNtSecure        = 1 << 2;  // the handler supports NT security
28  const UInt32 kFindSignature   = 1 << 3;  // the handler can find start of archive
29  const UInt32 kMultiSignature  = 1 << 4;  // there are several signatures
30  const UInt32 kUseGlobalOffset = 1 << 5;  // the seek position of stream must be set as global offset
31  const UInt32 kStartOpen       = 1 << 6;  // call handler for each start position
32  const UInt32 kPureStartOpen   = 1 << 7;  // call handler only for start of file
33  const UInt32 kBackwardOpen    = 1 << 8;  // archive can be open backward
34  const UInt32 kPreArc          = 1 << 9;  // such archive can be stored before real archive (like SFX stub)
35  const UInt32 kSymLinks        = 1 << 10; // the handler supports symbolic links
36  const UInt32 kHardLinks       = 1 << 11; // the handler supports hard links
37}
38
39namespace NArchive
40{
41  namespace NHandlerPropID
42  {
43    enum
44    {
45      kName = 0,        // VT_BSTR
46      kClassID,         // binary GUID in VT_BSTR
47      kExtension,       // VT_BSTR
48      kAddExtension,    // VT_BSTR
49      kUpdate,          // VT_BOOL
50      kKeepName,        // VT_BOOL
51      kSignature,       // binary in VT_BSTR
52      kMultiSignature,  // binary in VT_BSTR
53      kSignatureOffset, // VT_UI4
54      kAltStreams,      // VT_BOOL
55      kNtSecure,        // VT_BOOL
56      kFlags            // VT_UI4
57      // kVersion          // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR)
58    };
59  }
60
61  namespace NExtract
62  {
63    namespace NAskMode
64    {
65      enum
66      {
67        kExtract = 0,
68        kTest,
69        kSkip
70      };
71    }
72
73    namespace NOperationResult
74    {
75      enum
76      {
77        kOK = 0,
78        kUnsupportedMethod,
79        kDataError,
80        kCRCError,
81        kUnavailable,
82        kUnexpectedEnd,
83        kDataAfterEnd,
84        kIsNotArc,
85        kHeadersError
86      };
87    }
88  }
89
90  namespace NUpdate
91  {
92    namespace NOperationResult
93    {
94      enum
95      {
96        kOK = 0
97        , // kError
98      };
99    }
100  }
101}
102
103#define INTERFACE_IArchiveOpenCallback(x) \
104  STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \
105  STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \
106
107ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
108{
109  INTERFACE_IArchiveOpenCallback(PURE);
110};
111
112/*
113IArchiveExtractCallback::GetStream
114  Result:
115      (*inStream == NULL) - for directories
116      (*inStream == NULL) - if link (hard link or symbolic link) was created
117*/
118
119#define INTERFACE_IArchiveExtractCallback(x) \
120  INTERFACE_IProgress(x) \
121  STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
122  STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
123  STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) x; \
124
125ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)
126{
127  INTERFACE_IArchiveExtractCallback(PURE)
128};
129
130
131#define INTERFACE_IArchiveOpenVolumeCallback(x) \
132  STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \
133  STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \
134
135ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)
136{
137  INTERFACE_IArchiveOpenVolumeCallback(PURE);
138};
139
140
141ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)
142{
143  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;
144};
145
146
147ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
148{
149  STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;
150};
151
152
153/*
154IInArchive::Open
155    stream
156      if (kUseGlobalOffset), stream current position can be non 0.
157      if (!kUseGlobalOffset), stream current position is 0.
158    if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream
159    if (*maxCheckStartPosition == 0), the handler must check only current position as archive start
160
161IInArchive::Extract:
162  indices must be sorted
163  numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files"
164  testMode != 0 means "test files without writing to outStream"
165
166IInArchive::GetArchiveProperty:
167  kpidOffset  - start offset of archive.
168      VT_EMPTY : means offset = 0.
169      VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed
170  kpidPhySize - size of archive. VT_EMPTY means unknown size.
171    kpidPhySize is allowed to be larger than file size. In that case it must show
172    supposed size.
173
174  kpidIsDeleted:
175  kpidIsAltStream:
176  kpidIsAux:
177  kpidINode:
178    must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty.
179
180
181Notes:
182  Don't call IInArchive functions for same IInArchive object from different threads simultaneously.
183  Some IInArchive handlers will work incorrectly in that case.
184*/
185
186/* MSVC allows the code where there is throw() in declaration of function,
187   but there is no throw() in definition of function. */
188
189#ifdef _MSC_VER
190  #define MY_NO_THROW_DECL_ONLY throw()
191#else
192  #define MY_NO_THROW_DECL_ONLY
193#endif
194
195#define INTERFACE_IInArchive(x) \
196  STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \
197  STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \
198  STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \
199  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
200  STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; \
201  STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
202  STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
203  STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
204  STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
205  STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x;
206
207ARCHIVE_INTERFACE(IInArchive, 0x60)
208{
209  INTERFACE_IInArchive(PURE)
210};
211
212namespace NParentType
213{
214  enum
215  {
216    kDir = 0,
217    kAltStream
218  };
219};
220
221namespace NPropDataType
222{
223  const UInt32 kMask_ZeroEnd   = 1 << 4;
224  // const UInt32 kMask_BigEndian = 1 << 5;
225  const UInt32 kMask_Utf       = 1 << 6;
226  // const UInt32 kMask_Utf8  = kMask_Utf | 0;
227  const UInt32 kMask_Utf16 = kMask_Utf | 1;
228  // const UInt32 kMask_Utf32 = kMask_Utf | 2;
229
230  const UInt32 kNotDefined = 0;
231  const UInt32 kRaw = 1;
232  const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd;
233};
234
235// UTF string (pointer to wchar_t) with zero end and little-endian.
236#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1))
237
238/*
239GetRawProp:
240  Result:
241    S_OK - even if property is not set
242*/
243
244#define INTERFACE_IArchiveGetRawProps(x) \
245  STDMETHOD(GetParent)(UInt32 index, UInt32 *parent, UInt32 *parentType) x; \
246  STDMETHOD(GetRawProp)(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \
247  STDMETHOD(GetNumRawProps)(UInt32 *numProps) x; \
248  STDMETHOD(GetRawPropInfo)(UInt32 index, BSTR *name, PROPID *propID) x;
249
250ARCHIVE_INTERFACE(IArchiveGetRawProps, 0x70)
251{
252  INTERFACE_IArchiveGetRawProps(PURE)
253};
254
255#define INTERFACE_IArchiveGetRootProps(x) \
256  STDMETHOD(GetRootProp)(PROPID propID, PROPVARIANT *value) x; \
257  STDMETHOD(GetRootRawProp)(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \
258
259ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71)
260{
261  INTERFACE_IArchiveGetRootProps(PURE)
262};
263
264ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61)
265{
266  STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE;
267};
268
269/*
270  OpenForSize
271  Result:
272    S_FALSE - is not archive
273    ? - DATA error
274*/
275
276/*
277const UInt32 kOpenFlags_RealPhySize = 1 << 0;
278const UInt32 kOpenFlags_NoSeek = 1 << 1;
279// const UInt32 kOpenFlags_BeforeExtract = 1 << 2;
280*/
281
282/*
283Flags:
284   0 - opens archive with IInStream, if IInStream interface is supported
285     - if phySize is not available, it doesn't try to make full parse to get phySize
286   kOpenFlags_NoSeek -  ArcOpen2 function doesn't use IInStream interface, even if it's available
287   kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file
288
289  if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified,
290  the handler can return S_OK, but it doesn't check even Signature.
291  So next Extract can be called for that sequential stream.
292*/
293
294/*
295ARCHIVE_INTERFACE(IArchiveOpen2, 0x62)
296{
297  STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE;
298};
299*/
300
301// ---------- UPDATE ----------
302
303/*
304GetUpdateItemInfo outs:
305*newData  *newProps
306   0        0      - Copy data and properties from archive
307   0        1      - Copy data from archive, request new properties
308   1        0      - that combination is unused now
309   1        1      - Request new data and new properties. It can be used even for folders
310
311  indexInArchive = -1 if there is no item in archive, or if it doesn't matter.
312
313
314GetStream out:
315  Result:
316    S_OK:
317      (*inStream == NULL) - only for directories
318                          - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file
319      (*inStream != NULL) - for any file, even for empty file or anti-file
320    S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason)
321      (*inStream == NULL)
322
323The order of calling for hard links:
324  - GetStream()
325  - GetProperty(kpidHardLink)
326
327*/
328
329#define INTERFACE_IArchiveUpdateCallback(x) \
330  INTERFACE_IProgress(x); \
331  STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) x; \
332  STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
333  STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \
334  STDMETHOD(SetOperationResult)(Int32 operationResult) x; \
335
336ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80)
337{
338  INTERFACE_IArchiveUpdateCallback(PURE);
339};
340
341#define INTERFACE_IArchiveUpdateCallback2(x) \
342  INTERFACE_IArchiveUpdateCallback(x) \
343  STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \
344  STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \
345
346ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
347{
348  INTERFACE_IArchiveUpdateCallback2(PURE);
349};
350
351/*
352UpdateItems()
353-------------
354
355  outStream: output stream. (the handler) MUST support the case when
356    Seek position in outStream is not ZERO.
357    but the caller calls with empty outStream and seek position is ZERO??
358
359  archives with stub:
360
361  If archive is open and the handler and (Offset > 0), then the handler
362  knows about stub size.
363  UpdateItems():
364  1) the handler MUST copy that stub to outStream
365  2) the caller MUST NOT copy the stub to outStream, if
366     "rsfx" property is set with SetProperties
367
368  the handler must support the case where
369    ISequentialOutStream *outStream
370*/
371
372
373#define INTERFACE_IOutArchive(x) \
374  STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \
375  STDMETHOD(GetFileTimeType)(UInt32 *type) x;
376
377ARCHIVE_INTERFACE(IOutArchive, 0xA0)
378{
379  INTERFACE_IOutArchive(PURE)
380};
381
382
383ARCHIVE_INTERFACE(ISetProperties, 0x03)
384{
385  STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) PURE;
386};
387
388ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04)
389{
390  STDMETHOD(KeepModeForNextOpen)() PURE;
391};
392
393/* Exe handler: the handler for executable format (PE, ELF, Mach-O).
394   SFX archive: executable stub + some tail data.
395     before 9.31: exe handler didn't parse SFX archives as executable format.
396     for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */
397
398ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05)
399{
400  STDMETHOD(AllowTail)(Int32 allowTail) PURE;
401};
402
403
404#define IMP_IInArchive_GetProp(k) \
405  (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
406    { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
407    *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID];  *name = 0; return S_OK; } \
408
409#define IMP_IInArchive_GetProp_WITH_NAME(k) \
410  (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
411    { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
412    const STATPROPSTG &srcItem = k[index]; \
413    *propID = srcItem.propid; *varType = srcItem.vt; \
414    if (srcItem.lpwstrName == 0) *name = 0; else *name = ::SysAllocString(srcItem.lpwstrName); return S_OK; } \
415
416#define IMP_IInArchive_Props \
417  STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \
418    { *numProps = ARRAY_SIZE(kProps); return S_OK; } \
419  STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps)
420
421#define IMP_IInArchive_Props_WITH_NAME \
422  STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \
423    { *numProps = ARRAY_SIZE(kProps); return S_OK; } \
424  STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps)
425
426
427#define IMP_IInArchive_ArcProps \
428  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
429    { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \
430  STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps)
431
432#define IMP_IInArchive_ArcProps_WITH_NAME \
433  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
434    { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \
435  STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps)
436
437#define IMP_IInArchive_ArcProps_NO_Table \
438  STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
439    { *numProps = 0; return S_OK; } \
440  STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
441    { return E_NOTIMPL; } \
442
443#define IMP_IInArchive_ArcProps_NO \
444  IMP_IInArchive_ArcProps_NO_Table \
445  STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \
446    { value->vt = VT_EMPTY; return S_OK; }
447
448
449
450#define k_IsArc_Res_NO   0
451#define k_IsArc_Res_YES  1
452#define k_IsArc_Res_NEED_MORE 2
453// #define k_IsArc_Res_YES_LOW_PROB 3
454
455#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI
456#define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI
457
458extern "C"
459{
460  typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject);
461
462  typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size);
463  typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc);
464
465  typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats);
466  typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value);
467  typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value);
468
469  typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
470  typedef HRESULT (WINAPI *Func_SetLargePageMode)();
471
472  typedef IOutArchive * (*Func_CreateOutArchive)();
473  typedef IInArchive * (*Func_CreateInArchive)();
474}
475
476#endif
477