mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-08 12:07:03 -06:00
15.07
This commit is contained in:
committed by
Kornel Lesiński
parent
cba375916f
commit
f6444c3256
@@ -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);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user