📄 wimin.cpp
字号:
// Archive/WimIn.cpp
#include "StdAfx.h"
#include "Common/MyCom.h"
#include "Common/IntToString.h"
#include "../../Common/StreamUtils.h"
#include "../../Common/StreamObjects.h"
#include "../../Common/LimitedStreams.h"
#include "../Common/OutStreamWithSha1.h"
#include "../../../../C/CpuArch.h"
#include "WimIn.h"
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
namespace NArchive{
namespace NWim{
static const int kChunkSizeBits = 15;
static const UInt32 kChunkSize = (1 << kChunkSizeBits);
namespace NXpress {
class CDecoderFlusher
{
CDecoder *m_Decoder;
public:
bool NeedFlush;
CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()
{
if (NeedFlush)
m_Decoder->Flush();
m_Decoder->ReleaseStreams();
}
};
HRESULT CDecoder::CodeSpec(UInt32 outSize)
{
{
Byte levels[kMainTableSize];
for (int i = 0; i < kMainTableSize; i += 2)
{
Byte b = m_InBitStream.DirectReadByte();
levels[i] = b & 0xF;
levels[i + 1] = b >> 4;
}
if (!m_MainDecoder.SetCodeLengths(levels))
return S_FALSE;
}
while (outSize > 0)
{
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
if (number < 256)
{
m_OutWindowStream.PutByte((Byte)number);
outSize--;
}
else
{
if (number >= kMainTableSize)
return S_FALSE;
UInt32 posLenSlot = number - 256;
UInt32 posSlot = posLenSlot / kNumLenSlots;
UInt32 len = posLenSlot % kNumLenSlots;
UInt32 distance = (1 << posSlot) - 1 + m_InBitStream.ReadBits(posSlot);
if (len == kNumLenSlots - 1)
{
len = m_InBitStream.DirectReadByte();
if (len == 0xFF)
{
len = m_InBitStream.DirectReadByte();
len |= (UInt32)m_InBitStream.DirectReadByte() << 8;
}
else
len += kNumLenSlots - 1;
}
len += kMatchMinLen;
UInt32 locLen = (len <= outSize ? len : outSize);
if (!m_OutWindowStream.CopyBlock(distance, locLen))
return S_FALSE;
len -= locLen;
outSize -= locLen;
if (len != 0)
return S_FALSE;
}
}
return S_OK;
}
const UInt32 kDictSize = (1 << kNumPosSlots);
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize)
{
if (!m_OutWindowStream.Create(kDictSize) || !m_InBitStream.Create(1 << 16))
return E_OUTOFMEMORY;
CDecoderFlusher flusher(this);
m_InBitStream.SetStream(inStream);
m_OutWindowStream.SetStream(outStream);
m_InBitStream.Init();
m_OutWindowStream.Init(false);
RINOK(CodeSpec(outSize));
flusher.NeedFlush = false;
return Flush();
}
HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize)
{
try { return CodeReal(inStream, outStream, outSize); }
catch(const CInBufferException &e) { return e.ErrorCode; } \
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
catch(...) { return S_FALSE; }
}
}
static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
{
ft->dwLowDateTime = Get32(p);
ft->dwHighDateTime = Get32(p + 4);
}
HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress)
{
RINOK(inStream->Seek(resource.Offset, STREAM_SEEK_SET, NULL));
CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream();
CMyComPtr<ISequentialInStream> limitedStream = limitedStreamSpec;
limitedStreamSpec->SetStream(inStream);
if (!copyCoder)
{
copyCoderSpec = new NCompress::CCopyCoder;
copyCoder = copyCoderSpec;
}
if (!resource.IsCompressed())
{
if (resource.PackSize != resource.UnpackSize)
return S_FALSE;
limitedStreamSpec->Init(resource.PackSize);
return copyCoder->Code(limitedStreamSpec, outStream, NULL, NULL, progress);
}
if (resource.UnpackSize == 0)
return S_OK;
UInt64 numChunks = (resource.UnpackSize + kChunkSize - 1) >> kChunkSizeBits;
unsigned entrySize = ((resource.UnpackSize > (UInt64)1 << 32) ? 8 : 4);
UInt64 sizesBufSize64 = entrySize * (numChunks - 1);
size_t sizesBufSize = (size_t)sizesBufSize64;
if (sizesBufSize != sizesBufSize64)
return E_OUTOFMEMORY;
if (sizesBufSize > sizesBuf.GetCapacity())
{
sizesBuf.Free();
sizesBuf.SetCapacity(sizesBufSize);
}
RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize));
const Byte *p = (const Byte *)sizesBuf;
if (lzxMode && !lzxDecoder)
{
lzxDecoderSpec = new NCompress::NLzx::CDecoder(true);
lzxDecoder = lzxDecoderSpec;
RINOK(lzxDecoderSpec->SetParams(kChunkSizeBits));
}
UInt64 baseOffset = resource.Offset + sizesBufSize64;
UInt64 outProcessed = 0;
for (UInt32 i = 0; i < (UInt32)numChunks; i++)
{
UInt64 offset = 0;
if (i > 0)
{
offset = (entrySize == 4) ? Get32(p): Get64(p);
p += entrySize;
}
UInt64 nextOffset = resource.PackSize - sizesBufSize64;
if (i + 1 < (UInt32)numChunks)
nextOffset = (entrySize == 4) ? Get32(p): Get64(p);
if (nextOffset < offset)
return S_FALSE;
RINOK(inStream->Seek(baseOffset + offset, STREAM_SEEK_SET, NULL));
UInt64 inSize = nextOffset - offset;
limitedStreamSpec->Init(inSize);
if (progress)
{
RINOK(progress->SetRatioInfo(&offset, &outProcessed));
}
UInt32 outSize = kChunkSize;
if (outProcessed + outSize > resource.UnpackSize)
outSize = (UInt32)(resource.UnpackSize - outProcessed);
UInt64 outSize64 = outSize;
if (inSize == outSize)
{
RINOK(copyCoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
}
else
{
if (lzxMode)
{
lzxDecoderSpec->SetKeepHistory(false);
RINOK(lzxDecoder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
}
else
{
RINOK(xpressDecoder.Code(limitedStreamSpec, outStream, outSize));
}
}
outProcessed += outSize;
}
return S_OK;
}
HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest)
{
COutStreamWithSha1 *shaStreamSpec = new COutStreamWithSha1();
CMyComPtr<ISequentialOutStream> shaStream = shaStreamSpec;
shaStreamSpec->SetStream(outStream);
shaStreamSpec->Init(digest != NULL);
HRESULT result = Unpack(inStream, resource, lzxMode, shaStream, progress);
if (digest)
shaStreamSpec->Final(digest);
return result;
}
static HRESULT UnpackData(IInStream *inStream, const CResource &resource, bool lzxMode, CByteBuffer &buf, Byte *digest)
{
size_t size = (size_t)resource.UnpackSize;
if (size != resource.UnpackSize)
return E_OUTOFMEMORY;
buf.Free();
buf.SetCapacity(size);
CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2();
CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
outStreamSpec->Init((Byte *)buf, size);
CUnpacker unpacker;
return unpacker.Unpack(inStream, resource, lzxMode, outStream, NULL, digest);
}
static const UInt32 kSignatureSize = 8;
static const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 };
void CResource::Parse(const Byte *p)
{
Flags = p[7];
PackSize = Get64(p) & (((UInt64)1 << 56) - 1);
Offset = Get64(p + 8);
UnpackSize = Get64(p + 16);
}
#define GetResource(p, res) res.Parse(p)
static void GetStream(const Byte *p, CStreamInfo &s)
{
s.Resource.Parse(p);
s.PartNumber = Get16(p + 24);
s.RefCount = Get32(p + 26);
memcpy(s.Hash, p + 30, kHashSize);
}
static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size,
const UString &prefix, CObjectVector<CItem> &items)
{
for (;;)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -