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