// OpenArchive.h #ifndef __OPEN_ARCHIVE_H #define __OPEN_ARCHIVE_H #include "../../../Windows/PropVariant.h" #include "ArchiveOpenCallback.h" #include "LoadCodecs.h" #include "Property.h" #ifndef _SFX #define SUPPORT_ALT_STREAMS #endif HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw(); HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw(); HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw(); #ifdef SUPPORT_ALT_STREAMS int FindAltStreamColon_in_Path(const wchar_t *path); #endif /* struct COptionalOpenProperties { UString FormatName; CObjectVector Props; }; */ #ifdef _SFX #define OPEN_PROPS_DECL #else #define OPEN_PROPS_DECL const CObjectVector *props; // #define OPEN_PROPS_DECL , const CObjectVector *props #endif struct COpenSpecFlags { // bool CanReturnFull; bool CanReturnFrontal; bool CanReturnTail; bool CanReturnMid; bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; } COpenSpecFlags(): // CanReturnFull(true), CanReturnFrontal(false), CanReturnTail(false), CanReturnMid(false) {} }; struct COpenType { int FormatIndex; COpenSpecFlags SpecForcedType; COpenSpecFlags SpecMainType; COpenSpecFlags SpecWrongExt; COpenSpecFlags SpecUnknownExt; bool Recursive; bool CanReturnArc; bool CanReturnParser; bool EachPos; // bool SkipSfxStub; // bool ExeAsUnknown; bool ZerosTailIsAllowed; bool MaxStartOffset_Defined; UInt64 MaxStartOffset; const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const { return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt)); } COpenType(): FormatIndex(-1), Recursive(true), EachPos(false), CanReturnArc(true), CanReturnParser(false), // SkipSfxStub(true), // ExeAsUnknown(true), ZerosTailIsAllowed(false), MaxStartOffset_Defined(false), MaxStartOffset(0) { SpecForcedType.CanReturnFrontal = true; SpecForcedType.CanReturnTail = true; SpecForcedType.CanReturnMid = true; SpecMainType.CanReturnFrontal = true; SpecUnknownExt.CanReturnTail = true; // for sfx SpecUnknownExt.CanReturnMid = true; SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad // ZerosTailIsAllowed = true; } }; struct COpenOptions { CCodecs *codecs; COpenType openType; const CObjectVector *types; const CIntVector *excludedFormats; IInStream *stream; ISequentialInStream *seqStream; IArchiveOpenCallback *callback; COpenCallbackImp *callbackSpec; OPEN_PROPS_DECL // bool openOnlySpecifiedByExtension, bool stdInMode; UString filePath; COpenOptions(): codecs(NULL), types(NULL), excludedFormats(NULL), stream(NULL), seqStream(NULL), callback(NULL), callbackSpec(NULL), stdInMode(false) {} }; UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL); struct CArcErrorInfo { bool ThereIsTail; bool UnexpecedEnd; bool IgnoreTail; // all are zeros // bool NonZerosTail; bool ErrorFlags_Defined; UInt32 ErrorFlags; UInt32 WarningFlags; int ErrorFormatIndex; // - 1 means no Error. // if FormatIndex == ErrorFormatIndex, the archive is open with offset UInt64 TailSize; /* if CArc is Open OK with some format: - ErrorFormatIndex shows error format index, if extension is incorrect - other variables show message and warnings of archive that is open */ UString ErrorMessage; UString WarningMessage; // call IsArc_After_NonOpen only if Open returns S_FALSE bool IsArc_After_NonOpen() const { return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0); } CArcErrorInfo(): ThereIsTail(false), UnexpecedEnd(false), IgnoreTail(false), // NonZerosTail(false), ErrorFlags_Defined(false), ErrorFlags(0), WarningFlags(0), ErrorFormatIndex(-1), TailSize(0) {} void ClearErrors(); void ClearErrors_Full() { ErrorFormatIndex = -1; ClearErrors(); } bool IsThereErrorOrWarning() const { return ErrorFlags != 0 || WarningFlags != 0 || NeedTailWarning() || UnexpecedEnd || !ErrorMessage.IsEmpty() || !WarningMessage.IsEmpty(); } bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; } bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); } bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; } UInt32 GetWarningFlags() const { UInt32 a = WarningFlags; if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0) a |= kpv_ErrorFlags_DataAfterEnd; return a; } UInt32 GetErrorFlags() const { UInt32 a = ErrorFlags; if (UnexpecedEnd) a |= kpv_ErrorFlags_UnexpectedEnd; return a; } }; struct CReadArcItem { UString Path; // Path from root (including alt stream name, if alt stream) UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode #ifdef SUPPORT_ALT_STREAMS UString MainPath; /* MainPath = Path for non-AltStream, MainPath = Path of parent, if there is parent for AltStream. */ UString AltStreamName; bool IsAltStream; bool WriteToAltStreamIfColon; #endif bool IsDir; bool MainIsDir; UInt32 ParentIndex; // use it, if IsAltStream #ifndef _SFX bool _use_baseParentFolder_mode; int _baseParentFolder; #endif CReadArcItem() { #ifdef SUPPORT_ALT_STREAMS WriteToAltStreamIfColon = false; #endif #ifndef _SFX _use_baseParentFolder_mode = false; _baseParentFolder = -1; #endif } }; class CArc { HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr &archive); HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset); HRESULT OpenStream2(const COpenOptions &options); #ifndef _SFX // parts.Back() can contain alt stream name "nams:AltName" HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const; #endif public: CMyComPtr Archive; CMyComPtr InStream; // we use InStream in 2 cases (ArcStreamOffset != 0): // 1) if we use additional cache stream // 2) we reopen sfx archive with CTailInStream CMyComPtr GetRawProps; CMyComPtr GetRootProps; CArcErrorInfo ErrorInfo; // for OK archives CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN) UString Path; UString filePath; UString DefaultName; int FormatIndex; // - 1 means Parser. int SubfileIndex; FILETIME MTime; bool MTimeDefined; Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler UInt64 PhySize; // UInt64 OkPhySize; bool PhySizeDefined; // bool OkPhySize_Defined; UInt64 FileSize; UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file // bool offsetDefined; UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; } UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive // AString ErrorFlagsText; bool IsParseArc; bool IsTree; bool IsReadOnly; bool Ask_Deleted; bool Ask_AltStream; bool Ask_Aux; bool Ask_INode; bool IgnoreSplit; // don't try split handler // void Set_ErrorFlagsText(); CArc(): MTimeDefined(false), IsTree(false), IsReadOnly(false), Ask_Deleted(false), Ask_AltStream(false), Ask_Aux(false), Ask_INode(false), IgnoreSplit(false) {} HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes); // ~CArc(); HRESULT Close() { InStream.Release(); return Archive->Close(); } HRESULT GetItemPath(UInt32 index, UString &result) const; HRESULT GetDefaultItemPath(UInt32 index, UString &result) const; // GetItemPath2 adds [DELETED] dir prefix for deleted items. HRESULT GetItemPath2(UInt32 index, UString &result) const; HRESULT GetItem(UInt32 index, CReadArcItem &item) const; HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const; HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const; HRESULT IsItemAnti(UInt32 index, bool &result) const { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); } HRESULT OpenStream(const COpenOptions &options); HRESULT OpenStreamOrFile(COpenOptions &options); HRESULT ReOpen(const COpenOptions &options); HRESULT CreateNewTailStream(CMyComPtr &stream); }; struct CArchiveLink { CObjectVector Arcs; UStringVector VolumePaths; UInt64 VolumesSize; bool IsOpen; bool PasswordWasAsked; // UString Password; // int NonOpenErrorFormatIndex; // - 1 means no Error. UString NonOpen_ArcPath; CArcErrorInfo NonOpen_ErrorInfo; // UString ErrorsText; // void Set_ErrorsText(); CArchiveLink(): VolumesSize(0), IsOpen(false), PasswordWasAsked(false) {} void KeepModeForNextOpen(); HRESULT Close(); void Release(); ~CArchiveLink() { Release(); } const CArc *GetArc() const { return &Arcs.Back(); } IInArchive *GetArchive() const { return Arcs.Back().Archive; } IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; } IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; } HRESULT Open(COpenOptions &options); HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI); HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI); HRESULT Open_Strict(COpenOptions &options, IOpenCallbackUI *callbackUI) { HRESULT result = Open3(options, callbackUI); if (result == S_OK && NonOpen_ErrorInfo.ErrorFormatIndex >= 0) result = S_FALSE; return result; } HRESULT ReOpen(COpenOptions &options); }; bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector &types); struct CDirPathSortPair { unsigned Len; unsigned Index; void SetNumSlashes(const FChar *s); int Compare(const CDirPathSortPair &a) const { // We need sorting order where parent items will be after child items if (Len < a.Len) return 1; if (Len > a.Len) return -1; if (Index < a.Index) return -1; if (Index > a.Index) return 1; return 0; } }; #endif