4.59 beta

This commit is contained in:
Igor Pavlov
2008-08-13 00:00:00 +00:00
committed by Kornel Lesiński
parent 3901bf0ab8
commit 173c07e166
781 changed files with 22124 additions and 13650 deletions

View File

@@ -5,14 +5,22 @@
#include "Common/IntToString.h"
#include "Common/Defs.h"
#include "Common/ComTry.h"
#include "Common/StringToInt.h"
#include "Common/UTFConvert.h"
#include "Windows/PropVariant.h"
#include "../../Common/StreamUtils.h"
#include "../../Common/ProgressUtils.h"
#include "../../../../C/CpuArch.h"
#include "WimHandler.h"
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
using namespace NWindows;
namespace NArchive {
@@ -20,17 +28,17 @@ namespace NWim {
#define WIM_DETAILS
STATPROPSTG kProps[] =
STATPROPSTG kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsFolder, VT_BOOL},
{ NULL, kpidIsDir, VT_BOOL},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackedSize, VT_UI8},
{ NULL, kpidAttributes, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
{ NULL, kpidAttrib, VT_UI4},
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidCreationTime, VT_FILETIME},
{ NULL, kpidLastAccessTime, VT_FILETIME},
{ NULL, kpidLastWriteTime, VT_FILETIME}
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidATime, VT_FILETIME}
#ifdef WIM_DETAILS
, { NULL, kpidVolume, VT_UI4}
@@ -39,17 +47,113 @@ STATPROPSTG kProps[] =
#endif
};
STATPROPSTG kArcProps[] =
STATPROPSTG kArcProps[] =
{
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackedSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidComment, VT_FILETIME},
{ NULL, kpidIsVolume, VT_BOOL},
{ NULL, kpidVolume, VT_UI4},
{ NULL, kpidNumVolumes, VT_UI4}
};
static bool ParseNumber64(const AString &s, UInt64 &res)
{
const char *end;
if (s.Left(2) == "0x")
{
if (s.Length() == 2)
return false;
res = ConvertHexStringToUInt64((const char *)s + 2, &end);
}
else
{
if (s.IsEmpty())
return false;
res = ConvertStringToUInt64(s, &end);
}
return *end == 0;
}
static bool ParseNumber32(const AString &s, UInt32 &res)
{
UInt64 res64;
if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32))
return false;
res = (UInt32)res64;
return true;
}
void ParseTime(const CXmlItem &item, bool &defined, FILETIME &ft, const AString &s)
{
defined = false;
int cTimeIndex = item.FindSubTag(s);
if (cTimeIndex >= 0)
{
const CXmlItem &timeItem = item.SubItems[cTimeIndex];
UInt32 high = 0, low = 0;
if (ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high) &&
ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low))
{
defined = true;
ft.dwHighDateTime = high;
ft.dwLowDateTime = low;
}
}
}
void CImageInfo::Parse(const CXmlItem &item)
{
ParseTime(item, CTimeDefined, CTime, "CREATIONTIME");
ParseTime(item, MTimeDefined, MTime, "LASTMODIFICATIONTIME");
NameDefined = ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name);
// IndexDefined = ParseNumber32(item.GetPropertyValue("INDEX"), Index);
}
void CXml::Parse()
{
size_t size = Data.GetCapacity();
if (size < 2 || (size & 1) != 0 || (size > 1 << 24))
return;
const Byte *p = Data;
if (Get16(p) != 0xFEFF)
return;
UString s;
{
wchar_t *chars = s.GetBuffer((int)size / 2 + 1);
for (size_t i = 2; i < size; i += 2)
*chars++ = (wchar_t)Get16(p + i);
*chars = 0;
s.ReleaseBuffer();
}
AString utf;
if (!ConvertUnicodeToUTF8(s, utf))
return;
::CXml xml;
if (!xml.Parse(utf))
return;
if (xml.Root.Name != "WIM")
return;
for (int i = 0; i < xml.Root.SubItems.Size(); i++)
{
const CXmlItem &item = xml.Root.SubItems[i];
if (item.IsTagged("IMAGE"))
{
CImageInfo imageInfo;
imageInfo.Parse(item);
Images.Add(imageInfo);
}
}
}
static const wchar_t *kStreamsNamePrefix = L"Files" WSTRING_PATH_SEPARATOR;
static const wchar_t *kMethodLZX = L"LZX";
static const wchar_t *kMethodXpress = L"XPress";
static const wchar_t *kMethodCopy = L"Copy";
IMP_IInArchive_Props
@@ -59,11 +163,57 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
const CImageInfo *image = NULL;
if (m_Xmls.Size() == 1)
{
const CXml &xml = m_Xmls[0];
if (xml.Images.Size() == 1)
image = &xml.Images[0];
}
switch(propID)
{
case kpidSize: prop = m_Database.GetUnpackSize(); break;
case kpidPackedSize: prop = m_Database.GetPackSize(); break;
case kpidIsVolume:
case kpidPackSize: prop = m_Database.GetPackSize(); break;
case kpidCTime:
if (m_Xmls.Size() == 1)
{
const CXml &xml = m_Xmls[0];
int index = -1;
for (int i = 0; i < xml.Images.Size(); i++)
{
const CImageInfo &image = xml.Images[i];
if (image.CTimeDefined)
if (index < 0 || ::CompareFileTime(&image.CTime, &xml.Images[index].CTime) < 0)
index = i;
}
if (index >= 0)
prop = xml.Images[index].CTime;
}
break;
case kpidMTime:
if (m_Xmls.Size() == 1)
{
const CXml &xml = m_Xmls[0];
int index = -1;
for (int i = 0; i < xml.Images.Size(); i++)
{
const CImageInfo &image = xml.Images[i];
if (image.MTimeDefined)
if (index < 0 || ::CompareFileTime(&image.MTime, &xml.Images[index].MTime) > 0)
index = i;
}
if (index >= 0)
prop = xml.Images[index].MTime;
}
break;
case kpidComment: if (image != NULL && image->NameDefined) prop = image->Name; break;
case kpidIsVolume:
if (m_Xmls.Size() > 0)
{
UInt16 volIndex = m_Xmls[0].VolIndex;
@@ -71,7 +221,7 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = (m_Volumes[volIndex].Header.NumParts > 1);
}
break;
case kpidVolume:
case kpidVolume:
if (m_Xmls.Size() > 0)
{
UInt16 volIndex = m_Xmls[0].VolIndex;
@@ -79,7 +229,39 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = (UInt32)m_Volumes[volIndex].Header.PartNumber;
}
break;
case kpidNumVolumes: if (m_Volumes.Size() > 0) prop = (UInt32)(m_Volumes.Size() - 1);
case kpidNumVolumes: if (m_Volumes.Size() > 0) prop = (UInt32)(m_Volumes.Size() - 1); break;
case kpidMethod:
{
bool lzx = false, xpress = false, copy = false;
for (int i = 0; i < m_Xmls.Size(); i++)
{
const CVolume &vol = m_Volumes[m_Xmls[i].VolIndex];
const CHeader &header = vol.Header;
if (header.IsCompressed())
if (header.IsLzxMode())
lzx = true;
else
xpress = true;
else
copy = true;
}
UString res;
if (lzx)
res = kMethodLZX;
if (xpress)
{
if (!res.IsEmpty())
res += L' ';
res += kMethodXpress;
}
if (copy)
{
if (!res.IsEmpty())
res += L' ';
res += kMethodCopy;
}
prop = res;
}
}
prop.Detach(value);
return S_OK;
@@ -94,8 +276,12 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
const CItem &item = m_Database.Items[index];
const CStreamInfo *si = NULL;
const CVolume *vol = NULL;
if (item.StreamIndex >= 0)
{
si = &m_Database.Streams[item.StreamIndex];
vol = &m_Volumes[si->PartNumber];
}
switch(propID)
{
@@ -114,59 +300,19 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
break;
}
break;
case kpidIsFolder:
prop = item.IsDirectory();
break;
case kpidAttributes:
if (item.HasMetadata)
prop = item.Attributes;
break;
case kpidCreationTime:
if (item.HasMetadata)
prop = item.CreationTime;
break;
case kpidLastAccessTime:
if (item.HasMetadata)
prop = item.LastAccessTime;
break;
case kpidLastWriteTime:
if (item.HasMetadata)
prop = item.LastWriteTime;
break;
case kpidPackedSize:
if (si)
prop = si->Resource.PackSize;
else
prop = (UInt64)0;
break;
case kpidSize:
if (si)
prop = si->Resource.UnpackSize;
else
prop = (UInt64)0;
break;
case kpidMethod:
if (si)
if (si->Resource.IsCompressed())
prop = kMethodLZX;
else
prop = kMethodCopy;
break;
case kpidIsDir: prop = item.isDir(); break;
case kpidAttrib: if (item.HasMetadata) prop = item.Attrib; break;
case kpidCTime: if (item.HasMetadata) prop = item.CTime; break;
case kpidATime: if (item.HasMetadata) prop = item.ATime; break;
case kpidMTime: if (item.HasMetadata) prop = item.MTime; break;
case kpidPackSize: prop = si ? si->Resource.PackSize : (UInt64)0; break;
case kpidSize: prop = si ? si->Resource.UnpackSize : (UInt64)0; break;
case kpidMethod: if (si) prop = si->Resource.IsCompressed() ?
(vol->Header.IsLzxMode() ? kMethodLZX : kMethodXpress) : kMethodCopy; break;
#ifdef WIM_DETAILS
case kpidVolume:
if (si)
prop = (UInt32)si->PartNumber;
break;
case kpidOffset:
if (si)
prop = (UInt64)si->Resource.Offset;
break;
case kpidLinks:
if (si)
prop = (UInt32)si->RefCount;
else
prop = (UInt64)0;
break;
case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break;
case kpidOffset: if (si) prop = (UInt64)si->Resource.Offset; break;
case kpidLinks: prop = si ? (UInt32)si->RefCount : (UInt32)0; break;
#endif
}
}
@@ -184,16 +330,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop = s;
break;
}
case kpidIsFolder:
prop = false;
break;
case kpidPackedSize:
case kpidSize:
prop = (UInt64)m_Xmls[index].Data.GetCapacity();
break;
case kpidMethod:
prop = L"Copy";
break;
case kpidIsDir: prop = false; break;
case kpidPackSize:
case kpidSize: prop = (UInt64)m_Xmls[index].Data.GetCapacity(); break;
case kpidMethod: prop = L"Copy"; break;
}
}
}
@@ -206,7 +346,7 @@ class CVolumeName
{
// UInt32 _volIndex;
UString _before;
UString _after;
UString _after;
public:
CVolumeName() {};
@@ -228,7 +368,7 @@ public:
}
};
STDMETHODIMP CHandler::Open(IInStream *inStream,
STDMETHODIMP CHandler::Open(IInStream *inStream,
const UInt64 * /* maxCheckStartPosition */,
IArchiveOpenCallback *openArchiveCallback)
{
@@ -300,7 +440,10 @@ STDMETHODIMP CHandler::Open(IInStream *inStream,
if (xml.Data == m_Xmls[0].Data)
needAddXml = false;
if (needAddXml)
{
xml.Parse();
m_Xmls.Add(xml);
}
if (i == 1)
{
@@ -398,7 +541,7 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
RINOK(lps->SetCur());
UInt32 index = allFilesMode ? i : indices[i];
i++;
Int32 askMode = testMode ?
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
@@ -428,7 +571,7 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
continue;
RINOK(extractCallback->PrepareOperation(askMode));
realOutStream.Release();
RINOK(extractCallback->SetOperationResult(item.HasStream() ?
RINOK(extractCallback->SetOperationResult(item.HasStream() ?
NExtract::NOperationResult::kDataError :
NExtract::NOperationResult::kOK));
continue;
@@ -445,7 +588,9 @@ STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
if (streamIndex != prevSuccessStreamIndex || realOutStream)
{
Byte digest[20];
HRESULT res = unpacker.Unpack(m_Volumes[si.PartNumber].Stream, si.Resource, realOutStream, progress, digest);
const CVolume &vol = m_Volumes[si.PartNumber];
HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header.IsLzxMode(),
realOutStream, progress, digest);
if (res == S_OK)
{
if (memcmp(digest, si.Hash, kHashSize) == 0)

View File

@@ -4,6 +4,8 @@
#define __ARCHIVE_WIM_HANDLER_H
#include "Common/MyCom.h"
#include "Common/MyXml.h"
#include "../IArchive.h"
#include "WimIn.h"
@@ -16,13 +18,35 @@ struct CVolume
CMyComPtr<IInStream> Stream;
};
struct CImageInfo
{
bool CTimeDefined;
bool MTimeDefined;
bool NameDefined;
// bool IndexDefined;
FILETIME CTime;
FILETIME MTime;
UString Name;
// UInt32 Index;
CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false)
// , IndexDefined(false)
{}
void Parse(const CXmlItem &item);
};
struct CXml
{
CByteBuffer Data;
UInt16 VolIndex;
CObjectVector<CImageInfo> Images;
void Parse();
};
class CHandler:
class CHandler:
public IInArchive,
public CMyUnknownImp
{

View File

@@ -15,19 +15,127 @@
#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);
static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
namespace NXpress {
class CDecoderFlusher
{
ft->dwLowDateTime = GetUi32(p);
ft->dwHighDateTime = GetUi32(p + 4);
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;
}
HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource,
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));
@@ -64,7 +172,7 @@ HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource,
RINOK(ReadStream_FALSE(inStream, (Byte *)sizesBuf, sizesBufSize));
const Byte *p = (const Byte *)sizesBuf;
if (!lzxDecoder)
if (lzxMode && !lzxDecoder)
{
lzxDecoderSpec = new NCompress::NLzx::CDecoder(true);
lzxDecoder = lzxDecoderSpec;
@@ -78,18 +186,12 @@ HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource,
UInt64 offset = 0;
if (i > 0)
{
if (entrySize == 4)
offset = GetUi32(p);
else
offset = GetUi64(p);
offset = (entrySize == 4) ? Get32(p): Get64(p);
p += entrySize;
}
UInt64 nextOffset = resource.PackSize - sizesBufSize64;
if (i + 1 < (UInt32)numChunks)
if (entrySize == 4)
nextOffset = GetUi32(p);
else
nextOffset = GetUi64(p);
nextOffset = (entrySize == 4) ? Get32(p): Get64(p);
if (nextOffset < offset)
return S_FALSE;
@@ -106,28 +208,41 @@ HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource,
if (outProcessed + outSize > resource.UnpackSize)
outSize = (UInt32)(resource.UnpackSize - outProcessed);
UInt64 outSize64 = outSize;
lzxDecoderSpec->SetKeepHistory(false);
ICompressCoder *coder = (inSize == outSize) ? copyCoder : lzxDecoder;
RINOK(coder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
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,
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, shaStream, progress);
HRESULT result = Unpack(inStream, resource, lzxMode, shaStream, progress);
if (digest)
shaStreamSpec->Final(digest);
return result;
}
static HRESULT UnpackData(IInStream *inStream, const CResource &resource, CByteBuffer &buf, Byte *digest)
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)
@@ -140,29 +255,31 @@ static HRESULT UnpackData(IInStream *inStream, const CResource &resource, CByteB
outStreamSpec->Init((Byte *)buf, size);
CUnpacker unpacker;
return unpacker.Unpack(inStream, resource, outStream, NULL, digest);
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 };
static void GetResource(const Byte *p, CResource &res)
void CResource::Parse(const Byte *p)
{
res.Flags = p[7];
res.PackSize = GetUi64(p) & (((UInt64)1 << 56) - 1);
res.Offset = GetUi64(p + 8);
res.UnpackSize = GetUi64(p + 16);
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)
{
GetResource(p, s.Resource);
s.PartNumber = GetUi16(p + 24);
s.RefCount = GetUi32(p + 26);
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,
static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size,
const UString &prefix, CObjectVector<CItem> &items)
{
for (;;)
@@ -170,22 +287,22 @@ static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size,
if (pos + 8 > size)
return S_FALSE;
const Byte *p = base + pos;
UInt64 length = GetUi64(p);
UInt64 length = Get64(p);
if (length == 0)
return S_OK;
if (pos + 102 > size || pos + length + 8 > size || length > ((UInt64)1 << 62))
return S_FALSE;
CItem item;
item.Attributes = GetUi32(p + 8);
// item.SecurityId = GetUi32(p + 0xC);
UInt64 subdirOffset = GetUi64(p + 0x10);
GetFileTimeFromMem(p + 0x28, &item.CreationTime);
GetFileTimeFromMem(p + 0x30, &item.LastAccessTime);
GetFileTimeFromMem(p + 0x38, &item.LastWriteTime);
item.Attrib = Get32(p + 8);
// item.SecurityId = Get32(p + 0xC);
UInt64 subdirOffset = Get64(p + 0x10);
GetFileTimeFromMem(p + 0x28, &item.CTime);
GetFileTimeFromMem(p + 0x30, &item.ATime);
GetFileTimeFromMem(p + 0x38, &item.MTime);
memcpy(item.Hash, p + 0x40, kHashSize);
// UInt16 shortNameLen = GetUi16(p + 98);
UInt16 fileNameLen = GetUi16(p + 100);
// UInt16 shortNameLen = Get16(p + 98);
UInt16 fileNameLen = Get16(p + 100);
size_t tempPos = pos + 102;
if (tempPos + fileNameLen > size)
@@ -195,17 +312,17 @@ static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size,
MyStringCopy(sz, (const wchar_t *)prefix);
sz += prefix.Length();
for (UInt16 i = 0; i + 2 <= fileNameLen; i += 2)
*sz++ = GetUi16(base + tempPos + i);
*sz++ = Get16(base + tempPos + i);
*sz++ = '\0';
item.Name.ReleaseBuffer();
if (fileNameLen == 0 && item.IsDirectory() && !item.HasStream())
if (fileNameLen == 0 && item.isDir() && !item.HasStream())
{
item.Attributes = 0x10; // some swm archives have system/hidden attributes for root
item.Attrib = 0x10; // some swm archives have system/hidden attributes for root
item.Name.Delete(item.Name.Length() - 1);
}
items.Add(item);
pos += (size_t)length;
if (item.IsDirectory() && (subdirOffset != 0))
if (item.isDir() && (subdirOffset != 0))
{
if (subdirOffset >= size)
return S_FALSE;
@@ -214,15 +331,15 @@ static HRESULT ParseDirItem(const Byte *base, size_t pos, size_t size,
}
}
static HRESULT ParseDir(const Byte *base, size_t size,
static HRESULT ParseDir(const Byte *base, size_t size,
const UString &prefix, CObjectVector<CItem> &items)
{
size_t pos = 0;
size_t pos = 0;
if (pos + 8 > size)
return S_FALSE;
const Byte *p = base + pos;
UInt32 totalLength = GetUi32(p);
// UInt32 numEntries = GetUi32(p + 4);
UInt32 totalLength = Get32(p);
// UInt32 numEntries = Get32(p + 4);
pos += 8;
{
/*
@@ -232,7 +349,7 @@ static HRESULT ParseDir(const Byte *base, size_t size,
{
if (pos + 8 > size)
return S_FALSE;
UInt64 len = GetUi64(p + pos);
UInt64 len = Get64(p + pos);
entryLens.Add(len);
sum += len;
pos += 8;
@@ -267,9 +384,9 @@ int CompareItems(void *const *a1, void *const *a2, void * /* param */)
const CItem &i1 = **((const CItem **)a1);
const CItem &i2 = **((const CItem **)a2);
if (i1.IsDirectory() != i2.IsDirectory())
return (i1.IsDirectory()) ? 1 : -1;
if (i1.IsDirectory())
if (i1.isDir() != i2.isDir())
return (i1.isDir()) ? 1 : -1;
if (i1.isDir())
return -MyStringCompareNoCase(i1.Name, i2.Name);
int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
@@ -278,10 +395,10 @@ int CompareItems(void *const *a1, void *const *a2, void * /* param */)
return MyStringCompareNoCase(i1.Name, i2.Name);
}
static int FindHash(const CRecordVector<CStreamInfo> &streams,
static int FindHash(const CRecordVector<CStreamInfo> &streams,
const CRecordVector<int> &sortedByHash, const Byte *hash)
{
int left = 0, right = streams.Size();
int left = 0, right = streams.Size();
while (left != right)
{
int mid = (left + right) / 2;
@@ -301,50 +418,56 @@ static int FindHash(const CRecordVector<CStreamInfo> &streams,
return -1;
}
HRESULT ReadHeader(IInStream *inStream, CHeader &h)
HRESULT CHeader::Parse(const Byte *p)
{
const UInt32 kHeaderSizeMax = 0xD0;
Byte p[kHeaderSizeMax];
RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
UInt32 haderSize = GetUi32(p + 8);
if (memcmp(p, kSignature, kSignatureSize) != 0)
return S_FALSE;
UInt32 haderSize = Get32(p + 8);
if (haderSize < 0x74)
return S_FALSE;
h.Version = GetUi32(p + 0x0C);
h.Flags = GetUi32(p + 0x10);
if (!h.IsSupported())
Version = Get32(p + 0x0C);
Flags = Get32(p + 0x10);
if (!IsSupported())
return S_FALSE;
if (GetUi32(p + 0x14) != kChunkSize)
UInt32 chunkSize = Get32(p + 0x14);
if (chunkSize != kChunkSize && chunkSize != 0)
return S_FALSE;
memcpy(h.Guid, p + 0x18, 16);
h.PartNumber = GetUi16(p + 0x28);
h.NumParts = GetUi16(p + 0x2A);
memcpy(Guid, p + 0x18, 16);
PartNumber = Get16(p + 0x28);
NumParts = Get16(p + 0x2A);
int offset = 0x2C;
if (h.IsNewVersion())
if (IsNewVersion())
{
h.NumImages = GetUi32(p + offset);
NumImages = Get32(p + offset);
offset += 4;
}
GetResource(p + offset, h.OffsetResource);
GetResource(p + offset + 0x18, h.XmlResource);
GetResource(p + offset + 0x30, h.MetadataResource);
GetResource(p + offset, OffsetResource);
GetResource(p + offset + 0x18, XmlResource);
GetResource(p + offset + 0x30, MetadataResource);
/*
if (h.IsNewVersion())
if (IsNewVersion())
{
if (haderSize < 0xD0)
return S_FALSE;
GetResource(p + offset + 0x4C, h.IntegrityResource);
h.BootIndex = GetUi32(p + 0x48);
IntegrityResource.Parse(p + offset + 0x4C);
BootIndex = Get32(p + 0x48);
}
*/
return S_OK;
}
HRESULT ReadHeader(IInStream *inStream, CHeader &h)
{
const UInt32 kHeaderSizeMax = 0xD0;
Byte p[kHeaderSizeMax];
RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax));
if (memcmp(p, kSignature, kSignatureSize) != 0)
return S_FALSE;
return h.Parse(p);
}
HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
{
CByteBuffer offsetBuf;
RINOK(UnpackData(inStream, h.OffsetResource, offsetBuf, NULL));
RINOK(UnpackData(inStream, h.OffsetResource, h.IsLzxMode(), offsetBuf, NULL));
for (size_t i = 0; i + kStreamInfoSize <= offsetBuf.GetCapacity(); i += kStreamInfoSize)
{
CStreamInfo s;
@@ -357,7 +480,7 @@ HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDatabase &db)
{
RINOK(UnpackData(inStream, h.XmlResource, xml, NULL));
RINOK(UnpackData(inStream, h.XmlResource, h.IsLzxMode(), xml, NULL));
RINOK(ReadStreams(inStream, h, db));
bool needBootMetadata = !h.MetadataResource.IsEmpty();
@@ -372,13 +495,13 @@ HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDa
continue;
Byte hash[kHashSize];
CByteBuffer metadata;
RINOK(UnpackData(inStream, si.Resource, metadata, hash));
RINOK(UnpackData(inStream, si.Resource, h.IsLzxMode(), metadata, hash));
if (memcmp(hash, si.Hash, kHashSize) != 0)
return S_FALSE;
wchar_t sz[32];
ConvertUInt64ToString(imageIndex++, sz);
UString s = sz;
s += WCHAR_PATH_SEPARATOR;
s += WCHAR_PATH_SEPARATOR;
RINOK(ParseDir(metadata, metadata.GetCapacity(), s, db.Items));
if (needBootMetadata)
if (h.MetadataResource.Offset == si.Resource.Offset)
@@ -389,7 +512,7 @@ HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDa
if (needBootMetadata)
{
CByteBuffer metadata;
RINOK(UnpackData(inStream, h.MetadataResource, metadata, NULL));
RINOK(UnpackData(inStream, h.MetadataResource, h.IsLzxMode(), metadata, NULL));
RINOK(ParseDir(metadata, metadata.GetCapacity(), L"0" WSTRING_PATH_SEPARATOR, db.Items));
}
return S_OK;

View File

@@ -12,6 +12,77 @@
namespace NArchive {
namespace NWim {
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 ReleaseStream() { m_Stream.ReleaseStream(); }
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 int 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:
void ReleaseStreams()
{
m_OutWindowStream.ReleaseStream();
m_InBitStream.ReleaseStream();
}
HRESULT Flush() { return m_OutWindowStream.Flush(); }
HRESULT Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt32 outSize);
};
}
namespace NResourceFlags
{
const Byte Compressed = 4;
@@ -24,6 +95,8 @@ struct CResource
UInt64 Offset;
UInt64 UnpackSize;
Byte Flags;
void Parse(const Byte *p);
bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; }
bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
bool IsEmpty() const { return (UnpackSize == 0); }
@@ -47,6 +120,7 @@ struct CHeader
UInt16 NumParts;
UInt32 NumImages;
Byte Guid[16];
CResource OffsetResource;
CResource XmlResource;
CResource MetadataResource;
@@ -54,8 +128,11 @@ struct CHeader
CResource IntegrityResource;
UInt32 BootIndex;
*/
HRESULT Parse(const Byte *p);
bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; }
bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 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 IsNewVersion()const { return (Version > 0x010C00); }
@@ -80,12 +157,12 @@ struct CStreamInfo
struct CItem
{
UString Name;
UInt32 Attributes;
UInt32 Attrib;
// UInt32 SecurityId;
BYTE Hash[kHashSize];
FILETIME CreationTime;
FILETIME LastAccessTime;
FILETIME LastWriteTime;
FILETIME CTime;
FILETIME ATime;
FILETIME MTime;
// UInt32 ReparseTag;
// UInt64 HardLink;
// UInt16 NumStreams;
@@ -93,9 +170,9 @@ struct CItem
int StreamIndex;
bool HasMetadata;
CItem(): HasMetadata(true), StreamIndex(-1) {}
bool IsDirectory() const { return HasMetadata && ((Attributes & 0x10) != 0); }
bool HasStream() const
{
bool isDir() const { return HasMetadata && ((Attrib & 0x10) != 0); }
bool HasStream() const
{
for (int i = 0; i < kHashSize; i++)
if (Hash[i] != 0)
return true;
@@ -143,11 +220,13 @@ class CUnpacker
NCompress::NLzx::CDecoder *lzxDecoderSpec;
CMyComPtr<ICompressCoder> lzxDecoder;
NXpress::CDecoder xpressDecoder;
CByteBuffer sizesBuf;
HRESULT Unpack(IInStream *inStream, const CResource &res,
HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress);
public:
HRESULT Unpack(IInStream *inStream, const CResource &res,
HRESULT Unpack(IInStream *inStream, const CResource &res, bool lzxMode,
ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest);
};

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB