📄 wimhandler.cpp
字号:
// WimHandler.cpp
#include "StdAfx.h"
#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 {
namespace NWim {
#define WIM_DETAILS
STATPROPSTG kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidPackSize, VT_UI8},
{ NULL, kpidAttrib, VT_UI4},
{ NULL, kpidMethod, VT_BSTR},
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidATime, VT_FILETIME}
#ifdef WIM_DETAILS
, { NULL, kpidVolume, VT_UI4}
, { NULL, kpidOffset, VT_UI8}
, { NULL, kpidLinks, VT_UI4}
#endif
};
STATPROPSTG kArcProps[] =
{
{ NULL, kpidSize, 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
IMP_IInArchive_ArcProps
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 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;
if (volIndex < m_Volumes.Size())
prop = (m_Volumes[volIndex].Header.NumParts > 1);
}
break;
case kpidVolume:
if (m_Xmls.Size() > 0)
{
UInt16 volIndex = m_Xmls[0].VolIndex;
if (volIndex < m_Volumes.Size())
prop = (UInt32)m_Volumes[volIndex].Header.PartNumber;
}
break;
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;
COM_TRY_END
}
STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NWindows::NCOM::CPropVariant prop;
if (index < (UInt32)m_Database.Items.Size())
{
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)
{
case kpidPath:
if (item.HasMetadata)
prop = 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;
prop = s;
break;
}
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() ?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -