diff options
Diffstat (limited to 'CPP/7zip/Archive/Wim/WimIn.h')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Wim/WimIn.h | 355 |
1 files changed, 283 insertions, 72 deletions
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index da3e28a5..4b7c6d95 100755..100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -3,8 +3,10 @@ #ifndef __ARCHIVE_WIM_IN_H #define __ARCHIVE_WIM_IN_H -#include "Common/Buffer.h" -#include "Common/MyString.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyXml.h" + +#include "../../../Windows/PropVariant.h" #include "../../Compress/CopyCoder.h" #include "../../Compress/LzxDecoder.h" @@ -14,6 +16,104 @@ namespace NArchive { namespace NWim { +const UInt32 kDirRecordSizeOld = 62; +const UInt32 kDirRecordSize = 102; + +/* + There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields. + + Correct DIRENTRY structure: + { + hex offset + 0 UInt64 Len; + 8 UInt32 Attrib; + C UInt32 SecurityId; + + 10 UInt64 SubdirOffset; // = 0 for files + + 18 UInt64 unused1; // = 0? + 20 UInt64 unused2; // = 0? + + 28 UInt64 CTime; + 30 UInt64 ATime; + 38 UInt64 MTime; + + 40 Byte Sha1[20]; + + 54 UInt32 Unknown1; // is it 0 always? + + + union + { + 58 UInt64 NtNodeId; + { + 58 UInt32 ReparseTag; + 5C UInt32 ReparseFlags; // is it 0 always? Check with new imagex. + } + } + + 60 UInt16 Streams; + + 62 UInt16 ShortNameLen; + 64 UInt16 FileNameLen; + + 66 UInt16 Name[]; + UInt16 ShortName[]; + } + + // DIRENTRY for WIM_VERSION <= 1.10 + DIRENTRY_OLD structure: + { + hex offset + 0 UInt64 Len; + 8 UInt32 Attrib; + C UInt32 SecurityId; + + union + { + 10 UInt64 SubdirOffset; // + + 10 UInt32 OldWimFileId; // used for files in old WIMs + 14 UInt32 OldWimFileId_Reserved; // = 0 + } + + 18 UInt64 CTime; + 20 UInt64 ATime; + 28 UInt64 MTime; + + 30 UInt64 Unknown; // NtNodeId ? + + 38 UInt16 Streams; + 3A UInt16 ShortNameLen; + 3C UInt16 FileNameLen; + 3E UInt16 FileName[]; + UInt16 ShortName[]; + } + + ALT_STREAM structure: + { + hex offset + 0 UInt64 Len; + 8 UInt64 Unused; + 10 Byte Sha1[20]; + 24 UInt16 FileNameLen; + 26 UInt16 FileName[]; + } + + ALT_STREAM_OLD structure: + { + hex offset + 0 UInt64 Len; + 8 UInt64 StreamId; // 32-bit value + 10 UInt16 FileNameLen; + 12 UInt16 FileName[]; + } + + If item is file (not Directory) and there are alternative streams, + there is additional ALT_STREAM item of main "unnamed" stream in Streams array. + +*/ + namespace NXpress { class CBitStream @@ -24,7 +124,6 @@ class CBitStream public: bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); } - void ReleaseStream() { m_Stream.ReleaseStream(); } void Init() { m_Stream.Init(); m_BitPos = 0; } // UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; } @@ -74,11 +173,6 @@ class CDecoder HRESULT CodeSpec(UInt32 size); HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); public: - void ReleaseStreams() - { - m_OutWindowStream.ReleaseStream(); - m_InBitStream.ReleaseStream(); - } HRESULT Flush() { return m_OutWindowStream.Flush(); } HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); }; @@ -90,7 +184,7 @@ namespace NResourceFlags const Byte kFree = 1; const Byte kMetadata = 2; const Byte Compressed = 4; - const Byte Spanned = 4; + // const Byte Spanned = 4; } struct CResource @@ -107,7 +201,16 @@ struct CResource UnpackSize = 0; Flags = 0; } + UInt64 GetEndLimit() const { return Offset + PackSize; } void Parse(const Byte *p); + void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) + { + Parse(p); + UInt64 v = GetEndLimit(); + if (phySize < v) + phySize = v; + } + void WriteTo(Byte *p) const; bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; } bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; } @@ -117,16 +220,21 @@ struct CResource namespace NHeaderFlags { - const UInt32 kCompression = 2; - const UInt32 kSpanned = 8; - const UInt32 kRpFix = 0x80; - const UInt32 kXPRESS = 0x20000; - const UInt32 kLZX = 0x40000; + const UInt32 kCompression = 2; + const UInt32 kReadOnly = 4; + const UInt32 kSpanned = 8; + const UInt32 kResourceOnly = 0x10; + const UInt32 kMetadataOnly = 0x20; + const UInt32 kWriteInProgress = 0x40; + const UInt32 kReparsePointFixup = 0x80; + const UInt32 kXPRESS = 0x20000; + const UInt32 kLZX = 0x40000; } const UInt32 kWimVersion = 0x010D00; -const UInt32 kHeaderSizeMax = 0xD0; -const UInt32 kSignatureSize = 8; + +const unsigned kHeaderSizeMax = 0xD0; +const unsigned kSignatureSize = 8; extern const Byte kSignature[kSignatureSize]; const unsigned kChunkSizeBits = 15; const UInt32 kChunkSize = (1 << kChunkSizeBits); @@ -150,7 +258,7 @@ struct CHeader void SetDefaultFields(bool useLZX); void WriteTo(Byte *p) const; - HRESULT Parse(const Byte *p); + HRESULT Parse(const Byte *p, UInt64 &phySize); bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; } bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0 || (Flags & NHeaderFlags::kXPRESS) != 0 ) ; } bool IsLzxMode() const { return (Flags & NHeaderFlags::kLZX) != 0; } @@ -164,115 +272,217 @@ struct CHeader } }; -const UInt32 kHashSize = 20; -const UInt32 kStreamInfoSize = 24 + 2 + 4 + kHashSize; +const unsigned kHashSize = 20; +const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize; struct CStreamInfo { CResource Resource; - UInt16 PartNumber; + UInt16 PartNumber; // for NEW WIM format, we set it to 1 for OLD WIM format UInt32 RefCount; - UInt32 Id; - BYTE Hash[kHashSize]; + UInt32 Id; // for OLD WIM format + Byte Hash[kHashSize]; void WriteTo(Byte *p) const; }; -const UInt32 kDirRecordSizeOld = 62; -const UInt32 kDirRecordSize = 102; - struct CItem { - UString Name; - UString ShortName; - UInt32 Attrib; - // UInt32 SecurityId; - BYTE Hash[kHashSize]; - UInt32 Id; - FILETIME CTime; - FILETIME ATime; - FILETIME MTime; - // UInt32 ReparseTag; - // UInt64 HardLink; - // UInt16 NumStreams; + size_t Offset; + int IndexInSorted; int StreamIndex; int Parent; - unsigned Order; - bool HasMetadata; - CItem(): HasMetadata(true), StreamIndex(-1), Id(0) {} - bool IsDir() const { return HasMetadata && ((Attrib & 0x10) != 0); } - bool HasStream() const + int ImageIndex; // -1 means that file is unreferenced in Images (deleted item?) + bool IsDir; + bool IsAltStream; + + bool HasMetadata() const { return ImageIndex >= 0; } + + CItem(): + IndexInSorted(-1), + StreamIndex(-1), + Parent(-1), + IsDir(false), + IsAltStream(false) + {} +}; + +struct CImage +{ + CByteBuffer Meta; + CRecordVector<UInt32> SecurOffsets; + unsigned StartItem; + unsigned NumItems; + unsigned NumEmptyRootItems; + int VirtualRootIndex; // index in CDatabase::VirtualRoots[] + UString RootName; + CByteBuffer RootNameBuf; + + CImage(): VirtualRootIndex(-1) {} +}; + +struct CImageInfo +{ + bool CTimeDefined; + bool MTimeDefined; + bool NameDefined; + bool IndexDefined; + + FILETIME CTime; + FILETIME MTime; + UString Name; + + UInt64 DirCount; + UInt64 FileCount; + UInt32 Index; + + int ItemIndexInXml; + + UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; } + + CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false), + IndexDefined(false), ItemIndexInXml(-1) {} + void Parse(const CXmlItem &item); +}; + +struct CWimXml +{ + CByteBuffer Data; + CXml Xml; + + UInt16 VolIndex; + CObjectVector<CImageInfo> Images; + + UString FileName; + + UInt64 GetTotalFilesAndDirs() const { - for (unsigned i = 0; i < kHashSize; i++) - if (Hash[i] != 0) - return true; - return Id != 0; + UInt64 sum = 0; + FOR_VECTOR (i, Images) + sum += Images[i].GetTotalFilesAndDirs(); + return sum; } + + void ToUnicode(UString &s); + bool Parse(); +}; + +struct CVolume +{ + CHeader Header; + CMyComPtr<IInStream> Stream; }; class CDatabase { - const Byte *DirData; + Byte *DirData; size_t DirSize; size_t DirProcessed; size_t DirStartOffset; - int Order; IArchiveOpenCallback *OpenCallback; - + HRESULT ParseDirItem(size_t pos, int parent); - HRESULT ParseImageDirs(const CByteBuffer &buf, int parent); + HRESULT ParseImageDirs(CByteBuffer &buf, int parent); public: - CRecordVector<CStreamInfo> Streams; - CObjectVector<CItem> Items; - CIntVector SortedItems; - int NumImages; - bool SkipRoot; - bool ShowImageNumber; + CRecordVector<CStreamInfo> DataStreams; + + CRecordVector<CStreamInfo> MetaStreams; + + CRecordVector<CItem> Items; + CObjectVector<CByteBuffer> ReparseItems; + CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems + // -1 means no reparse; + + CObjectVector<CImage> Images; + bool IsOldVersion; + bool ThereAreDeletedStreams; + bool ThereAreAltStreams; + bool RefCountError; + + // User Items can contain all images or just one image from all. + CUIntVector SortedItems; + int IndexOfUserImage; // -1 : if more than one images was filled to Sorted Items + + unsigned NumExludededItems; + int ExludedItem; // -1 : if there are no exclude items + CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives + + bool ThereIsError() const { return RefCountError; } + + unsigned GetNumUserItemsInImage(unsigned imageIndex) const + { + if (IndexOfUserImage >= 0 && imageIndex != (unsigned)IndexOfUserImage) + return 0; + if (imageIndex >= Images.Size()) + return 0; + return Images[imageIndex].NumItems - NumExludededItems; + } + + bool ItemHasStream(const CItem &item) const; UInt64 GetUnpackSize() const { UInt64 res = 0; - for (int i = 0; i < Streams.Size(); i++) - res += Streams[i].Resource.UnpackSize; + FOR_VECTOR (i, DataStreams) + res += DataStreams[i].Resource.UnpackSize; return res; } UInt64 GetPackSize() const { UInt64 res = 0; - for (int i = 0; i < Streams.Size(); i++) - res += Streams[i].Resource.PackSize; + FOR_VECTOR (i, DataStreams) + res += DataStreams[i].Resource.PackSize; return res; } void Clear() { - Streams.Clear(); + DataStreams.Clear(); + + MetaStreams.Clear(); + Items.Clear(); + ReparseItems.Clear(); + ItemToReparse.Clear(); + SortedItems.Clear(); - NumImages = 0; + + Images.Clear(); + VirtualRoots.Clear(); - SkipRoot = true; - ShowImageNumber = true; IsOldVersion = false; + ThereAreDeletedStreams = false; + ThereAreAltStreams = false; + RefCountError = false; } - UString GetItemPath(int index) const; + CDatabase(): RefCountError(false) {} - HRESULT Open(IInStream *inStream, const CHeader &h, CByteBuffer &xml, IArchiveOpenCallback *openCallback); + void GetShortName(unsigned index, NWindows::NCOM::CPropVariant &res) const; + void GetItemName(unsigned index1, NWindows::NCOM::CPropVariant &res) const; + void GetItemPath(unsigned index, bool showImageNumber, NWindows::NCOM::CPropVariant &res) const; - void DetectPathMode() - { - ShowImageNumber = (NumImages != 1); - } + HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml); + HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback); + HRESULT FillAndCheck(); - HRESULT Sort(bool skipRootDir); + /* + imageIndex showImageNumber NumImages + * true * Show Image_Number + -1 * >1 Show Image_Number + -1 false 1 Don't show Image_Number + N false * Don't show Image_Number + */ + HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber); + + HRESULT ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback); }; -HRESULT ReadHeader(IInStream *inStream, CHeader &header); +HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize); class CUnpacker { @@ -285,6 +495,7 @@ class CUnpacker NXpress::CDecoder xpressDecoder; CByteBuffer sizesBuf; + HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode, ISequentialOutStream *outStream, ICompressProgressInfo *progress); public: |