mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 13:15:04 -06:00
4.49 beta
This commit is contained in:
committed by
Kornel Lesiński
parent
fd8b1d78b4
commit
7038848692
@@ -45,11 +45,11 @@ STDMETHODIMP CCoderMixerMT::Code(ISequentialInStream *inStream,
|
||||
RINOK(_coders[i].Create());
|
||||
}
|
||||
|
||||
while (_streamBinders.Size() + 1 < _coders.Size())
|
||||
_streamBinders.Clear();
|
||||
for (i = 0; i + 1 < _coders.Size(); i++)
|
||||
{
|
||||
_streamBinders.Add(CStreamBinder());
|
||||
int i = _streamBinders.Size() - 1;
|
||||
CStreamBinder &sb = _streamBinders.Back();
|
||||
CStreamBinder &sb = _streamBinders[i];
|
||||
RINOK(sb.CreateEvents());
|
||||
sb.CreateStreams(&_coders[i + 1].InStream, &_coders[i].OutStream);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#ifndef __CODER_MIXER_MT_H
|
||||
#define __CODER_MIXER_MT_H
|
||||
|
||||
#include "../../../Common/Vector.h"
|
||||
#include "../../../Common/MyVector.h"
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../ICoder.h"
|
||||
#include "../../Common/StreamBinder.h"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "OutStreamWithCRC.h"
|
||||
|
||||
STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result;
|
||||
@@ -15,7 +15,7 @@ STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *pr
|
||||
}
|
||||
else
|
||||
result = _stream->Write(data, size, &realProcessedSize);
|
||||
if (_calculateCrc)
|
||||
if (_calculate)
|
||||
_crc = CrcUpdate(_crc, data, realProcessedSize);
|
||||
_size += realProcessedSize;
|
||||
if(processedSize != NULL)
|
||||
|
||||
@@ -15,27 +15,24 @@ class COutStreamWithCRC:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
private:
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt64 _size;
|
||||
UInt32 _crc;
|
||||
bool _calculateCrc;
|
||||
bool _calculate;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
|
||||
void Init(bool calculateCrc = true)
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init(bool calculate = true)
|
||||
{
|
||||
_size = 0;
|
||||
_calculateCrc = calculateCrc;
|
||||
_calculate = calculate;
|
||||
_crc = CRC_INIT_VAL;
|
||||
}
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void InitCRC() { _crc = CRC_INIT_VAL; }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
|
||||
void InitCRC() { _crc = CRC_INIT_VAL; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
24
CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
Executable file
24
CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
Executable file
@@ -0,0 +1,24 @@
|
||||
// OutStreamWithSha1.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "OutStreamWithSha1.h"
|
||||
|
||||
STDMETHODIMP COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
HRESULT result;
|
||||
if(!_stream)
|
||||
{
|
||||
realProcessedSize = size;
|
||||
result = S_OK;
|
||||
}
|
||||
else
|
||||
result = _stream->Write(data, size, &realProcessedSize);
|
||||
if (_calculate)
|
||||
_sha.Update((const Byte *)data, realProcessedSize);
|
||||
_size += realProcessedSize;
|
||||
if(processedSize != NULL)
|
||||
*processedSize = realProcessedSize;
|
||||
return result;
|
||||
}
|
||||
38
CPP/7zip/Archive/Common/OutStreamWithSha1.h
Executable file
38
CPP/7zip/Archive/Common/OutStreamWithSha1.h
Executable file
@@ -0,0 +1,38 @@
|
||||
// OutStreamWithSha1.h
|
||||
|
||||
#ifndef __OUTSTREAMWITHSHA1_H
|
||||
#define __OUTSTREAMWITHSHA1_H
|
||||
|
||||
#include "../../../Common/MyCom.h"
|
||||
#include "../../IStream.h"
|
||||
|
||||
|
||||
|
||||
#include "../../Crypto/Hash/Sha1.h"
|
||||
|
||||
|
||||
class COutStreamWithSha1:
|
||||
public ISequentialOutStream,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
CMyComPtr<ISequentialOutStream> _stream;
|
||||
UInt64 _size;
|
||||
NCrypto::NSha1::CContext _sha;
|
||||
bool _calculate;
|
||||
public:
|
||||
MY_UNKNOWN_IMP
|
||||
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
||||
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
|
||||
void ReleaseStream() { _stream.Release(); }
|
||||
void Init(bool calculate = true)
|
||||
{
|
||||
_size = 0;
|
||||
_calculate = calculate;
|
||||
_sha.Init();
|
||||
}
|
||||
void InitSha1() { _sha.Init(); }
|
||||
UInt64 GetSize() const { return _size; }
|
||||
void Final(Byte *digest) { _sha.Final(digest); }
|
||||
};
|
||||
|
||||
#endif
|
||||
8
CPP/7zip/Archive/Wim/StdAfx.h
Executable file
8
CPP/7zip/Archive/Wim/StdAfx.h
Executable file
@@ -0,0 +1,8 @@
|
||||
// StdAfx.h
|
||||
|
||||
#ifndef __STDAFX_H
|
||||
#define __STDAFX_H
|
||||
|
||||
#include "../../../Common/MyWindows.h"
|
||||
|
||||
#endif
|
||||
477
CPP/7zip/Archive/Wim/WimHandler.cpp
Executable file
477
CPP/7zip/Archive/Wim/WimHandler.cpp
Executable file
@@ -0,0 +1,477 @@
|
||||
// WimHandler.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "Common/IntToString.h"
|
||||
#include "Common/Defs.h"
|
||||
#include "Common/ComTry.h"
|
||||
|
||||
#include "Windows/PropVariant.h"
|
||||
|
||||
#include "../../Common/StreamUtils.h"
|
||||
#include "../../Common/ProgressUtils.h"
|
||||
|
||||
#include "WimHandler.h"
|
||||
|
||||
using namespace NWindows;
|
||||
|
||||
namespace NArchive {
|
||||
namespace NWim {
|
||||
|
||||
#define WIM_DETAILS
|
||||
|
||||
#ifdef WIM_DETAILS
|
||||
|
||||
enum
|
||||
{
|
||||
kpidVolume = kpidUserDefined,
|
||||
kpidOffset,
|
||||
kpidLinks
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
STATPROPSTG kProperties[] =
|
||||
{
|
||||
{ NULL, kpidPath, VT_BSTR},
|
||||
{ NULL, kpidIsFolder, VT_BOOL},
|
||||
{ NULL, kpidSize, VT_UI8},
|
||||
{ NULL, kpidPackedSize, VT_UI8},
|
||||
{ NULL, kpidAttributes, VT_UI8},
|
||||
{ NULL, kpidMethod, VT_BSTR},
|
||||
{ NULL, kpidCreationTime, VT_FILETIME},
|
||||
{ NULL, kpidLastAccessTime, VT_FILETIME},
|
||||
{ NULL, kpidLastWriteTime, VT_FILETIME}
|
||||
|
||||
#ifdef WIM_DETAILS
|
||||
, { L"Volume", kpidVolume, VT_UI4}
|
||||
, { L"Offset", kpidOffset, VT_UI8}
|
||||
, { L"Links", kpidLinks, VT_UI4}
|
||||
#endif
|
||||
};
|
||||
|
||||
static const wchar_t *kStreamsNamePrefix = L"Files" WSTRING_PATH_SEPARATOR;
|
||||
static const wchar_t *kMethodLZX = L"LZX";
|
||||
static const wchar_t *kMethodCopy = L"Copy";
|
||||
|
||||
STDMETHODIMP CHandler::GetArchiveProperty(PROPID /* propID */, PROPVARIANT *value)
|
||||
{
|
||||
value->vt = VT_EMPTY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties)
|
||||
{
|
||||
*numProperties = sizeof(kProperties) / sizeof(kProperties[0]);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType)
|
||||
{
|
||||
if(index >= sizeof(kProperties) / sizeof(kProperties[0]))
|
||||
return E_INVALIDARG;
|
||||
const STATPROPSTG &srcItem = kProperties[index];
|
||||
*propID = srcItem.propid;
|
||||
*varType = srcItem.vt;
|
||||
if (srcItem.lpwstrName == 0)
|
||||
*name = 0;
|
||||
else
|
||||
*name = ::SysAllocString(srcItem.lpwstrName);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties)
|
||||
{
|
||||
*numProperties = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 /* index */,
|
||||
BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
|
||||
{
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
NWindows::NCOM::CPropVariant propVariant;
|
||||
if (index < (UInt32)m_Database.Items.Size())
|
||||
{
|
||||
const CItem &item = m_Database.Items[index];
|
||||
const CStreamInfo *si = NULL;
|
||||
if (item.StreamIndex >= 0)
|
||||
si = &m_Database.Streams[item.StreamIndex];
|
||||
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
if (item.HasMetadata)
|
||||
propVariant = item.Name;
|
||||
else
|
||||
{
|
||||
wchar_t sz[32];
|
||||
ConvertUInt64ToString(item.StreamIndex, sz);
|
||||
UString s = sz;
|
||||
while (s.Length() < m_NameLenForStreams)
|
||||
s = L'0' + s;
|
||||
s = UString(kStreamsNamePrefix) + s;
|
||||
propVariant = s;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kpidIsFolder:
|
||||
propVariant = item.IsDirectory();
|
||||
break;
|
||||
case kpidAttributes:
|
||||
if (item.HasMetadata)
|
||||
propVariant = item.Attributes;
|
||||
break;
|
||||
case kpidCreationTime:
|
||||
if (item.HasMetadata)
|
||||
propVariant = item.CreationTime;
|
||||
break;
|
||||
case kpidLastAccessTime:
|
||||
if (item.HasMetadata)
|
||||
propVariant = item.LastAccessTime;
|
||||
break;
|
||||
case kpidLastWriteTime:
|
||||
if (item.HasMetadata)
|
||||
propVariant = item.LastWriteTime;
|
||||
break;
|
||||
case kpidPackedSize:
|
||||
if (si)
|
||||
propVariant = si->Resource.PackSize;
|
||||
else
|
||||
propVariant = (UInt64)0;
|
||||
break;
|
||||
case kpidSize:
|
||||
if (si)
|
||||
propVariant = si->Resource.UnpackSize;
|
||||
else
|
||||
propVariant = (UInt64)0;
|
||||
break;
|
||||
case kpidMethod:
|
||||
if (si)
|
||||
if (si->Resource.IsCompressed())
|
||||
propVariant = kMethodLZX;
|
||||
else
|
||||
propVariant = kMethodCopy;
|
||||
break;
|
||||
#ifdef WIM_DETAILS
|
||||
case kpidVolume:
|
||||
if (si)
|
||||
propVariant = (UInt32)si->PartNumber;
|
||||
break;
|
||||
case kpidOffset:
|
||||
if (si)
|
||||
propVariant = (UInt64)si->Resource.Offset;
|
||||
break;
|
||||
case kpidLinks:
|
||||
if (si)
|
||||
propVariant = (UInt32)si->RefCount;
|
||||
else
|
||||
propVariant = (UInt64)0;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= m_Database.Items.Size();
|
||||
{
|
||||
switch(propID)
|
||||
{
|
||||
case kpidPath:
|
||||
{
|
||||
wchar_t sz[32];
|
||||
ConvertUInt64ToString(m_Xmls[index].VolIndex, sz);
|
||||
UString s = (UString)sz + L".xml";
|
||||
propVariant = s;
|
||||
break;
|
||||
}
|
||||
case kpidIsFolder:
|
||||
propVariant = false;
|
||||
break;
|
||||
case kpidPackedSize:
|
||||
case kpidSize:
|
||||
propVariant = (UInt64)m_Xmls[index].Data.GetCapacity();
|
||||
break;
|
||||
case kpidMethod:
|
||||
propVariant = L"Copy";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
propVariant.Detach(value);
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
class CVolumeName
|
||||
{
|
||||
// UInt32 _volIndex;
|
||||
UString _before;
|
||||
UString _after;
|
||||
public:
|
||||
CVolumeName() {};
|
||||
|
||||
void InitName(const UString &name)
|
||||
{
|
||||
// _volIndex = 1;
|
||||
int dotPos = name.ReverseFind('.');
|
||||
if (dotPos < 0)
|
||||
dotPos = name.Length();
|
||||
_before = name.Left(dotPos);
|
||||
_after = name.Mid(dotPos);
|
||||
}
|
||||
|
||||
UString GetNextName(UInt32 index)
|
||||
{
|
||||
wchar_t s[32];
|
||||
ConvertUInt64ToString((index), s);
|
||||
return _before + (UString)s + _after;
|
||||
}
|
||||
};
|
||||
|
||||
STDMETHODIMP CHandler::Open(IInStream *inStream,
|
||||
const UInt64 * /* maxCheckStartPosition */,
|
||||
IArchiveOpenCallback *openArchiveCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
Close();
|
||||
try
|
||||
{
|
||||
CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
|
||||
|
||||
CVolumeName seqName;
|
||||
if (openArchiveCallback != NULL)
|
||||
openArchiveCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
|
||||
|
||||
UInt32 numVolumes = 1;
|
||||
int firstVolumeIndex = -1;
|
||||
for (UInt32 i = 1; i <= numVolumes; i++)
|
||||
{
|
||||
CMyComPtr<IInStream> curStream;
|
||||
if (i != 1)
|
||||
{
|
||||
UString fullName = seqName.GetNextName(i);
|
||||
HRESULT result = openVolumeCallback->GetStream(fullName, &curStream);
|
||||
if (result == S_FALSE)
|
||||
continue;
|
||||
if (result != S_OK)
|
||||
return result;
|
||||
if (!curStream)
|
||||
break;
|
||||
}
|
||||
else
|
||||
curStream = inStream;
|
||||
CHeader header;
|
||||
HRESULT res = NWim::ReadHeader(curStream, header);
|
||||
if (res != S_OK)
|
||||
{
|
||||
if (i == 1)
|
||||
return res;
|
||||
if (res == S_FALSE)
|
||||
continue;
|
||||
return res;
|
||||
}
|
||||
if (firstVolumeIndex >= 0)
|
||||
if (!header.AreFromOnArchive(m_Volumes[firstVolumeIndex].Header))
|
||||
break;
|
||||
if (m_Volumes.Size() > header.PartNumber && m_Volumes[header.PartNumber].Stream)
|
||||
break;
|
||||
CXml xml;
|
||||
xml.VolIndex = header.PartNumber;
|
||||
res = OpenArchive(curStream, header, xml.Data, m_Database);
|
||||
if (res != S_OK)
|
||||
{
|
||||
if (i == 1)
|
||||
return res;
|
||||
if (res == S_FALSE)
|
||||
continue;
|
||||
return res;
|
||||
}
|
||||
|
||||
while (m_Volumes.Size() <= header.PartNumber)
|
||||
m_Volumes.Add(CVolume());
|
||||
CVolume &volume = m_Volumes[header.PartNumber];
|
||||
volume.Header = header;
|
||||
volume.Stream = curStream;
|
||||
|
||||
firstVolumeIndex = header.PartNumber;
|
||||
|
||||
bool needAddXml = true;
|
||||
if (m_Xmls.Size() != 0)
|
||||
if (xml.Data == m_Xmls[0].Data)
|
||||
needAddXml = false;
|
||||
if (needAddXml)
|
||||
m_Xmls.Add(xml);
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
if (header.PartNumber != 1)
|
||||
break;
|
||||
if (!openVolumeCallback)
|
||||
break;
|
||||
numVolumes = header.NumParts;
|
||||
{
|
||||
NCOM::CPropVariant propVariant;
|
||||
RINOK(openVolumeCallback->GetProperty(kpidName, &propVariant));
|
||||
if (propVariant.vt != VT_BSTR)
|
||||
break;
|
||||
seqName.InitName(propVariant.bstrVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RINOK(SortDatabase(m_Database));
|
||||
|
||||
wchar_t sz[32];
|
||||
ConvertUInt64ToString(m_Database.Streams.Size(), sz);
|
||||
m_NameLenForStreams = MyStringLen(sz);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return S_FALSE;
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Close()
|
||||
{
|
||||
m_Database.Clear();
|
||||
m_Volumes.Clear();
|
||||
m_Xmls.Clear();
|
||||
m_NameLenForStreams = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
|
||||
Int32 _aTestMode, IArchiveExtractCallback *extractCallback)
|
||||
{
|
||||
COM_TRY_BEGIN
|
||||
bool allFilesMode = (numItems == UInt32(-1));
|
||||
|
||||
if (allFilesMode)
|
||||
numItems = m_Database.Items.Size() + m_Xmls.Size();
|
||||
if (numItems == 0)
|
||||
return S_OK;
|
||||
bool testMode = (_aTestMode != 0);
|
||||
|
||||
UInt32 i;
|
||||
UInt64 totalSize = 0;
|
||||
for (i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
if (index < (UInt32)m_Database.Items.Size())
|
||||
{
|
||||
int streamIndex = m_Database.Items[index].StreamIndex;
|
||||
if (streamIndex >= 0)
|
||||
{
|
||||
const CStreamInfo &si = m_Database.Streams[streamIndex];
|
||||
totalSize += si.Resource.UnpackSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
totalSize += m_Xmls[index - (UInt32)m_Database.Items.Size()].Data.GetCapacity();
|
||||
}
|
||||
|
||||
RINOK(extractCallback->SetTotal(totalSize));
|
||||
|
||||
UInt64 currentTotalSize = 0;
|
||||
UInt64 currentItemSize = 0;
|
||||
|
||||
int prevSuccessStreamIndex = -1;
|
||||
|
||||
CUnpacker unpacker;
|
||||
|
||||
CLocalProgress *localProgressSpec = new CLocalProgress;
|
||||
CMyComPtr<ICompressProgressInfo> progress = localProgressSpec;
|
||||
localProgressSpec->Init(extractCallback, false);
|
||||
|
||||
CLocalCompressProgressInfo *localCompressProgressSpec = new CLocalCompressProgressInfo;
|
||||
CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
|
||||
|
||||
for (i = 0; i < numItems; currentTotalSize += currentItemSize)
|
||||
{
|
||||
currentItemSize = 0;
|
||||
RINOK(extractCallback->SetCompleted(¤tTotalSize));
|
||||
UInt32 index = allFilesMode ? i : indices[i];
|
||||
i++;
|
||||
Int32 askMode = testMode ?
|
||||
NArchive::NExtract::NAskMode::kTest :
|
||||
NArchive::NExtract::NAskMode::kExtract;
|
||||
|
||||
CMyComPtr<ISequentialOutStream> realOutStream;
|
||||
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
|
||||
if (index >= (UInt32)m_Database.Items.Size())
|
||||
{
|
||||
if(!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
const CByteBuffer &data = m_Xmls[index - (UInt32)m_Database.Items.Size()].Data;
|
||||
currentItemSize = data.GetCapacity();
|
||||
if (realOutStream)
|
||||
{
|
||||
RINOK(WriteStream(realOutStream, (const Byte *)data, (UInt32)data.GetCapacity(), NULL));
|
||||
realOutStream.Release();
|
||||
}
|
||||
RINOK(extractCallback->SetOperationResult(NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
const CItem &item = m_Database.Items[index];
|
||||
int streamIndex = item.StreamIndex;
|
||||
if (streamIndex < 0)
|
||||
{
|
||||
if(!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(item.HasStream() ?
|
||||
NArchive::NExtract::NOperationResult::kDataError :
|
||||
NArchive::NExtract::NOperationResult::kOK));
|
||||
continue;
|
||||
}
|
||||
|
||||
const CStreamInfo &si = m_Database.Streams[streamIndex];
|
||||
currentItemSize = si.Resource.UnpackSize;
|
||||
|
||||
if(!testMode && (!realOutStream))
|
||||
continue;
|
||||
RINOK(extractCallback->PrepareOperation(askMode));
|
||||
Int32 opRes = NArchive::NExtract::NOperationResult::kOK;
|
||||
if (streamIndex != prevSuccessStreamIndex || realOutStream)
|
||||
{
|
||||
Byte digest[20];
|
||||
localCompressProgressSpec->Init(progress, ¤tTotalSize, ¤tTotalSize);
|
||||
HRESULT res = unpacker.Unpack(m_Volumes[si.PartNumber].Stream, si.Resource, realOutStream, compressProgress, digest);
|
||||
if (res == S_OK)
|
||||
{
|
||||
if (memcmp(digest, si.Hash, kHashSize) == 0)
|
||||
prevSuccessStreamIndex = streamIndex;
|
||||
else
|
||||
opRes = NArchive::NExtract::NOperationResult::kCRCError;
|
||||
}
|
||||
else if (res == S_FALSE)
|
||||
opRes = NArchive::NExtract::NOperationResult::kDataError;
|
||||
else
|
||||
return res;
|
||||
}
|
||||
realOutStream.Release();
|
||||
RINOK(extractCallback->SetOperationResult(opRes));
|
||||
}
|
||||
return S_OK;
|
||||
COM_TRY_END
|
||||
}
|
||||
|
||||
STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
|
||||
{
|
||||
*numItems = m_Database.Items.Size() + m_Xmls.Size();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
60
CPP/7zip/Archive/Wim/WimHandler.h
Executable file
60
CPP/7zip/Archive/Wim/WimHandler.h
Executable file
@@ -0,0 +1,60 @@
|
||||
// WimHandler.h
|
||||
|
||||
#ifndef __ARCHIVE_WIM_HANDLER_H
|
||||
#define __ARCHIVE_WIM_HANDLER_H
|
||||
|
||||
#include "Common/MyCom.h"
|
||||
#include "../IArchive.h"
|
||||
#include "WimIn.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NWim {
|
||||
|
||||
struct CVolume
|
||||
{
|
||||
CHeader Header;
|
||||
CMyComPtr<IInStream> Stream;
|
||||
};
|
||||
|
||||
struct CXml
|
||||
{
|
||||
CByteBuffer Data;
|
||||
UInt16 VolIndex;
|
||||
};
|
||||
|
||||
class CHandler:
|
||||
public IInArchive,
|
||||
public CMyUnknownImp
|
||||
{
|
||||
public:
|
||||
MY_UNKNOWN_IMP1(IInArchive)
|
||||
|
||||
STDMETHOD(Open)(IInStream *stream,
|
||||
const UInt64 *maxCheckStartPosition,
|
||||
IArchiveOpenCallback *openArchiveCallback);
|
||||
STDMETHOD(Close)();
|
||||
STDMETHOD(GetNumberOfItems)(UInt32 *numItems);
|
||||
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
|
||||
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems,
|
||||
Int32 testMode, IArchiveExtractCallback *extractCallback);
|
||||
|
||||
STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value);
|
||||
|
||||
STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties);
|
||||
STDMETHOD(GetPropertyInfo)(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType);
|
||||
|
||||
STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties);
|
||||
STDMETHOD(GetArchivePropertyInfo)(UInt32 index,
|
||||
BSTR *name, PROPID *propID, VARTYPE *varType);
|
||||
|
||||
private:
|
||||
CDatabase m_Database;
|
||||
CObjectVector<CVolume> m_Volumes;
|
||||
CObjectVector<CXml> m_Xmls;
|
||||
int m_NameLenForStreams;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
467
CPP/7zip/Archive/Wim/WimIn.cpp
Executable file
467
CPP/7zip/Archive/Wim/WimIn.cpp
Executable file
@@ -0,0 +1,467 @@
|
||||
// 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 "WimIn.h"
|
||||
|
||||
namespace NArchive{
|
||||
namespace NWim{
|
||||
|
||||
static const int kChunkSizeBits = 15;
|
||||
static const UInt32 kChunkSize = (1 << kChunkSizeBits);
|
||||
|
||||
static HRESULT ReadBytes(ISequentialInStream *inStream, void *data, UInt32 size)
|
||||
{
|
||||
UInt32 realProcessedSize;
|
||||
RINOK(ReadStream(inStream, data, size, &realProcessedSize));
|
||||
return (realProcessedSize == size) ? S_OK : S_FALSE;
|
||||
}
|
||||
|
||||
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
|
||||
#define WIM_LITTLE_ENDIAN_UNALIGN
|
||||
#endif
|
||||
|
||||
#ifdef WIM_LITTLE_ENDIAN_UNALIGN
|
||||
static inline UInt16 GetUInt16FromMem(const Byte *p) { return *(const UInt16 *)p; }
|
||||
static inline UInt32 GetUInt32FromMem(const Byte *p) { return *(const UInt32 *)p; }
|
||||
static inline UInt64 GetUInt64FromMem(const Byte *p) { return *(const UInt64 *)p; }
|
||||
#else
|
||||
static UInt16 GetUInt16FromMem(const Byte *p) { return p[0] | ((UInt16)p[1] << 8); }
|
||||
static UInt32 GetUInt32FromMem(const Byte *p) { return p[0] | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16) | ((UInt32)p[3] << 24); }
|
||||
static UInt64 GetUInt64FromMem(const Byte *p) { return GetUInt32FromMem(p) | ((UInt64)GetUInt32FromMem(p + 4) << 32); }
|
||||
#endif
|
||||
|
||||
static void GetFileTimeFromMem(const Byte *p, FILETIME *ft)
|
||||
{
|
||||
ft->dwLowDateTime = GetUInt32FromMem(p);
|
||||
ft->dwHighDateTime = GetUInt32FromMem(p + 4);
|
||||
}
|
||||
|
||||
HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource,
|
||||
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);
|
||||
UInt32 sizesBufSize = (UInt32)sizesBufSize64;
|
||||
if (sizesBufSize != sizesBufSize64)
|
||||
return E_OUTOFMEMORY;
|
||||
if (sizesBufSize > sizesBuf.GetCapacity())
|
||||
{
|
||||
sizesBuf.Free();
|
||||
sizesBuf.SetCapacity(sizesBufSize);
|
||||
}
|
||||
RINOK(ReadBytes(inStream, (Byte *)sizesBuf, sizesBufSize));
|
||||
const Byte *p = (const Byte *)sizesBuf;
|
||||
|
||||
if (!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)
|
||||
{
|
||||
if (entrySize == 4)
|
||||
offset = GetUInt32FromMem(p);
|
||||
else
|
||||
offset = GetUInt64FromMem(p);
|
||||
p += entrySize;
|
||||
}
|
||||
UInt64 nextOffset = resource.PackSize - sizesBufSize64;
|
||||
if (i + 1 < (UInt32)numChunks)
|
||||
if (entrySize == 4)
|
||||
nextOffset = GetUInt32FromMem(p);
|
||||
else
|
||||
nextOffset = GetUInt64FromMem(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;
|
||||
lzxDecoderSpec->SetKeepHistory(false, 0);
|
||||
ICompressCoder *coder = (inSize == outSize) ? copyCoder : lzxDecoder;
|
||||
RINOK(coder->Code(limitedStreamSpec, outStream, NULL, &outSize64, NULL));
|
||||
outProcessed += outSize;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource,
|
||||
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);
|
||||
if (digest)
|
||||
shaStreamSpec->Final(digest);
|
||||
return result;
|
||||
}
|
||||
|
||||
static HRESULT UnpackData(IInStream *inStream, const CResource &resource, 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, 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)
|
||||
{
|
||||
res.Flags = p[7];
|
||||
res.PackSize = GetUInt64FromMem(p) & (((UInt64)1 << 56) - 1);
|
||||
res.Offset = GetUInt64FromMem(p + 8);
|
||||
res.UnpackSize = GetUInt64FromMem(p + 16);
|
||||
}
|
||||
|
||||
static void GetStream(const Byte *p, CStreamInfo &s)
|
||||
{
|
||||
GetResource(p, s.Resource);
|
||||
s.PartNumber = GetUInt16FromMem(p + 24);
|
||||
s.RefCount = GetUInt32FromMem(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 (;;)
|
||||
{
|
||||
if (pos + 8 > size)
|
||||
return S_FALSE;
|
||||
const Byte *p = base + pos;
|
||||
UInt64 length = GetUInt64FromMem(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 = GetUInt32FromMem(p + 8);
|
||||
// item.SecurityId = GetUInt32FromMem(p + 0xC);
|
||||
UInt64 subdirOffset = GetUInt64FromMem(p + 0x10);
|
||||
GetFileTimeFromMem(p + 0x28, &item.CreationTime);
|
||||
GetFileTimeFromMem(p + 0x30, &item.LastAccessTime);
|
||||
GetFileTimeFromMem(p + 0x38, &item.LastWriteTime);
|
||||
memcpy(item.Hash, p + 0x40, kHashSize);
|
||||
|
||||
// UInt16 shortNameLen = GetUInt16FromMem(p + 98);
|
||||
UInt16 fileNameLen = GetUInt16FromMem(p + 100);
|
||||
|
||||
size_t tempPos = pos + 102;
|
||||
if (tempPos + fileNameLen > size)
|
||||
return S_FALSE;
|
||||
|
||||
wchar_t *sz = item.Name.GetBuffer(prefix.Length() + fileNameLen / 2 + 1);
|
||||
MyStringCopy(sz, (const wchar_t *)prefix);
|
||||
sz += prefix.Length();
|
||||
for (UInt16 i = 0; i + 2 <= fileNameLen; i += 2)
|
||||
*sz++ = GetUInt16FromMem(base + tempPos + i);
|
||||
*sz++ = '\0';
|
||||
item.Name.ReleaseBuffer();
|
||||
if (fileNameLen == 0 && item.IsDirectory() && !item.HasStream())
|
||||
{
|
||||
item.Attributes = 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 (subdirOffset >= size)
|
||||
return S_FALSE;
|
||||
RINOK(ParseDirItem(base, (size_t)subdirOffset, size, item.Name + WCHAR_PATH_SEPARATOR, items));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT ParseDir(const Byte *base, size_t size,
|
||||
const UString &prefix, CObjectVector<CItem> &items)
|
||||
{
|
||||
size_t pos = 0;
|
||||
if (pos + 8 > size)
|
||||
return S_FALSE;
|
||||
const Byte *p = base + pos;
|
||||
UInt32 totalLength = GetUInt32FromMem(p);
|
||||
// UInt32 numEntries = GetUInt32FromMem(p + 4);
|
||||
pos += 8;
|
||||
{
|
||||
/*
|
||||
CRecordVector<UInt64> entryLens;
|
||||
UInt64 sum = 0;
|
||||
for (UInt32 i = 0; i < numEntries; i++)
|
||||
{
|
||||
if (pos + 8 > size)
|
||||
return S_FALSE;
|
||||
UInt64 len = GetUInt64FromMem(p + pos);
|
||||
entryLens.Add(len);
|
||||
sum += len;
|
||||
pos += 8;
|
||||
}
|
||||
pos += sum; // skeep security descriptors
|
||||
while ((pos & 7) != 0)
|
||||
pos++;
|
||||
if (pos != totalLength)
|
||||
return S_FALSE;
|
||||
*/
|
||||
pos = totalLength;
|
||||
}
|
||||
return ParseDirItem(base, pos, size, prefix, items);
|
||||
}
|
||||
|
||||
static int CompareHashRefs(const int *p1, const int *p2, void *param)
|
||||
{
|
||||
const CRecordVector<CStreamInfo> &streams = *(const CRecordVector<CStreamInfo> *)param;
|
||||
return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
|
||||
}
|
||||
|
||||
static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */)
|
||||
{
|
||||
int res = MyCompare(p1->PartNumber, p2->PartNumber);
|
||||
if (res != 0)
|
||||
return res;
|
||||
return MyCompare(p1->Resource.Offset, p2->Resource.Offset);
|
||||
}
|
||||
|
||||
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())
|
||||
return -MyStringCompareNoCase(i1.Name, i2.Name);
|
||||
|
||||
int res = MyCompare(i1.StreamIndex, i2.StreamIndex);
|
||||
if (res != 0)
|
||||
return res;
|
||||
return MyStringCompareNoCase(i1.Name, i2.Name);
|
||||
}
|
||||
|
||||
static int FindHash(const CRecordVector<CStreamInfo> &streams,
|
||||
const CRecordVector<int> &sortedByHash, const Byte *hash)
|
||||
{
|
||||
int left = 0, right = streams.Size();
|
||||
while (left != right)
|
||||
{
|
||||
int mid = (left + right) / 2;
|
||||
int streamIndex = sortedByHash[mid];
|
||||
UInt32 i;
|
||||
const Byte *hash2 = streams[streamIndex].Hash;
|
||||
for (i = 0; i < kHashSize; i++)
|
||||
if (hash[i] != hash2[i])
|
||||
break;
|
||||
if (i == kHashSize)
|
||||
return streamIndex;
|
||||
if (hash[i] < hash2[i])
|
||||
right = mid;
|
||||
else
|
||||
left = mid + 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
HRESULT ReadHeader(IInStream *inStream, CHeader &h)
|
||||
{
|
||||
const UInt32 kHeaderSizeMax = 0xD0;
|
||||
Byte p[kHeaderSizeMax];
|
||||
RINOK(ReadBytes(inStream, p, kHeaderSizeMax));
|
||||
UInt32 haderSize = GetUInt32FromMem(p + 8);
|
||||
if (memcmp(p, kSignature, kSignatureSize) != 0)
|
||||
return S_FALSE;
|
||||
if (haderSize < 0x74)
|
||||
return S_FALSE;
|
||||
h.Version = GetUInt32FromMem(p + 0x0C);
|
||||
h.Flags = GetUInt32FromMem(p + 0x10);
|
||||
if (!h.IsSupported())
|
||||
return S_FALSE;
|
||||
if (GetUInt32FromMem(p + 0x14) != kChunkSize)
|
||||
return S_FALSE;
|
||||
memcpy(h.Guid, p + 0x18, 16);
|
||||
h.PartNumber = GetUInt16FromMem(p + 0x28);
|
||||
h.NumParts = GetUInt16FromMem(p + 0x2A);
|
||||
int offset = 0x2C;
|
||||
if (h.IsNewVersion())
|
||||
{
|
||||
h.NumImages = GetUInt32FromMem(p + offset);
|
||||
offset += 4;
|
||||
}
|
||||
GetResource(p + offset, h.OffsetResource);
|
||||
GetResource(p + offset + 0x18, h.XmlResource);
|
||||
GetResource(p + offset + 0x30, h.MetadataResource);
|
||||
/*
|
||||
if (h.IsNewVersion())
|
||||
{
|
||||
if (haderSize < 0xD0)
|
||||
return S_FALSE;
|
||||
GetResource(p + offset + 0x4C, h.IntegrityResource);
|
||||
h.BootIndex = GetUInt32FromMem(p + 0x48);
|
||||
}
|
||||
*/
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
|
||||
{
|
||||
CByteBuffer offsetBuf;
|
||||
RINOK(UnpackData(inStream, h.OffsetResource, offsetBuf, NULL));
|
||||
for (size_t i = 0; i + kStreamInfoSize <= offsetBuf.GetCapacity(); i += kStreamInfoSize)
|
||||
{
|
||||
CStreamInfo s;
|
||||
GetStream((const Byte *)offsetBuf + i, s);
|
||||
if (s.PartNumber == h.PartNumber)
|
||||
db.Streams.Add(s);
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OpenArchive(IInStream *inStream, const CHeader &h, CByteBuffer &xml, CDatabase &db)
|
||||
{
|
||||
RINOK(UnpackData(inStream, h.XmlResource, xml, NULL));
|
||||
|
||||
RINOK(ReadStreams(inStream, h, db));
|
||||
bool needBootMetadata = !h.MetadataResource.IsEmpty();
|
||||
if (h.PartNumber == 1)
|
||||
{
|
||||
int imageIndex = 1;
|
||||
for (int j = 0; j < db.Streams.Size(); j++)
|
||||
{
|
||||
// if (imageIndex > 1) break;
|
||||
const CStreamInfo &si = db.Streams[j];
|
||||
if (!si.Resource.IsMetadata() || si.PartNumber != h.PartNumber)
|
||||
continue;
|
||||
Byte hash[kHashSize];
|
||||
CByteBuffer metadata;
|
||||
RINOK(UnpackData(inStream, si.Resource, 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;
|
||||
RINOK(ParseDir(metadata, metadata.GetCapacity(), s, db.Items));
|
||||
if (needBootMetadata)
|
||||
if (h.MetadataResource.Offset == si.Resource.Offset)
|
||||
needBootMetadata = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (needBootMetadata)
|
||||
{
|
||||
CByteBuffer metadata;
|
||||
RINOK(UnpackData(inStream, h.MetadataResource, metadata, NULL));
|
||||
RINOK(ParseDir(metadata, metadata.GetCapacity(), L"0" WSTRING_PATH_SEPARATOR, db.Items));
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT SortDatabase(CDatabase &db)
|
||||
{
|
||||
db.Streams.Sort(CompareStreamsByPos, NULL);
|
||||
|
||||
{
|
||||
CRecordVector<int> sortedByHash;
|
||||
{
|
||||
for (int j = 0; j < db.Streams.Size(); j++)
|
||||
sortedByHash.Add(j);
|
||||
sortedByHash.Sort(CompareHashRefs, &db.Streams);
|
||||
}
|
||||
|
||||
for (int i = 0; i < db.Items.Size(); i++)
|
||||
{
|
||||
CItem &item = db.Items[i];
|
||||
item.StreamIndex = -1;
|
||||
if (item.HasStream())
|
||||
item.StreamIndex = FindHash(db.Streams, sortedByHash, item.Hash);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
CRecordVector<bool> used;
|
||||
int j;
|
||||
for (j = 0; j < db.Streams.Size(); j++)
|
||||
{
|
||||
const CStreamInfo &s = db.Streams[j];
|
||||
used.Add(s.Resource.IsMetadata() && s.PartNumber == 1);
|
||||
}
|
||||
for (int i = 0; i < db.Items.Size(); i++)
|
||||
{
|
||||
CItem &item = db.Items[i];
|
||||
if (item.StreamIndex >= 0)
|
||||
used[item.StreamIndex] = true;
|
||||
}
|
||||
for (j = 0; j < db.Streams.Size(); j++)
|
||||
if (!used[j])
|
||||
{
|
||||
CItem item;
|
||||
item.StreamIndex = j;
|
||||
item.HasMetadata = false;
|
||||
db.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
db.Items.Sort(CompareItems, NULL);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
139
CPP/7zip/Archive/Wim/WimIn.h
Executable file
139
CPP/7zip/Archive/Wim/WimIn.h
Executable file
@@ -0,0 +1,139 @@
|
||||
// Archive/WimIn.h
|
||||
|
||||
#ifndef __ARCHIVE_WIM_IN_H
|
||||
#define __ARCHIVE_WIM_IN_H
|
||||
|
||||
#include "Common/MyString.h"
|
||||
#include "Common/Buffer.h"
|
||||
|
||||
#include "../../Compress/Lzx/LzxDecoder.h"
|
||||
#include "../../Compress/Copy/CopyCoder.h"
|
||||
|
||||
namespace NArchive {
|
||||
namespace NWim {
|
||||
|
||||
namespace NResourceFlags
|
||||
{
|
||||
const Byte Compressed = 4;
|
||||
const Byte kMetadata = 2;
|
||||
}
|
||||
|
||||
struct CResource
|
||||
{
|
||||
UInt64 PackSize;
|
||||
UInt64 Offset;
|
||||
UInt64 UnpackSize;
|
||||
Byte Flags;
|
||||
bool IsCompressed() const { return (Flags & NResourceFlags::Compressed) != 0; }
|
||||
bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
|
||||
bool IsEmpty() const { return (UnpackSize == 0); }
|
||||
};
|
||||
|
||||
namespace NHeaderFlags
|
||||
{
|
||||
const UInt32 kCompression = 2;
|
||||
const UInt32 kSpanned = 8;
|
||||
const UInt32 kRpFix = 0x80;
|
||||
const UInt32 kXPRESS = 0x20000;
|
||||
const UInt32 kLZX = 0x40000;
|
||||
}
|
||||
|
||||
struct CHeader
|
||||
{
|
||||
UInt32 Flags;
|
||||
UInt32 Version;
|
||||
// UInt32 ChunkSize;
|
||||
UInt16 PartNumber;
|
||||
UInt16 NumParts;
|
||||
UInt32 NumImages;
|
||||
Byte Guid[16];
|
||||
CResource OffsetResource;
|
||||
CResource XmlResource;
|
||||
CResource MetadataResource;
|
||||
/*
|
||||
CResource IntegrityResource;
|
||||
UInt32 BootIndex;
|
||||
*/
|
||||
bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; }
|
||||
bool IsSupported() const { return (!IsCompressed() || (Flags & NHeaderFlags::kLZX) != 0); }
|
||||
bool IsSpanned() const { return (!IsCompressed() || (Flags & NHeaderFlags::kSpanned) != 0); }
|
||||
|
||||
bool IsNewVersion()const { return (Version > 0x010C00); }
|
||||
|
||||
bool AreFromOnArchive(const CHeader &h)
|
||||
{
|
||||
return (memcmp(Guid, h.Guid, sizeof(Guid)) == 0) && (h.NumParts == NumParts);
|
||||
}
|
||||
};
|
||||
|
||||
const UInt32 kHashSize = 20;
|
||||
const UInt32 kStreamInfoSize = 24 + 2 + 4 + kHashSize;
|
||||
|
||||
struct CStreamInfo
|
||||
{
|
||||
CResource Resource;
|
||||
UInt16 PartNumber;
|
||||
UInt32 RefCount;
|
||||
BYTE Hash[kHashSize];
|
||||
};
|
||||
|
||||
struct CItem
|
||||
{
|
||||
UString Name;
|
||||
UInt32 Attributes;
|
||||
// UInt32 SecurityId;
|
||||
BYTE Hash[kHashSize];
|
||||
FILETIME CreationTime;
|
||||
FILETIME LastAccessTime;
|
||||
FILETIME LastWriteTime;
|
||||
// UInt32 ReparseTag;
|
||||
// UInt64 HardLink;
|
||||
// UInt16 NumStreams;
|
||||
// UInt16 ShortNameLen;
|
||||
int StreamIndex;
|
||||
bool HasMetadata;
|
||||
CItem(): HasMetadata(true), StreamIndex(-1) {}
|
||||
bool IsDirectory() const { return HasMetadata && ((Attributes & 0x10) != 0); }
|
||||
bool HasStream() const
|
||||
{
|
||||
for (int i = 0; i < kHashSize; i++)
|
||||
if (Hash[i] != 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct CDatabase
|
||||
{
|
||||
CRecordVector<CStreamInfo> Streams;
|
||||
CObjectVector<CItem> Items;
|
||||
void Clear()
|
||||
{
|
||||
Streams.Clear();
|
||||
Items.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
HRESULT ReadHeader(IInStream *inStream, CHeader &header);
|
||||
HRESULT OpenArchive(IInStream *inStream, const CHeader &header, CByteBuffer &xml, CDatabase &database);
|
||||
HRESULT SortDatabase(CDatabase &database);
|
||||
|
||||
class CUnpacker
|
||||
{
|
||||
NCompress::CCopyCoder *copyCoderSpec;
|
||||
CMyComPtr<ICompressCoder> copyCoder;
|
||||
|
||||
NCompress::NLzx::CDecoder *lzxDecoderSpec;
|
||||
CMyComPtr<ICompressCoder> lzxDecoder;
|
||||
|
||||
CByteBuffer sizesBuf;
|
||||
HRESULT Unpack(IInStream *inStream, const CResource &res,
|
||||
ISequentialOutStream *outStream, ICompressProgressInfo *progress);
|
||||
public:
|
||||
HRESULT Unpack(IInStream *inStream, const CResource &res,
|
||||
ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest);
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
13
CPP/7zip/Archive/Wim/WimRegister.cpp
Executable file
13
CPP/7zip/Archive/Wim/WimRegister.cpp
Executable file
@@ -0,0 +1,13 @@
|
||||
// WimRegister.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/RegisterArc.h"
|
||||
|
||||
#include "WimHandler.h"
|
||||
static IInArchive *CreateArc() { return new NArchive::NWim::CHandler; }
|
||||
|
||||
static CArcInfo g_ArcInfo =
|
||||
{ L"Wim", L"wim swm", 0, 0xE6, { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 }, 8, false, CreateArc, 0 };
|
||||
|
||||
REGISTER_ARC(Wim)
|
||||
BIN
CPP/7zip/Archive/Wim/wim.ico
Executable file
BIN
CPP/7zip/Archive/Wim/wim.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
Reference in New Issue
Block a user