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:
Diffstat (limited to 'CPP/7zip/Archive/XarHandler.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/XarHandler.cpp365
1 files changed, 250 insertions, 115 deletions
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp
index e7d88b6c..918ef736 100755..100644
--- a/CPP/7zip/Archive/XarHandler.cpp
+++ b/CPP/7zip/Archive/XarHandler.cpp
@@ -4,13 +4,13 @@
#include "../../../C/CpuArch.h"
-#include "Common/ComTry.h"
-#include "Common/MyXml.h"
-#include "Common/StringToInt.h"
-#include "Common/UTFConvert.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyXml.h"
+#include "../../Common/StringToInt.h"
+#include "../../Common/UTFConvert.h"
-#include "Windows/PropVariant.h"
-#include "Windows/Time.h"
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
@@ -24,6 +24,8 @@
#include "Common/OutStreamWithSha1.h"
+using namespace NWindows;
+
#define XAR_SHOW_RAW
#define Get16(p) GetBe16(p)
@@ -33,6 +35,25 @@
namespace NArchive {
namespace NXar {
+static const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14);
+static const UInt32 kXmlPackSizeMax = kXmlSizeMax;
+
+/*
+#define XAR_CKSUM_NONE 0
+#define XAR_CKSUM_SHA1 1
+#define XAR_CKSUM_MD5 2
+
+static const char *k_ChecksumAlgos[] =
+{
+ "None"
+ , "SHA-1"
+ , "MD5"
+};
+*/
+
+#define METHOD_NAME_ZLIB "zlib"
+
+
struct CFile
{
AString Name;
@@ -41,125 +62,153 @@ struct CFile
UInt64 PackSize;
UInt64 Offset;
- // UInt32 mode;
UInt64 CTime;
UInt64 MTime;
UInt64 ATime;
+ UInt32 Mode;
+
+ AString User;
+ AString Group;
bool IsDir;
bool HasData;
-
+ bool ModeDefined;
bool Sha1IsDefined;
- Byte Sha1[20];
// bool packSha1IsDefined;
- // Byte packSha1[20];
+
+ Byte Sha1[NCrypto::NSha1::kDigestSize];
+ // Byte packSha1[NCrypto::NSha1::kDigestSize];
int Parent;
- CFile(): IsDir(false), HasData(false), Sha1IsDefined(false),
- /* packSha1IsDefined(false), */
- Parent(-1), Size(0), PackSize(0), CTime(0), MTime(0), ATime(0) {}
+ CFile(): IsDir(false), HasData(false), ModeDefined(false), Sha1IsDefined(false),
+ /* packSha1IsDefined(false), */
+ Parent(-1),
+ Size(0), PackSize(0), Offset(0),
+ CTime(0), MTime(0), ATime(0), Mode(0) {}
+
+ bool IsCopyMethod() const
+ {
+ return Method.IsEmpty() || Method == "octet-stream";
+ }
+
+ void UpdateTotalPackSize(UInt64 &totalSize) const
+ {
+ UInt64 t = Offset + PackSize;
+ if (totalSize < t)
+ totalSize = t;
+ }
};
class CHandler:
public IInArchive,
+ public IInArchiveGetStream,
public CMyUnknownImp
{
UInt64 _dataStartPos;
CMyComPtr<IInStream> _inStream;
AString _xml;
CObjectVector<CFile> _files;
+ // UInt32 _checkSumAlgo;
+ UInt64 _phySize;
+ Int32 _mainSubfile;
+ bool _is_pkg;
HRESULT Open2(IInStream *stream);
HRESULT Extract(IInStream *stream);
public:
- MY_UNKNOWN_IMP1(IInArchive)
+ MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive(;)
+ STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
};
-const UInt32 kXmlSizeMax = ((UInt32)1 << 30) - (1 << 14);
+static const Byte kArcProps[] =
+{
+ kpidSubType,
+ kpidHeadersSize
+};
-STATPROPSTG kProps[] =
+static const Byte kProps[] =
{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidPackSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME},
- { NULL, kpidMethod, VT_BSTR}
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidPosixAttrib,
+ kpidUser,
+ kpidGroup,
+ kpidMethod
};
IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
+IMP_IInArchive_ArcProps
-static bool ParseNumber(const char *s, int size, UInt32 &res)
-{
- const char *end;
- res = (UInt32)ConvertStringToUInt64(s, &end);
- return (end - s == size);
-}
+#define PARSE_NUM(_num_, _dest_) \
+ { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \
+ if ((unsigned)(end - p) != _num_) return 0; p += _num_ + 1; }
static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res)
{
- AString s = item.GetSubStringForTag(name);
+ const AString s = item.GetSubStringForTag(name);
+ if (s.IsEmpty())
+ return false;
const char *end;
res = ConvertStringToUInt64(s, &end);
- return (end - (const char *)s == s.Length());
+ return *end == 0;
}
static UInt64 ParseTime(const CXmlItem &item, const char *name)
{
- AString s = item.GetSubStringForTag(name);
- if (s.Length() < 20)
+ const AString s = item.GetSubStringForTag(name);
+ if (s.Len() < 20)
return 0;
const char *p = s;
if (p[ 4] != '-' || p[ 7] != '-' || p[10] != 'T' ||
p[13] != ':' || p[16] != ':' || p[19] != 'Z')
return 0;
UInt32 year, month, day, hour, min, sec;
- if (!ParseNumber(p, 4, year )) return 0;
- if (!ParseNumber(p + 5, 2, month)) return 0;
- if (!ParseNumber(p + 8, 2, day )) return 0;
- if (!ParseNumber(p + 11, 2, hour )) return 0;
- if (!ParseNumber(p + 14, 2, min )) return 0;
- if (!ParseNumber(p + 17, 2, sec )) return 0;
+ PARSE_NUM(4, year)
+ PARSE_NUM(2, month)
+ PARSE_NUM(2, day)
+ PARSE_NUM(2, hour)
+ PARSE_NUM(2, min)
+ PARSE_NUM(2, sec)
UInt64 numSecs;
- if (!NWindows::NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
+ if (!NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
return 0;
return numSecs * 10000000;
}
-static bool HexToByte(char c, Byte &res)
+static int HexToByte(char c)
{
- if (c >= '0' && c <= '9') res = c - '0';
- else if (c >= 'A' && c <= 'F') res = c - 'A' + 10;
- else if (c >= 'a' && c <= 'f') res = c - 'a' + 10;
- else return false;
- return true;
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+ return -1;
}
-#define METHOD_NAME_ZLIB "zlib"
-
static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest)
{
int index = item.FindSubTag(name);
- if (index < 0)
+ if (index < 0)
return false;
const CXmlItem &checkItem = item.SubItems[index];
- AString style = checkItem.GetPropertyValue("style");
+ const AString style = checkItem.GetPropVal("style");
if (style == "SHA1")
{
- AString s = checkItem.GetSubString();
- if (s.Length() != 40)
+ const AString s = checkItem.GetSubString();
+ if (s.Len() != NCrypto::NSha1::kDigestSize * 2)
return false;
- for (int i = 0; i < s.Length(); i += 2)
+ for (unsigned i = 0; i < s.Len(); i += 2)
{
- Byte b0, b1;
- if (!HexToByte(s[i], b0) || !HexToByte(s[i + 1], b1))
+ int b0 = HexToByte(s[i]);
+ int b1 = HexToByte(s[i + 1]);
+ if (b0 < 0 || b1 < 0)
return false;
- digest[i / 2] = (b0 << 4) | b1;
+ digest[i / 2] = (Byte)((b0 << 4) | b1);
}
return true;
}
@@ -203,17 +252,17 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex];
if (encodingItem.IsTag)
{
- AString s = encodingItem.GetPropertyValue("style");
- if (s.Length() >= 0)
+ AString s = encodingItem.GetPropVal("style");
+ if (s.Len() >= 0)
{
AString appl = "application/";
- if (s.Left(appl.Length()) == appl)
+ if (s.IsPrefixedBy(appl))
{
- s = s.Mid(appl.Length());
+ s.DeleteFrontal(appl.Len());
AString xx = "x-";
- if (s.Left(xx.Length()) == xx)
+ if (s.IsPrefixedBy(xx))
{
- s = s.Mid(xx.Length());
+ s.DeleteFrontal(xx.Len());
if (s == "gzip")
s = METHOD_NAME_ZLIB;
}
@@ -227,9 +276,23 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
file.CTime = ParseTime(item, "ctime");
file.MTime = ParseTime(item, "mtime");
file.ATime = ParseTime(item, "atime");
+
+ {
+ const AString s = item.GetSubStringForTag("mode");
+ if (s[0] == '0')
+ {
+ const char *end;
+ file.Mode = ConvertOctStringToUInt32(s, &end);
+ file.ModeDefined = (*end == 0);
+ }
+ }
+
+ file.User = item.GetSubStringForTag("user");
+ file.Group = item.GetSubStringForTag("group");
+
files.Add(file);
}
- for (int i = 0; i < item.SubItems.Size(); i++)
+ FOR_VECTOR (i, item.SubItems)
if (!AddItem(item.SubItems[i], files, parent))
return false;
return true;
@@ -237,28 +300,28 @@ static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int paren
HRESULT CHandler::Open2(IInStream *stream)
{
- UInt64 archiveStartPos;
- RINOK(stream->Seek(0, STREAM_SEEK_SET, &archiveStartPos));
-
const UInt32 kHeaderSize = 0x1C;
Byte buf[kHeaderSize];
RINOK(ReadStream_FALSE(stream, buf, kHeaderSize));
UInt32 size = Get16(buf + 4);
- // UInt32 ver = Get16(buf + 6); // == 0
+ // UInt32 ver = Get16(buf + 6); // == 1
if (Get32(buf) != 0x78617221 || size != kHeaderSize)
return S_FALSE;
UInt64 packSize = Get64(buf + 8);
UInt64 unpackSize = Get64(buf + 0x10);
- // UInt32 checkSumAlogo = Get32(buf + 0x18);
- if (unpackSize >= kXmlSizeMax)
+ // _checkSumAlgo = Get32(buf + 0x18);
+
+ if (packSize >= kXmlPackSizeMax ||
+ unpackSize >= kXmlSizeMax)
return S_FALSE;
- _dataStartPos = archiveStartPos + kHeaderSize + packSize;
+ _dataStartPos = kHeaderSize + packSize;
+ _phySize = _dataStartPos;
- char *ss = _xml.GetBuffer((int)unpackSize + 1);
+ char *ss = _xml.GetBuffer((unsigned)unpackSize);
NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
@@ -291,6 +354,19 @@ HRESULT CHandler::Open2(IInStream *stream)
return S_FALSE;
if (!AddItem(toc, _files, -1))
return S_FALSE;
+
+ UInt64 totalPackSize = 0;
+ FOR_VECTOR(i, _files)
+ {
+ const CFile &file = _files[i];
+ file.UpdateTotalPackSize(totalPackSize);
+ if (file.Name == "Payload")
+ _mainSubfile = i;
+ if (file.Name == "PackageInfo")
+ _is_pkg = true;
+ }
+ _phySize = _dataStartPos + totalPackSize;
+
return S_OK;
}
@@ -311,9 +387,12 @@ STDMETHODIMP CHandler::Open(IInStream *stream,
STDMETHODIMP CHandler::Close()
{
+ _phySize = 0;
_inStream.Release();
_files.Clear();
_xml.Empty();
+ _mainSubfile = -1;
+ _is_pkg = false;
return S_OK;
}
@@ -327,7 +406,7 @@ STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
return S_OK;
}
-static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
+static void TimeToProp(UInt64 t, NCOM::CPropVariant &prop)
{
if (t != 0)
{
@@ -338,34 +417,56 @@ static void TimeToProp(UInt64 t, NWindows::NCOM::CPropVariant &prop)
}
}
+static void Utf8StringToProp(const AString &s, NCOM::CPropVariant &prop)
+{
+ if (!s.IsEmpty())
+ {
+ UString us;
+ if (ConvertUTF8ToUnicode(s, us))
+ prop = us;
+ }
+}
+
+STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidHeadersSize: prop = _dataStartPos; break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ case kpidSubType: if (_is_pkg) prop = "pkg"; break;
+ case kpidExtension: prop = _is_pkg ? "pkg" : "xar"; break;
+ }
+ 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;
+ NCOM::CPropVariant prop;
#ifdef XAR_SHOW_RAW
- if ((int)index == _files.Size())
+ if (index == _files.Size())
{
- switch(propID)
+ switch (propID)
{
- case kpidPath: prop = L"[TOC].xml"; break;
+ case kpidPath: prop = "[TOC].xml"; break;
case kpidSize:
- case kpidPackSize: prop = (UInt64)_xml.Length(); break;
+ case kpidPackSize: prop = (UInt64)_xml.Len(); break;
}
}
else
#endif
{
const CFile &item = _files[index];
- switch(propID)
+ switch (propID)
{
- case kpidMethod:
- {
- UString name;
- if (!item.Method.IsEmpty() && ConvertUTF8ToUnicode(item.Method, name))
- prop = name;
- break;
- }
+ case kpidMethod: Utf8StringToProp(item.Method, prop); break;
+
case kpidPath:
{
AString path;
@@ -373,30 +474,40 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
do
{
const CFile &item = _files[cur];
- AString s = item.Name;
- if (s.IsEmpty())
- s = "unknown";
- if (path.IsEmpty())
- path = s;
+ if (!path.IsEmpty())
+ path.InsertAtFront(CHAR_PATH_SEPARATOR);
+ if (item.Name.IsEmpty())
+ path.Insert(0, "unknown");
else
- path = s + CHAR_PATH_SEPARATOR + path;
+ path.Insert(0, item.Name);
cur = item.Parent;
}
while (cur >= 0);
- UString name;
- if (ConvertUTF8ToUnicode(path, name))
- prop = name;
+ Utf8StringToProp(path, prop);
break;
}
- case kpidIsDir: prop = item.IsDir; break;
- case kpidSize: if (!item.IsDir) prop = item.Size; break;
- case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break;
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidSize: if (!item.IsDir) prop = item.Size; break;
+ case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break;
- case kpidMTime: TimeToProp(item.MTime, prop); break;
- case kpidCTime: TimeToProp(item.CTime, prop); break;
- case kpidATime: TimeToProp(item.ATime, prop); break;
+ case kpidMTime: TimeToProp(item.MTime, prop); break;
+ case kpidCTime: TimeToProp(item.CTime, prop); break;
+ case kpidATime: TimeToProp(item.ATime, prop); break;
+ case kpidPosixAttrib:
+ if (item.ModeDefined)
+ {
+ UInt32 mode = item.Mode;
+ const UInt32 k_PosixAttrib_Dir = (1 << 14);
+ const UInt32 k_PosixAttrib_RegFile = (1 << 15);
+ if ((mode & 0xF000) == 0)
+ mode |= (item.IsDir ? k_PosixAttrib_Dir : k_PosixAttrib_RegFile);
+ prop = mode;
+ }
+ break;
+ case kpidUser: Utf8StringToProp(item.User, prop); break;
+ case kpidGroup: Utf8StringToProp(item.Group, prop); break;
}
}
prop.Detach(value);
@@ -408,7 +519,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 testMode, IArchiveExtractCallback *extractCallback)
{
COM_TRY_BEGIN
- bool allFilesMode = (numItems == (UInt32)-1);
+ bool allFilesMode = (numItems == (UInt32)(Int32)-1);
if (allFilesMode)
numItems = _files.Size();
if (numItems == 0)
@@ -417,10 +528,10 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt32 i;
for (i = 0; i < numItems; i++)
{
- int index = (int)(allFilesMode ? i : indices[i]);
+ UInt32 index = (allFilesMode ? i : indices[i]);
#ifdef XAR_SHOW_RAW
if (index == _files.Size())
- totalSize += _xml.Length();
+ totalSize += _xml.Len();
else
#endif
totalSize += _files[index].Size;
@@ -433,8 +544,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 currentUnpSize = 0;
const UInt32 kZeroBufSize = (1 << 14);
- CByteBuffer zeroBuf;
- zeroBuf.SetCapacity(kZeroBufSize);
+ CByteBuffer zeroBuf(kZeroBufSize);
memset(zeroBuf, 0, kZeroBufSize);
NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
@@ -478,7 +588,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
Int32 askMode = testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
- Int32 index = allFilesMode ? i : indices[i];
+ UInt32 index = allFilesMode ? i : indices[i];
RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
if (index < _files.Size())
@@ -504,9 +614,9 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (index == _files.Size())
{
outStreamSha1Spec->Init(false);
- outStreamLimSpec->Init(_xml.Length());
- RINOK(WriteStream(outStream, (const char *)_xml, _xml.Length()));
- currentPackSize = currentUnpSize = _xml.Length();
+ outStreamLimSpec->Init(_xml.Len());
+ RINOK(WriteStream(outStream, (const char *)_xml, _xml.Len()));
+ currentPackSize = currentUnpSize = _xml.Len();
}
else
#endif
@@ -524,17 +634,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
HRESULT res = S_OK;
ICompressCoder *coder = NULL;
- if (item.Method.IsEmpty() || item.Method == "octet-stream")
+ if (item.IsCopyMethod())
if (item.PackSize == item.Size)
coder = copyCoder;
else
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
else if (item.Method == METHOD_NAME_ZLIB)
coder = zlibCoder;
else if (item.Method == "bzip2")
coder = bzip2Coder;
else
- opRes = NExtract::NOperationResult::kUnSupportedMethod;
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
if (coder)
res = coder->Code(inStream, outStream, NULL, NULL, progress);
@@ -578,10 +688,35 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
COM_TRY_END
}
-static IInArchive *CreateArc() { return new NArchive::NXar::CHandler; }
+STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
+{
+ *stream = NULL;
+ COM_TRY_BEGIN
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ {
+ Create_BufInStream_WithNewBuf((const void *)(const char *)_xml, _xml.Len(), stream);
+ return S_OK;
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ if (item.HasData && item.IsCopyMethod() && item.PackSize == item.Size)
+ return CreateLimitedInStream(_inStream, _dataStartPos + item.Offset, item.Size, stream);
+ }
+ return S_FALSE;
+ COM_TRY_END
+}
+
+IMP_CreateArcIn
static CArcInfo g_ArcInfo =
- { L"Xar", L"xar", 0, 0xE1, { 'x', 'a', 'r', '!', 0, 0x1C }, 6, false, CreateArc, 0 };
+ { "Xar", "xar pkg", 0, 0xE1,
+ 6, { 'x', 'a', 'r', '!', 0, 0x1C },
+ 0,
+ 0,
+ CreateArc };
REGISTER_ARC(Xar)