Home | History | Annotate | Download | only in Archive
      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