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

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2007-07-11 04:00:00 +0400
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:15:52 +0300
commit7038848692e7049234f223703522681a19db49a5 (patch)
tree38c5acef39a775a1f58f81b13be81fc6ef8c72e3 /CPP/7zip/Archive/Wim
parentfd8b1d78b496fe38193bf8c5e86af3b43f0b022d (diff)
4.49 beta
Diffstat (limited to 'CPP/7zip/Archive/Wim')
-rwxr-xr-xCPP/7zip/Archive/Wim/StdAfx.h8
-rwxr-xr-xCPP/7zip/Archive/Wim/WimHandler.cpp477
-rwxr-xr-xCPP/7zip/Archive/Wim/WimHandler.h60
-rwxr-xr-xCPP/7zip/Archive/Wim/WimIn.cpp467
-rwxr-xr-xCPP/7zip/Archive/Wim/WimIn.h139
-rwxr-xr-xCPP/7zip/Archive/Wim/WimRegister.cpp13
-rwxr-xr-xCPP/7zip/Archive/Wim/wim.icobin0 -> 3638 bytes
7 files changed, 1164 insertions, 0 deletions
diff --git a/CPP/7zip/Archive/Wim/StdAfx.h b/CPP/7zip/Archive/Wim/StdAfx.h
new file mode 100755
index 00000000..e7fb6986
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/StdAfx.h
@@ -0,0 +1,8 @@
+// StdAfx.h
+
+#ifndef __STDAFX_H
+#define __STDAFX_H
+
+#include "../../../Common/MyWindows.h"
+
+#endif
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
new file mode 100755
index 00000000..aa9300a2
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -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(&currentTotalSize));
+ 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, &currentTotalSize, &currentTotalSize);
+ 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;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h
new file mode 100755
index 00000000..5142d785
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandler.h
@@ -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
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp
new file mode 100755
index 00000000..e99cb37b
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -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;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h
new file mode 100755
index 00000000..bc74f61b
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimIn.h
@@ -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
diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp
new file mode 100755
index 00000000..22344b3a
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -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)
diff --git a/CPP/7zip/Archive/Wim/wim.ico b/CPP/7zip/Archive/Wim/wim.ico
new file mode 100755
index 00000000..887975e6
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/wim.ico
Binary files differ