diff options
Diffstat (limited to 'CPP/7zip/Archive/Wim/WimIn.h')
-rw-r--r-- | CPP/7zip/Archive/Wim/WimIn.h | 345 |
1 files changed, 245 insertions, 100 deletions
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h index c3b93a8d..ac4a2bd8 100644 --- a/CPP/7zip/Archive/Wim/WimIn.h +++ b/CPP/7zip/Archive/Wim/WimIn.h @@ -3,12 +3,15 @@ #ifndef __ARCHIVE_WIM_IN_H #define __ARCHIVE_WIM_IN_H +#include "../../../../C/Alloc.h" + #include "../../../Common/MyBuffer.h" #include "../../../Common/MyXml.h" #include "../../../Windows/PropVariant.h" #include "../../Compress/CopyCoder.h" +#include "../../Compress/LzmsDecoder.h" #include "../../Compress/LzxDecoder.h" #include "../IArchive.h" @@ -16,8 +19,20 @@ namespace NArchive { namespace NWim { -const UInt32 kDirRecordSizeOld = 62; -const UInt32 kDirRecordSize = 102; +/* +WIM versions: +hexVer : headerSize : ver + : 1.07.01 - 1.08.01 : Longhorn.4001-4015 - another header, no signature, CAB compression +10900 : 60 : 1.09 : Longhorn.4029-4039 (2003) +10A00 : 60 : 1.10 : Longhorn.4083 (2004) image starting from 1 +10B00 : ?? : 1.11 : ?? +10C00 : 74 : 1.12 : Longhorn.4093 - VistaBeta1.5112 (2005) - (Multi-Part, SHA1) +10D00 : D0 : 1.13 : VistaBeta2 - Win10, (NumImages, BootIndex, IntegrityResource) +00E00 : D0 : 0.14 : LZMS, solid, esd, dism +*/ + +const unsigned kDirRecordSizeOld = 62; +const unsigned kDirRecordSize = 102; /* There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields. @@ -114,85 +129,26 @@ const UInt32 kDirRecordSize = 102; */ -namespace NXpress { - -class CBitStream -{ - CInBuffer m_Stream; - UInt32 m_Value; - unsigned m_BitPos; -public: - bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } - void SetStream(ISequentialInStream *s) { m_Stream.SetStream(s); } - - void Init() { m_Stream.Init(); m_BitPos = 0; } - // UInt64 GetProcessedSize() const { return m_Stream.GetProcessedSize() - m_BitPos / 8; } - Byte DirectReadByte() { return m_Stream.ReadByte(); } - - void Normalize() - { - if (m_BitPos < 16) - { - Byte b0 = m_Stream.ReadByte(); - Byte b1 = m_Stream.ReadByte(); - m_Value = (m_Value << 8) | b1; - m_Value = (m_Value << 8) | b0; - m_BitPos += 16; - } - } - - UInt32 GetValue(unsigned numBits) - { - Normalize(); - return (m_Value >> (m_BitPos - numBits)) & ((1 << numBits) - 1); - } - - void MovePos(unsigned numBits) { m_BitPos -= numBits; } - - UInt32 ReadBits(unsigned numBits) - { - UInt32 res = GetValue(numBits); - m_BitPos -= numBits; - return res; - } -}; - -const unsigned kNumHuffmanBits = 16; -const UInt32 kMatchMinLen = 3; -const UInt32 kNumLenSlots = 16; -const UInt32 kNumPosSlots = 16; -const UInt32 kNumPosLenSlots = kNumPosSlots * kNumLenSlots; -const UInt32 kMainTableSize = 256 + kNumPosLenSlots; - -class CDecoder -{ - CBitStream m_InBitStream; - CLzOutWindow m_OutWindowStream; - NCompress::NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder; - - HRESULT CodeSpec(UInt32 size); - HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); -public: - HRESULT Flush() { return m_OutWindowStream.Flush(); } - HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize); -}; - -} namespace NResourceFlags { - const Byte kFree = 1; - const Byte kMetadata = 2; - const Byte Compressed = 4; - // const Byte Spanned = 4; + // const Byte kFree = 1 << 0; + const Byte kMetadata = 1 << 1; + const Byte kCompressed = 1 << 2; + // const Byte kSpanned = 1 << 3; + const Byte kSolid = 1 << 4; } +const UInt64 k_SolidBig_Resource_Marker = (UInt64)1 << 32; + struct CResource { UInt64 PackSize; UInt64 Offset; UInt64 UnpackSize; Byte Flags; + bool KeepSolid; + int SolidIndex; void Clear() { @@ -200,7 +156,10 @@ struct CResource Offset = 0; UnpackSize = 0; Flags = 0; + KeepSolid = false; + SolidIndex = -1; } + UInt64 GetEndLimit() const { return Offset + PackSize; } void Parse(const Byte *p); void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize) @@ -212,59 +171,130 @@ struct CResource } void WriteTo(Byte *p) const; - bool IsFree() const { return (Flags & NResourceFlags::kFree) != 0; } + bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; } - bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; } + bool IsCompressed() const { return (Flags & NResourceFlags::kCompressed) != 0; } + bool IsSolid() const { return (Flags & NResourceFlags::kSolid) != 0; } + bool IsSolidBig() const { return IsSolid() && UnpackSize == k_SolidBig_Resource_Marker; } + bool IsSolidSmall() const { return IsSolid() && UnpackSize == 0; } + bool IsEmpty() const { return (UnpackSize == 0); } }; + +struct CSolid +{ + unsigned StreamIndex; + // unsigned NumRefs; + int FirstSmallStream; + + UInt64 SolidOffset; + + UInt64 UnpackSize; + int Method; + int ChunkSizeBits; + + UInt64 HeadersSize; + // size_t NumChunks; + CObjArray<UInt64> Chunks; // [NumChunks + 1] (start offset) + + UInt64 GetChunkPackSize(size_t chunkIndex) const { return Chunks[chunkIndex + 1] - Chunks[chunkIndex]; } + + CSolid(): + FirstSmallStream(-1), + // NumRefs(0), + Method(-1) + {} +}; + + namespace NHeaderFlags { - 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 kCompression = 1 << 1; + const UInt32 kReadOnly = 1 << 2; + const UInt32 kSpanned = 1 << 3; + const UInt32 kResourceOnly = 1 << 4; + const UInt32 kMetadataOnly = 1 << 5; + const UInt32 kWriteInProgress = 1 << 6; + const UInt32 kReparsePointFixup = 1 << 7; + + const UInt32 kXPRESS = (UInt32)1 << 17; + const UInt32 kLZX = (UInt32)1 << 18; + const UInt32 kLZMS = (UInt32)1 << 19; + + const UInt32 kMethodMask = 0xFFFE0000; } -const UInt32 kWimVersion = 0x010D00; + +namespace NMethod +{ + const UInt32 kXPRESS = 1; + const UInt32 kLZX = 2; + const UInt32 kLZMS = 3; +} + + +const UInt32 k_Version_NonSolid = 0x10D00; +const UInt32 k_Version_Solid = 0xE00; const unsigned kHeaderSizeMax = 0xD0; const unsigned kSignatureSize = 8; extern const Byte kSignature[kSignatureSize]; + const unsigned kChunkSizeBits = 15; -const UInt32 kChunkSize = (1 << kChunkSizeBits); +const UInt32 kChunkSize = (UInt32)1 << kChunkSizeBits; + struct CHeader { UInt32 Version; UInt32 Flags; UInt32 ChunkSize; + unsigned ChunkSizeBits; Byte Guid[16]; UInt16 PartNumber; UInt16 NumParts; UInt32 NumImages; - + UInt32 BootIndex; + + bool _IsOldVersion; // 1.10- + bool _IsNewVersion; // 1.13+ or 0.14 + CResource OffsetResource; CResource XmlResource; CResource MetadataResource; CResource IntegrityResource; - UInt32 BootIndex; void SetDefaultFields(bool useLZX); void WriteTo(Byte *p) const; 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; } - bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); } - bool IsOldVersion() const { return (Version <= 0x010A00); } - bool IsNewVersion() const { return (Version > 0x010C00); } + + bool IsSupported() const + { + return (!IsCompressed() + || (Flags & NHeaderFlags::kLZX) != 0 + || (Flags & NHeaderFlags::kXPRESS) != 0 + || (Flags & NHeaderFlags::kLZMS) != 0); + } + + unsigned GetMethod() const + { + if (!IsCompressed()) + return 0; + UInt32 mask = (Flags & NHeaderFlags::kMethodMask); + if (mask == 0) return 0; + if (mask == NHeaderFlags::kXPRESS) return NMethod::kXPRESS; + if (mask == NHeaderFlags::kLZX) return NMethod::kLZX; + if (mask == NHeaderFlags::kLZMS) return NMethod::kLZMS; + return mask; + } + + bool IsOldVersion() const { return _IsOldVersion; } + bool IsNewVersion() const { return _IsNewVersion; } + bool IsSolidVersion() const { return (Version == k_Version_Solid); } bool AreFromOnArchive(const CHeader &h) { @@ -272,7 +302,17 @@ struct CHeader } }; + const unsigned kHashSize = 20; + +inline bool IsEmptySha(const Byte *data) +{ + for (unsigned i = 0; i < kHashSize; i++) + if (data[i] != 0) + return false; + return true; +} + const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize; struct CStreamInfo @@ -283,9 +323,12 @@ struct CStreamInfo UInt32 Id; // for OLD WIM format Byte Hash[kHashSize]; + bool IsEmptyHash() const { return IsEmptySha(Hash); } + void WriteTo(Byte *p) const; }; + struct CItem { size_t Offset; @@ -321,6 +364,7 @@ struct CImage CImage(): VirtualRootIndex(-1) {} }; + struct CImageInfo { bool CTimeDefined; @@ -345,6 +389,7 @@ struct CImageInfo void Parse(const CXmlItem &item); }; + struct CWimXml { CByteBuffer Data; @@ -354,6 +399,7 @@ struct CWimXml CObjectVector<CImageInfo> Images; UString FileName; + bool IsEncrypted; UInt64 GetTotalFilesAndDirs() const { @@ -365,14 +411,18 @@ struct CWimXml void ToUnicode(UString &s); bool Parse(); + + CWimXml(): IsEncrypted(false) {} }; + struct CVolume { CHeader Header; CMyComPtr<IInStream> Stream; }; + class CDatabase { Byte *DirData; @@ -386,9 +436,9 @@ class CDatabase public: CRecordVector<CStreamInfo> DataStreams; - - CRecordVector<CStreamInfo> MetaStreams; + + CObjectVector<CSolid> Solids; CRecordVector<CItem> Items; CObjectVector<CByteBuffer> ReparseItems; @@ -397,10 +447,15 @@ public: CObjectVector<CImage> Images; + bool IsOldVersion9; bool IsOldVersion; bool ThereAreDeletedStreams; bool ThereAreAltStreams; bool RefCountError; + bool HeadersError; + + bool GetStartImageIndex() const { return IsOldVersion9 ? 0 : 1; } + unsigned GetDirAlignMask() const { return IsOldVersion9 ? 3 : 7; } // User Items can contain all images or just one image from all. CUIntVector SortedItems; @@ -423,6 +478,31 @@ public: bool ItemHasStream(const CItem &item) const; + UInt64 Get_UnpackSize_of_Resource(const CResource &r) const + { + if (!r.IsSolid()) + return r.UnpackSize; + if (r.IsSolidSmall()) + return r.PackSize; + if (r.IsSolidBig() && r.SolidIndex >= 0) + return Solids[(unsigned)r.SolidIndex].UnpackSize; + return 0; + } + + UInt64 Get_PackSize_of_Resource(unsigned streamIndex) const + { + const CResource &r = DataStreams[streamIndex].Resource; + if (!r.IsSolidSmall()) + return r.PackSize; + if (r.SolidIndex >= 0) + { + const CSolid &ss = Solids[(unsigned)r.SolidIndex]; + if (ss.FirstSmallStream == (int)streamIndex) + return DataStreams[ss.StreamIndex].Resource.PackSize; + } + return 0; + } + UInt64 GetUnpackSize() const { UInt64 res = 0; @@ -442,8 +522,8 @@ public: void Clear() { DataStreams.Clear(); - MetaStreams.Clear(); + Solids.Clear(); Items.Clear(); ReparseItems.Clear(); @@ -458,6 +538,7 @@ public: ThereAreDeletedStreams = false; ThereAreAltStreams = false; RefCountError = false; + HeadersError = false; } CDatabase(): RefCountError(false) {} @@ -468,7 +549,7 @@ public: HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml); HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback); - HRESULT FillAndCheck(); + HRESULT FillAndCheck(const CObjectVector<CVolume> &volumes); /* imageIndex showImageNumber NumImages @@ -484,23 +565,87 @@ public: HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize); + +struct CMidBuf +{ + Byte *Data; + size_t _size; + + CMidBuf(): Data(NULL), _size(0) {} + + void EnsureCapacity(size_t size) + { + if (size > _size) + { + ::MidFree(Data); + _size = 0; + Data = (Byte *)::MidAlloc(size); + if (Data) + _size = size; + } + } + + ~CMidBuf() { ::MidFree(Data); } +}; + + class CUnpacker { NCompress::CCopyCoder *copyCoderSpec; CMyComPtr<ICompressCoder> copyCoder; NCompress::NLzx::CDecoder *lzxDecoderSpec; - CMyComPtr<ICompressCoder> lzxDecoder; + CMyComPtr<IUnknown> lzxDecoder; - NXpress::CDecoder xpressDecoder; + NCompress::NLzms::CDecoder *lzmsDecoder; CByteBuffer sizesBuf; - HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode, - ISequentialOutStream *outStream, ICompressProgressInfo *progress); + CMidBuf packBuf; + CMidBuf unpackBuf; + + // solid resource + int _solidIndex; + size_t _unpackedChunkIndex; + + HRESULT UnpackChunk( + ISequentialInStream *inStream, + unsigned method, unsigned chunkSizeBits, + size_t inSize, size_t outSize, + ISequentialOutStream *outStream); + + HRESULT Unpack2( + IInStream *inStream, + const CResource &res, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress); + public: - HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode, - ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest); + UInt64 TotalPacked; + + CUnpacker(): + lzmsDecoder(NULL), + _solidIndex(-1), + _unpackedChunkIndex(0), + TotalPacked(0) + {} + ~CUnpacker(); + + HRESULT Unpack( + IInStream *inStream, + const CResource &res, + const CHeader &header, + const CDatabase *db, + ISequentialOutStream *outStream, + ICompressProgressInfo *progress, + Byte *digest); + + HRESULT UnpackData(IInStream *inStream, + const CResource &resource, const CHeader &header, + const CDatabase *db, + CByteBuffer &buf, Byte *digest); }; }} |