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 
13 namespace NFileTimeType
14 {
15   enum EEnum
16   {
17     kWindows,
18     kUnix,
19     kDOS
20   };
21 }
22 
23 namespace 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 
39 namespace 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 
107 ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
108 {
109   INTERFACE_IArchiveOpenCallback(PURE);
110 };
111 
112 /*
113 IArchiveExtractCallback::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 
125 ARCHIVE_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 
135 ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)
136 {
137   INTERFACE_IArchiveOpenVolumeCallback(PURE);
138 };
139 
140 
141 ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)
142 {
143   STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;
144 };
145 
146 
147 ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
148 {
149   STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;
150 };
151 
152 
153 /*
154 IInArchive::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 
161 IInArchive::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 
166 IInArchive::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 
181 Notes:
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 
207 ARCHIVE_INTERFACE(IInArchive, 0x60)
208 {
209   INTERFACE_IInArchive(PURE)
210 };
211 
212 namespace NParentType
213 {
214   enum
215   {
216     kDir = 0,
217     kAltStream
218   };
219 };
220 
221 namespace 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 /*
239 GetRawProp:
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 
250 ARCHIVE_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 
259 ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71)
260 {
261   INTERFACE_IArchiveGetRootProps(PURE)
262 };
263 
264 ARCHIVE_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 /*
277 const UInt32 kOpenFlags_RealPhySize = 1 << 0;
278 const UInt32 kOpenFlags_NoSeek = 1 << 1;
279 // const UInt32 kOpenFlags_BeforeExtract = 1 << 2;
280 */
281 
282 /*
283 Flags:
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 /*
295 ARCHIVE_INTERFACE(IArchiveOpen2, 0x62)
296 {
297   STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE;
298 };
299 */
300 
301 // ---------- UPDATE ----------
302 
303 /*
304 GetUpdateItemInfo 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 
314 GetStream 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 
323 The 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 
336 ARCHIVE_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 
346 ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
347 {
348   INTERFACE_IArchiveUpdateCallback2(PURE);
349 };
350 
351 /*
352 UpdateItems()
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 
377 ARCHIVE_INTERFACE(IOutArchive, 0xA0)
378 {
379   INTERFACE_IOutArchive(PURE)
380 };
381 
382 
383 ARCHIVE_INTERFACE(ISetProperties, 0x03)
384 {
385   STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps) PURE;
386 };
387 
388 ARCHIVE_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 
398 ARCHIVE_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 
458 extern "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