Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'CPP/7zip/Archive/Wim/WimIn.h')
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.h345
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);
};
}}