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/VmdkHandler.cpp')
-rw-r--r--CPP/7zip/Archive/VmdkHandler.cpp1034
1 files changed, 822 insertions, 212 deletions
diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp
index 4b404e14..83e38d02 100644
--- a/CPP/7zip/Archive/VmdkHandler.cpp
+++ b/CPP/7zip/Archive/VmdkHandler.cpp
@@ -8,6 +8,9 @@
#include "../../Common/ComTry.h"
#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/StringToInt.h"
+#include "../../Common/UTFConvert.h"
#include "../../Windows/PropVariant.h"
@@ -19,24 +22,29 @@
#include "HandlerCont.h"
+using namespace NWindows;
+
+namespace NArchive {
+namespace NVmdk {
+
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
#define Get64(p) GetUi64(p)
-using namespace NWindows;
+#define LE_16(offs, dest) dest = Get16(p + (offs));
+#define LE_32(offs, dest) dest = Get32(p + (offs));
+#define LE_64(offs, dest) dest = Get64(p + (offs));
-namespace NArchive {
-namespace NVmdk {
#define SIGNATURE { 'K', 'D', 'M', 'V' }
static const Byte k_Signature[] = SIGNATURE;
-static const UInt32 k_Flags_NL = (UInt32)1 << 0;
-static const UInt32 k_Flags_RGD = (UInt32)1 << 1;
-static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2;
+static const UInt32 k_Flags_NL = (UInt32)1 << 0;
+static const UInt32 k_Flags_RGD = (UInt32)1 << 1;
+static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2;
static const UInt32 k_Flags_Compressed = (UInt32)1 << 16;
-static const UInt32 k_Flags_Marker = (UInt32)1 << 17;
+static const UInt32 k_Flags_Marker = (UInt32)1 << 17;
static const unsigned k_NumMidBits = 9; // num bits for index in Grain Table
@@ -57,12 +65,12 @@ struct CHeader
UInt64 gdOffset;
UInt64 overHead;
- bool Is_NL() const { return (flags & k_Flags_NL) != 0; };
- bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; };
+ bool Is_NL() const { return (flags & k_Flags_NL) != 0; };
+ bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; };
bool Is_Compressed() const { return (flags & k_Flags_Compressed) != 0; };
- bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; };
+ bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; };
- bool Parse(const Byte *buf);
+ bool Parse(const Byte *p);
bool IsSameImageFor(const CHeader &h) const
{
@@ -74,25 +82,25 @@ struct CHeader
}
};
-bool CHeader::Parse(const Byte *buf)
+bool CHeader::Parse(const Byte *p)
{
- if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
+ if (memcmp(p, k_Signature, sizeof(k_Signature)) != 0)
return false;
- version = Get32(buf + 0x4);
- flags = Get32(buf + 0x8);
- capacity = Get64(buf + 0xC);
- grainSize = Get64(buf + 0x14);
- descriptorOffset = Get64(buf + 0x1C);
- descriptorSize = Get64(buf + 0x24);
- numGTEsPerGT = Get32(buf + 0x2C);
- // rgdOffset = Get64(buf + 0x30);
- gdOffset = Get64(buf + 0x38);
- overHead = Get64(buf + 0x40);
+ LE_32 (0x04, version);
+ LE_32 (0x08, flags);
+ LE_64 (0x0C, capacity);
+ LE_64 (0x14, grainSize);
+ LE_64 (0x1C, descriptorOffset);
+ LE_64 (0x24, descriptorSize);
+ LE_32 (0x2C, numGTEsPerGT);
+ // LE_64 (0x30, rgdOffset);
+ LE_64 (0x38, gdOffset);
+ LE_64 (0x40, overHead);
// uncleanShutdown = buf[0x48];
- algo = Get16(buf + 0x4D);
+ LE_16(0x4D, algo);
- if (Is_NL() && Get32(buf + 0x49) != 0x0A0D200A) // do we need Is_NL() check here?
+ if (Is_NL() && Get32(p + 0x49) != 0x0A0D200A) // do we need Is_NL() check here?
return false;
return (numGTEsPerGT == (1 << k_NumMidBits)) && (version <= 3);
@@ -115,21 +123,154 @@ struct CMarker
void Parse(const Byte *p)
{
- NumSectors = Get64(p);
- SpecSize = Get32(p + 8);
- Type = Get32(p + 12);
+ LE_64 (0, NumSectors);
+ LE_32 (8, SpecSize);
+ LE_32 (12, Type);
+ }
+};
+
+
+static bool Str_to_ValName(const AString &s, AString &name, AString &val)
+{
+ name.Empty();
+ val.Empty();
+ int qu = s.Find('"');
+ int eq = s.Find('=');
+ if (eq < 0 || (qu >= 0 && eq > qu))
+ return false;
+ name = s.Left(eq);
+ name.Trim();
+ val = s.Ptr(eq + 1);
+ val.Trim();
+ return true;
+}
+
+static inline bool IsSpaceChar(char c)
+{
+ return (c == ' ' || c == '\t');
+}
+
+static const char *SkipSpaces(const char *s)
+{
+ for (;; s++)
+ {
+ char c = *s;
+ if (c == 0 || !IsSpaceChar(c))
+ return s;
}
+}
+
+#define SKIP_SPACES(s) s = SkipSpaces(s);
+
+static const char *GetNextWord(const char *s, AString &dest)
+{
+ dest.Empty();
+ SKIP_SPACES(s);
+ const char *start = s;
+ for (;; s++)
+ {
+ char c = *s;
+ if (c == 0 || IsSpaceChar(c))
+ {
+ dest.SetFrom(start, (unsigned)(s - start));
+ return s;
+ }
+ }
+}
+
+static const char *GetNextNumber(const char *s, UInt64 &val)
+{
+ SKIP_SPACES(s);
+ if (*s == 0)
+ return s;
+ const char *end;
+ val = ConvertStringToUInt64(s, &end);
+ char c = *end;
+ if (c != 0 && !IsSpaceChar(c))
+ return NULL;
+ return end;
+}
+
+
+struct CExtentInfo
+{
+ AString Access; // RW, RDONLY, or NOACCESS
+ UInt64 NumSectors; // 512 bytes sectors
+ AString Type; // FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, VMFSRAW
+ AString FileName;
+ UInt64 StartSector; // used for FLAT
+
+ // for VMWare Player 9:
+ // PartitionUUID
+ // DeviceIdentifier
+
+ bool IsType_ZERO() const { return Type == "ZERO"; }
+ // bool IsType_FLAT() const { return Type == "FLAT"; }
+ bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; }
+
+ bool Parse(const char *s);
};
+bool CExtentInfo::Parse(const char *s)
+{
+ NumSectors = 0;
+ StartSector = 0;
+ Access.Empty();
+ Type.Empty();
+ FileName.Empty();
+
+ s = GetNextWord(s, Access);
+ s = GetNextNumber(s, NumSectors);
+ if (!s)
+ return false;
+ s = GetNextWord(s, Type);
+
+ if (Type.IsEmpty())
+ return false;
+
+ SKIP_SPACES(s);
+
+ if (IsType_ZERO())
+ return (*s == 0);
+
+ if (*s != '\"')
+ return false;
+ s++;
+ {
+ const char *s2 = strchr(s, '\"');
+ if (!s2)
+ return false;
+ FileName.SetFrom(s, (unsigned)(s2 - s));
+ s = s2 + 1;
+ }
+ SKIP_SPACES(s);
+ if (*s == 0)
+ return true;
+
+ s = GetNextNumber(s, StartSector);
+ if (!s)
+ return false;
+ return true;
+ // SKIP_SPACES(s);
+ // return (*s == 0);
+}
+
struct CDescriptor
{
AString CID;
AString parentCID;
AString createType;
+ // AString encoding; // UTF-8, windows-1252 - default is UTF-8
+
+ CObjectVector<CExtentInfo> Extents;
+
+ static void GetUnicodeName(const AString &s, UString &res)
+ {
+ if (!ConvertUTF8ToUnicode(s, res))
+ MultiByteToUnicodeString2(res, s);
+ }
- AStringVector Extents;
-
void Clear()
{
CID.Empty();
@@ -138,25 +279,16 @@ struct CDescriptor
Extents.Clear();
}
- void Parse(const Byte *p, size_t size);
+ bool IsThere_Parent() const
+ {
+ return !parentCID.IsEmpty() && !parentCID.IsEqualTo_Ascii_NoCase("ffffffff");
+ }
+
+ bool Parse(const Byte *p, size_t size);
};
-static bool Str_to_ValName(const AString &s, AString &name, AString &val)
-{
- name.Empty();
- val.Empty();
- int qu = s.Find('"');
- int eq = s.Find('=');
- if (eq < 0 || (qu >= 0 && eq > qu))
- return false;
- name = s.Left(eq);
- name.Trim();
- val = s.Ptr(eq + 1);
- val.Trim();
- return true;
-}
-void CDescriptor::Parse(const Byte *p, size_t size)
+bool CDescriptor::Parse(const Byte *p, size_t size)
{
Clear();
@@ -166,7 +298,7 @@ void CDescriptor::Parse(const Byte *p, size_t size)
for (size_t i = 0;; i++)
{
- char c = p[i];
+ const char c = p[i];
if (i == size || c == 0 || c == 0xA || c == 0xD)
{
if (!s.IsEmpty() && s[0] != '#')
@@ -181,8 +313,14 @@ void CDescriptor::Parse(const Byte *p, size_t size)
createType = val;
}
else
- Extents.Add(s);
+ {
+ CExtentInfo ei;
+ if (!ei.Parse(s))
+ return false;
+ Extents.Add(ei);
+ }
}
+
s.Empty();
if (c == 0 || i >= size)
break;
@@ -190,25 +328,116 @@ void CDescriptor::Parse(const Byte *p, size_t size)
else
s += (char)c;
}
+
+ return true;
}
+struct CExtent
+{
+ bool IsOK;
+ bool IsArc;
+ bool NeedDeflate;
+ bool Unsupported;
+ bool IsZero;
+ bool IsFlat;
+ bool DescriptorOK;
+ bool HeadersError;
+
+ unsigned ClusterBits;
+ UInt32 ZeroSector;
+
+ CObjectVector<CByteBuffer> Tables;
+
+ CMyComPtr<IInStream> Stream;
+ UInt64 PosInArc;
+
+ UInt64 PhySize;
+ UInt64 VirtSize; // from vmdk header of volume
+
+ UInt64 StartOffset; // virtual offset of this extent
+ UInt64 NumBytes; // from main descriptor, if multi-vol
+ UInt64 FlatOffset; // in Stream
+
+ CByteBuffer DescriptorBuf;
+ CDescriptor Descriptor;
+
+ CHeader h;
+
+ UInt64 GetEndOffset() const { return StartOffset + NumBytes; }
+
+ bool IsVmdk() const { return !IsZero && !IsFlat; };
+ // if (IsOK && IsVmdk()), then VMDK header of this extent was read
+
+ CExtent():
+ IsOK(false),
+ IsArc(false),
+ NeedDeflate(false),
+ Unsupported(false),
+ IsZero(false),
+ IsFlat(false),
+ DescriptorOK(false),
+ HeadersError(false),
+
+ ClusterBits(0),
+ ZeroSector(0),
+
+ PosInArc(0),
+
+ PhySize(0),
+ VirtSize(0),
+
+ StartOffset(0),
+ NumBytes(0),
+ FlatOffset(0)
+ {}
+
+
+ HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors);
+ HRESULT Open3(IInStream *stream, IArchiveOpenCallback *openCallback,
+ unsigned numVols, unsigned volIndex, UInt64 &complexity);
+
+ HRESULT Seek(UInt64 offset)
+ {
+ PosInArc = offset;
+ return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
+ }
+
+ HRESULT InitAndSeek()
+ {
+ if (Stream)
+ return Seek(0);
+ return S_OK;
+ }
+
+ HRESULT Read(void *data, size_t *size)
+ {
+ HRESULT res = ReadStream(Stream, data, size);
+ PosInArc += *size;
+ return res;
+ }
+};
+
+
class CHandler: public CHandlerImg
{
- unsigned _clusterBits;
+ bool _isArc;
+ bool _unsupported;
+ bool _unsupportedSome;
+ bool _headerError;
+ bool _missingVol;
+ bool _isMultiVol;
+ bool _needDeflate;
- CObjectVector<CByteBuffer> _tables;
UInt64 _cacheCluster;
+ unsigned _cacheExtent;
CByteBuffer _cache;
CByteBuffer _cacheCompressed;
-
+
+ unsigned _clusterBitsMax;
UInt64 _phySize;
- UInt32 _zeroSector;
- bool _needDeflate;
- bool _isArc;
- bool _unsupported;
- // bool _headerError;
+ CObjectVector<CExtent> _extents;
CBufInStream *_bufInStreamSpec;
CMyComPtr<ISequentialInStream> _bufInStream;
@@ -222,24 +451,13 @@ class CHandler: public CHandlerImg
CByteBuffer _descriptorBuf;
CDescriptor _descriptor;
- CHeader h;
-
-
- HRESULT Seek(UInt64 offset)
- {
- _posInArc = offset;
- return Stream->Seek(offset, STREAM_SEEK_SET, NULL);
- }
-
- HRESULT InitAndSeek()
+ void InitAndSeekMain()
{
_virtPos = 0;
- return Seek(0);
}
- HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors);
virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback);
-
+ virtual void CloseAtError();
public:
INTERFACE_IInArchive_Img(;)
@@ -261,19 +479,130 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
if (size == 0)
return S_OK;
}
-
+
+ unsigned extentIndex;
+ {
+ unsigned left = 0, right = _extents.Size();
+ for (;;)
+ {
+ unsigned mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (_virtPos < _extents[mid].StartOffset)
+ right = mid;
+ else
+ left = mid;
+ }
+ extentIndex = left;
+ }
+
+ CExtent &extent = _extents[extentIndex];
+
+ {
+ const UInt64 vir = _virtPos - extent.StartOffset;
+ if (vir >= extent.NumBytes)
+ {
+ return E_FAIL;
+ /*
+ if (vir > extent.NumBytes)
+ _stream_dataError = true;
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+
+ {
+ const UInt64 rem = extent.NumBytes - vir;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (vir >= extent.VirtSize)
+ {
+ // if vmdk's VirtSize is smaller than VirtSize from main multi-volume descriptor
+ _stream_dataError = true;
+ return S_FALSE;
+ /*
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+
+ {
+ const UInt64 rem = extent.VirtSize - vir;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (extent.IsZero || !extent.IsOK || !extent.Stream || extent.Unsupported)
+ {
+ if (extent.Unsupported)
+ {
+ _stream_unsupportedMethod = true;
+ return S_FALSE;
+ }
+ if (!extent.IsOK || !extent.Stream)
+ {
+ _stream_unavailData = true;
+ return S_FALSE;
+ }
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+
+ if (extent.IsFlat)
+ {
+ UInt64 offset = extent.FlatOffset + vir;
+ if (offset != extent.PosInArc)
+ {
+ RINOK(extent.Seek(offset));
+ }
+ UInt32 size2 = 0;
+ HRESULT res = extent.Stream->Read(data, size, &size2);
+ if (res == S_OK && size2 == 0)
+ {
+ _stream_unavailData = true;
+ /*
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+ // _stream_PackSize += size2;
+ extent.PosInArc += size2;
+ _virtPos += size2;
+ if (processedSize)
+ *processedSize = size2;
+ return res;
+ }
+ }
+
+
for (;;)
{
- const UInt64 cluster = _virtPos >> _clusterBits;
- const size_t clusterSize = (size_t)1 << _clusterBits;
- const size_t lowBits = (size_t)_virtPos & (clusterSize - 1);
+ const UInt64 vir = _virtPos - extent.StartOffset;
+ const unsigned clusterBits = extent.ClusterBits;
+ const UInt64 cluster = vir >> clusterBits;
+ const size_t clusterSize = (size_t)1 << clusterBits;
+ const size_t lowBits = (size_t)vir & (clusterSize - 1);
{
size_t rem = clusterSize - lowBits;
if (size > rem)
size = (UInt32)rem;
}
- if (cluster == _cacheCluster)
+ if (extentIndex == _cacheExtent && cluster == _cacheCluster)
{
memcpy(data, _cache + lowBits, size);
_virtPos += size;
@@ -284,9 +613,9 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
const UInt64 high = cluster >> k_NumMidBits;
- if (high < _tables.Size())
+ if (high < extent.Tables.Size())
{
- const CByteBuffer &table = _tables[(unsigned)high];
+ const CByteBuffer &table = extent.Tables[(unsigned)high];
if (table.Size() != 0)
{
@@ -294,28 +623,27 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
const Byte *p = (const Byte *)table + (midBits << 2);
const UInt32 v = Get32(p);
- if (v != 0 && v != _zeroSector)
+ if (v != 0 && v != extent.ZeroSector)
{
UInt64 offset = (UInt64)v << 9;
- if (_needDeflate)
+ if (extent.NeedDeflate)
{
- if (offset != _posInArc)
+ if (offset != extent.PosInArc)
{
- // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - _posInArc));
- RINOK(Seek(offset));
+ // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc));
+ RINOK(extent.Seek(offset));
}
const size_t kStartSize = 1 << 9;
{
size_t curSize = kStartSize;
- HRESULT res = ReadStream(Stream, _cacheCompressed, &curSize);
- _posInArc += curSize;
- RINOK(res);
+ RINOK(extent.Read(_cacheCompressed, &curSize));
+ // _stream_PackSize += curSize;
if (curSize != kStartSize)
return S_FALSE;
}
- if (Get64(_cacheCompressed) != (cluster << (_clusterBits - 9)))
+ if (Get64(_cacheCompressed) != (cluster << (clusterBits - 9)))
return S_FALSE;
UInt32 dataSize = Get32(_cacheCompressed + 8);
@@ -331,9 +659,8 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
return S_FALSE;
size_t curSize = dataSize2 - kStartSize;
const size_t curSize2 = curSize;
- HRESULT res = ReadStream(Stream, _cacheCompressed + kStartSize, &curSize);
- _posInArc += curSize;
- RINOK(res);
+ RINOK(extent.Read(_cacheCompressed + kStartSize, &curSize));
+ // _stream_PackSize += curSize;
if (curSize != curSize2)
return S_FALSE;
}
@@ -341,6 +668,8 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
_bufInStreamSpec->Init(_cacheCompressed + 12, dataSize);
_cacheCluster = (UInt64)(Int64)-1;
+ _cacheExtent = (unsigned)(int)-1;
+
if (_cache.Size() < clusterSize)
return E_FAIL;
_bufOutStreamSpec->Init(_cache, clusterSize);
@@ -349,16 +678,26 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
UInt64 blockSize64 = clusterSize;
HRESULT res = _zlibDecoderSpec->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
- // if (_bufOutStreamSpec->GetPos() != clusterSize)
- // memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
+ /*
+ if (_bufOutStreamSpec->GetPos() != clusterSize)
+ {
+ _stream_dataError = true;
+ memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
+ }
+ */
- if (res == S_OK)
if (_bufOutStreamSpec->GetPos() != clusterSize
|| _zlibDecoderSpec->GetInputProcessedSize() != dataSize)
- res = S_FALSE;
+ {
+ _stream_dataError = true;
+ if (res == S_OK)
+ res = S_FALSE;
+ }
RINOK(res);
+
_cacheCluster = cluster;
+ _cacheExtent = extentIndex;
continue;
/*
@@ -371,16 +710,29 @@ STDMETHODIMP CHandler::Read(void *data, UInt32 size, UInt32 *processedSize)
}
{
offset += lowBits;
- if (offset != _posInArc)
+ if (offset != extent.PosInArc)
{
- // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - _posInArc));
- RINOK(Seek(offset));
+ // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc));
+ RINOK(extent.Seek(offset));
}
- HRESULT res = Stream->Read(data, size, &size);
- _posInArc += size;
- _virtPos += size;
+ UInt32 size2 = 0;
+ HRESULT res = extent.Stream->Read(data, size, &size2);
+ if (res == S_OK && size2 == 0)
+ {
+ _stream_unavailData = true;
+ /*
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+ extent.PosInArc += size2;
+ // _stream_PackSize += size2;
+ _virtPos += size2;
if (processedSize)
- *processedSize = size;
+ *processedSize = size2;
return res;
}
}
@@ -404,9 +756,10 @@ static const Byte kProps[] =
static const Byte kArcProps[] =
{
+ kpidNumVolumes,
+ kpidMethod,
kpidClusterSize,
kpidHeadersSize,
- kpidMethod,
kpidId,
kpidName,
kpidComment
@@ -421,38 +774,72 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
COM_TRY_BEGIN
NCOM::CPropVariant prop;
+ const CExtent *e = NULL;
+ const CDescriptor *desc = NULL;
+
+ if (_isMultiVol)
+ desc = &_descriptor;
+ else if (_extents.Size() == 1)
+ {
+ e = &_extents[0];
+ desc = &e->Descriptor;
+ }
+
switch (propID)
{
case kpidMainSubfile: prop = (UInt32)0; break;
case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
- case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break;
- case kpidHeadersSize: prop = (h.overHead << 9); break;
+ case kpidClusterSize: prop = (UInt32)((UInt32)1 << _clusterBitsMax); break;
+ case kpidHeadersSize: if (e) prop = (e->h.overHead << 9); break;
case kpidMethod:
{
AString s;
- if (!_descriptor.createType.IsEmpty())
- s = _descriptor.createType;
-
- if (h.algo != 0)
+ if (desc && !desc->createType.IsEmpty())
+ s = desc->createType;
+
+ bool zlib = false;
+ bool marker = false;
+ int algo = -1;
+
+ FOR_VECTOR (i, _extents)
{
- s.Add_Space_if_NotEmpty();
- if (h.algo == 1)
- s += "zlib";
- else
+ const CExtent &extent = _extents[i];
+ if (!extent.IsOK || !extent.IsVmdk())
+ continue;
+
+ const CHeader &h = extent.h;
+
+ if (h.algo != 0)
{
- char temp[16];
- ConvertUInt32ToString(h.algo, temp);
- s += temp;
+ if (h.algo == 1)
+ zlib = true;
+ else if (algo != (int)h.algo)
+ {
+ s.Add_Space_if_NotEmpty();
+ char temp[16];
+ ConvertUInt32ToString(h.algo, temp);
+ s += temp;
+ algo = h.algo;
+ }
}
+
+ if (h.Is_Marker())
+ marker = true;
}
-
- if (h.Is_Marker())
+
+ if (zlib)
+ {
+ s.Add_Space_if_NotEmpty();
+ s += "zlib";
+ }
+
+ if (marker)
{
s.Add_Space_if_NotEmpty();
s += "Marker";
}
-
+
if (!s.IsEmpty())
prop = s;
break;
@@ -460,10 +847,10 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidComment:
{
- if (_descriptorBuf.Size() != 0)
+ if (e && e->DescriptorBuf.Size() != 0)
{
AString s;
- s.SetFrom_CalcLen((const char *)(const Byte *)_descriptorBuf, (unsigned)_descriptorBuf.Size());
+ s.SetFrom_CalcLen((const char *)(const Byte *)e->DescriptorBuf, (unsigned)e->DescriptorBuf.Size());
if (!s.IsEmpty() && s.Len() <= (1 << 16))
prop = s;
}
@@ -471,46 +858,38 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
}
case kpidId:
- if (!_descriptor.CID.IsEmpty())
+ if (desc && !desc->CID.IsEmpty())
{
- prop = _descriptor.CID;
+ prop = desc->CID;
break;
}
case kpidName:
{
- if (_descriptor.Extents.Size() == 1)
+ if (!_isMultiVol && desc && desc->Extents.Size() == 1)
{
- const AString &s = _descriptor.Extents[0];
- if (!s.IsEmpty())
+ const CExtentInfo &ei = desc->Extents[0];
+ if (!ei.FileName.IsEmpty())
{
- if (s.Back() == '"')
- {
- AString s2 = s;
- s2.DeleteBack();
- if (s2.Len() > 5 && StringsAreEqualNoCase_Ascii(s2.RightPtr(5), ".vmdk"))
- {
- int pos = s2.ReverseFind('"');
- if (pos >= 0)
- {
- s2.DeleteFrontal(pos + 1);
- prop = s2;
- }
- }
- }
+ UString u;
+ CDescriptor::GetUnicodeName(ei.FileName, u);
+ if (!u.IsEmpty())
+ prop = u;
}
}
break;
}
-
+
+ case kpidNumVolumes: if (_isMultiVol) prop = (UInt32)_extents.Size(); break;
+
case kpidErrorFlags:
{
UInt32 v = 0;
if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
- // if (_headerError) v |= kpv_ErrorFlags_HeadersError;
- if (!Stream && v == 0 && _isArc)
- v = kpv_ErrorFlags_HeadersError;
+ if (_unsupportedSome) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (_headerError) v |= kpv_ErrorFlags_HeadersError;
+ if (_missingVol) v |= kpv_ErrorFlags_UnexpectedEnd;
if (v != 0)
prop = v;
break;
@@ -533,9 +912,22 @@ STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIAN
case kpidSize: prop = _size; break;
case kpidPackSize:
{
- UInt64 ov = (h.overHead << 9);
- if (_phySize >= ov)
- prop = _phySize - ov;
+ UInt64 packSize = 0;
+ FOR_VECTOR (i, _extents)
+ {
+ const CExtent &e = _extents[i];
+ if (!e.IsOK)
+ continue;
+ if (e.IsVmdk() && !_isMultiVol)
+ {
+ UInt64 ov = (e.h.overHead << 9);
+ if (e.PhySize >= ov)
+ packSize += e.PhySize - ov;
+ }
+ else
+ packSize += e.PhySize;
+ }
+ prop = packSize;
break;
}
case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
@@ -556,19 +948,26 @@ static int inline GetLog(UInt64 num)
}
-HRESULT CHandler::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors)
+HRESULT CExtent::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors)
{
sector <<= 9;
RINOK(stream->Seek(sector, STREAM_SEEK_SET, NULL));
size_t size = numSectors << 9;
RINOK(ReadStream_FALSE(stream, data, size));
UInt64 end = sector + size;
- if (_phySize < end)
- _phySize = end;
+ if (PhySize < end)
+ PhySize = end;
return S_OK;
}
+void CHandler::CloseAtError()
+{
+ _extents.Clear();
+ CHandlerImg::CloseAtError();
+}
+
+
HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
{
const unsigned kSectoreSize = 512;
@@ -578,43 +977,242 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
if (headerSize < sizeof(k_Signature))
return S_FALSE;
+
+ CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
+
if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
{
const char *kSignature_Descriptor = "# Disk DescriptorFile";
- size_t k_SigDesc_Size = strlen(kSignature_Descriptor);
- if (headerSize >= k_SigDesc_Size)
- if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) == 0)
+ const size_t k_SigDesc_Size = strlen(kSignature_Descriptor);
+ if (headerSize < k_SigDesc_Size)
+ return S_FALSE;
+ if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) != 0)
+ return S_FALSE;
+
+ UInt64 endPos;
+ RINOK(stream->Seek(0, STREAM_SEEK_END, &endPos));
+ if (endPos > (1 << 20))
+ return S_FALSE;
+ const size_t numBytes = (size_t)endPos;
+ _descriptorBuf.Alloc(numBytes);
+ RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
+ RINOK(ReadStream_FALSE(stream, _descriptorBuf, numBytes));
+
+ if (!_descriptor.Parse(_descriptorBuf, _descriptorBuf.Size()))
+ return S_FALSE;
+ _isMultiVol = true;
+ _isArc = true;
+ _phySize = numBytes;
+ if (_descriptor.IsThere_Parent())
+ _unsupported = true;
+
+ if (openCallback)
+ {
+ openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
+ }
+ if (!volumeCallback)
+ {
+ _unsupported = true;
+ return E_NOTIMPL;
+ }
+
+ /*
+ UInt64 totalVirtSize = 0;
+ FOR_VECTOR (i, _descriptor.Extents)
+ {
+ const CExtentInfo &ei = _descriptor.Extents[i];
+ if (ei.NumSectors >= ((UInt64)1 << (63 - 9)))
+ return S_FALSE;
+ totalVirtSize += ei.NumSectors;
+ if (totalVirtSize >= ((UInt64)1 << (63 - 9)))
+ return S_FALSE;
+ }
+ totalVirtSize <<= 9;
+ */
+
+ if (_descriptor.Extents.Size() > 1)
+ {
+ const UInt64 numFiles = _descriptor.Extents.Size();
+ RINOK(openCallback->SetTotal(&numFiles, NULL));
+ }
+ }
+
+ UInt64 complexity = 0;
+
+ for (;;)
+ {
+ CExtent *e = NULL;
+ CMyComPtr<IInStream> nextStream;
+
+ if (_isMultiVol)
+ {
+ const unsigned extentIndex = _extents.Size();
+ if (extentIndex >= _descriptor.Extents.Size())
+ break;
+ const CExtentInfo &ei = _descriptor.Extents[extentIndex];
+ e = &_extents.AddNew();
+ e->StartOffset = 0;
+ if (ei.NumSectors >= ((UInt64)1 << (62 - 9)) ||
+ ei.StartSector >= ((UInt64)1 << (62 - 9)))
+ return S_FALSE;
+ e->NumBytes = ei.NumSectors << 9;
+ e->IsZero = ei.IsType_ZERO();
+ if (extentIndex != 0)
+ e->StartOffset = _extents[extentIndex - 1].GetEndOffset();
+ if (e->GetEndOffset() < e->StartOffset)
+ return S_FALSE;
+
+ e->VirtSize = e->NumBytes;
+ if (e->IsZero)
{
- _unsupported = true;
- _isArc = true;
- // return E_NOTIMPL;
+ e->IsOK = true;
+ continue;
}
- return S_FALSE;
+
+ e->IsFlat = ei.IsType_Flat();
+ e->FlatOffset = ei.StartSector << 9;
+
+ UString u;
+ CDescriptor::GetUnicodeName(ei.FileName, u);
+ if (u.IsEmpty())
+ {
+ _missingVol = true;
+ continue;
+ }
+
+ HRESULT result = volumeCallback->GetStream(u, &nextStream);
+ if (result == S_FALSE)
+ {
+ _missingVol = true;
+ continue;
+ }
+ if (result != S_OK)
+ return result;
+ if (!nextStream)
+ {
+ _missingVol = true;
+ continue;
+ }
+
+ if (e->IsFlat)
+ {
+ e->IsOK = true;
+ e->Stream = nextStream;
+ e->PhySize = e->NumBytes;
+ continue;
+ }
+
+ stream = nextStream;
+
+ headerSize = kSectoreSize;
+ RINOK(ReadStream(stream, buf, &headerSize));
+
+ if (headerSize != kSectoreSize)
+ continue;
+ if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
+ continue;
+ }
+ else
+ {
+ if (headerSize != kSectoreSize)
+ return S_FALSE;
+ e = &_extents.AddNew();
+ e->StartOffset = 0;
+ }
+
+ HRESULT res = S_FALSE;
+ if (e->h.Parse(buf))
+ res = e->Open3(stream, openCallback, _isMultiVol ? _descriptor.Extents.Size() : 1, _extents.Size() - 1, complexity);
+
+ if (!_isMultiVol)
+ {
+ _isArc = e->IsArc;
+ _phySize = e->PhySize;
+ _unsupported = e->Unsupported;
+ }
+
+ if (e->Unsupported)
+ _unsupportedSome = true;
+ if (e->HeadersError)
+ _headerError = true;
+
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ if (!_isMultiVol)
+ return res;
+ continue;
+ }
+
+ e->Stream = stream;
+ e->IsOK = true;
+
+ if (!_isMultiVol)
+ {
+ e->NumBytes = e->VirtSize;
+ break;
+ }
+
+ if (e->NumBytes != e->VirtSize)
+ _headerError = true;
}
- if (headerSize != kSectoreSize)
- return S_FALSE;
+ if (!_extents.IsEmpty())
+ _size = _extents.Back().GetEndOffset();
- // CHeader h;
+ _needDeflate = false;
+ _clusterBitsMax = 0;
+
+ unsigned numOKs = 0;
+ unsigned numUnsupported = 0;
- if (!h.Parse(buf))
- return S_FALSE;
+ FOR_VECTOR (i, _extents)
+ {
+ const CExtent &e = _extents[i];
+ if (e.Unsupported)
+ numUnsupported++;
+ if (!e.IsOK)
+ continue;
+ numOKs++;
+ if (e.IsVmdk())
+ {
+ if (e.NeedDeflate)
+ _needDeflate = true;
+ if (_clusterBitsMax < e.ClusterBits)
+ _clusterBitsMax = e.ClusterBits;
+ }
+ }
+
+ if (numUnsupported != 0 && numUnsupported == _extents.Size())
+ _unsupported = true;
+
+ return S_OK;
+}
+
+HRESULT CExtent::Open3(IInStream *stream, IArchiveOpenCallback *openCallback,
+ unsigned numVols, unsigned volIndex, UInt64 &complexity)
+{
if (h.descriptorSize != 0)
{
- if (h.descriptorOffset < 1)
- return S_FALSE;
- if (h.descriptorSize > (1 << 20))
+ if (h.descriptorOffset == 0 ||
+ h.descriptorSize > (1 << 10))
return S_FALSE;
- size_t numBytes = (size_t)h.descriptorSize << 9;
- _descriptorBuf.Alloc(numBytes);
- RINOK(ReadForHeader(stream, h.descriptorOffset, _descriptorBuf, (size_t)h.descriptorSize));
- if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(_descriptorBuf) == 0)
+ DescriptorBuf.Alloc((size_t)h.descriptorSize << 9);
+ RINOK(ReadForHeader(stream, h.descriptorOffset, DescriptorBuf, (size_t)h.descriptorSize));
+ if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(DescriptorBuf) == 0)
{
// We check data as end marker.
// and if probably it's footer's copy of header, we don't want to open it.
return S_FALSE;
}
+
+ DescriptorOK = Descriptor.Parse(DescriptorBuf, DescriptorBuf.Size());
+ if (!DescriptorOK)
+ HeadersError = true;
+ if (Descriptor.IsThere_Parent())
+ Unsupported = true;
}
if (h.gdOffset == (UInt64)(Int64)-1)
@@ -647,7 +1245,7 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
m.Parse(buf2 + 512 * 2);
if (m.NumSectors != 0 || m.SpecSize != 0 || m.Type != k_Marker_END_OF_STREAM)
return S_FALSE;
- _phySize = endPos;
+ PhySize = endPos;
}
int grainSize_Log = GetLog(h.grainSize);
@@ -658,27 +1256,27 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
if (h.overHead >= ((UInt64)1 << (63 - 9)))
return S_FALSE;
- _isArc = true;
- _clusterBits = (9 + grainSize_Log);
- _size = h.capacity << 9;
- _needDeflate = (h.algo >= 1);
+ IsArc = true;
+ ClusterBits = (9 + grainSize_Log);
+ VirtSize = h.capacity << 9;
+ NeedDeflate = (h.algo >= 1);
if (h.Is_Compressed() ? (h.algo > 1 || !h.Is_Marker()) : (h.algo != 0))
{
- _unsupported = true;
- _phySize = 0;
+ Unsupported = true;
+ PhySize = 0;
return S_FALSE;
}
{
UInt64 overHeadBytes = h.overHead << 9;
- if (_phySize < overHeadBytes)
- _phySize = overHeadBytes;
+ if (PhySize < overHeadBytes)
+ PhySize = overHeadBytes;
}
- _zeroSector = 0;
+ ZeroSector = 0;
if (h.Is_ZeroGrain())
- _zeroSector = 1;
+ ZeroSector = 1;
const UInt64 numSectorsPerGde = (UInt64)1 << (grainSize_Log + k_NumMidBits);
const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> (grainSize_Log + k_NumMidBits);
@@ -713,12 +1311,22 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
RINOK(ReadForHeader(stream, h.gdOffset, table, numSectors));
}
- size_t clusterSize = (size_t)1 << _clusterBits;
+ const size_t clusterSize = (size_t)1 << ClusterBits;
+
+ const UInt64 complexityStart = complexity;
if (openCallback)
{
- UInt64 totalBytes = (UInt64)numGdeEntries << (k_NumMidBits + 2);
- RINOK(openCallback->SetTotal(NULL, &totalBytes));
+ complexity += (UInt64)numGdeEntries << (k_NumMidBits + 2);
+ {
+ const UInt64 numVols2 = numVols;
+ RINOK(openCallback->SetTotal((numVols == 1) ? NULL : &numVols2, &complexity));
+ }
+ if (numVols != 1)
+ {
+ const UInt64 volIndex2 = volIndex;
+ RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &complexityStart));
+ }
}
UInt64 lastSector = 0;
@@ -728,14 +1336,14 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
for (size_t i = 0; i < numGdeEntries; i++)
{
UInt32 v = Get32((const Byte *)table + (size_t)i * 4);
- CByteBuffer &buf = _tables.AddNew();
- if (v == 0 || v == _zeroSector)
+ CByteBuffer &buf = Tables.AddNew();
+ if (v == 0 || v == ZeroSector)
continue;
-
- if (openCallback && ((i - numProcessed_Prev) & 0xFFF) == 0)
+ if (openCallback && (i - numProcessed_Prev) >= 1024)
{
- UInt64 numBytes = (UInt64)i << (k_NumMidBits + 2);
- RINOK(openCallback->SetCompleted(NULL, &numBytes));
+ const UInt64 comp = complexityStart + ((UInt64)i << (k_NumMidBits + 2));
+ const UInt64 volIndex2 = volIndex;
+ RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &comp));
numProcessed_Prev = i;
}
@@ -764,25 +1372,24 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
for (size_t k = 0; k < k_NumMidItems; k++)
{
UInt32 v = Get32((const Byte *)buf + (size_t)k * 4);
- if (v == 0 || v == _zeroSector)
+ if (v == 0 || v == ZeroSector)
continue;
if (v < h.overHead)
return S_FALSE;
if (lastSector < v)
{
lastSector = v;
- if (_needDeflate)
+ if (NeedDeflate)
lastVirtCluster = ((UInt64)i << k_NumMidBits) + k;
}
}
}
-
- if (!_needDeflate)
+ if (!NeedDeflate)
{
UInt64 end = ((UInt64)lastSector << 9) + clusterSize;
- if (_phySize < end)
- _phySize = end;
+ if (PhySize < end)
+ PhySize = end;
}
else if (lastSector != 0)
{
@@ -790,27 +1397,18 @@ HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
if (ReadForHeader(stream, lastSector, buf, 1) == S_OK)
{
UInt64 lba = Get64(buf);
- if (lba == (lastVirtCluster << (_clusterBits - 9)))
+ if (lba == (lastVirtCluster << (ClusterBits - 9)))
{
UInt32 dataSize = Get32(buf + 8);
size_t dataSize2 = (size_t)dataSize + 12;
dataSize2 = (dataSize2 + 511) & ~(size_t)511;
UInt64 end = ((UInt64)lastSector << 9) + dataSize2;
- if (_phySize < end)
- _phySize = end;
+ if (PhySize < end)
+ PhySize = end;
}
}
}
- if (_descriptorBuf.Size() != 0)
- {
- _descriptor.Parse(_descriptorBuf, _descriptorBuf.Size());
- if (!_descriptor.parentCID.IsEmpty())
- if (!_descriptor.parentCID.IsEqualTo_Ascii_NoCase("ffffffff"))
- _unsupported = true;
- }
-
- Stream = stream;
return S_OK;
}
@@ -819,21 +1417,26 @@ STDMETHODIMP CHandler::Close()
{
_phySize = 0;
_size = 0;
+
_cacheCluster = (UInt64)(Int64)-1;
- _zeroSector = 0;
- _clusterBits = 0;
+ _cacheExtent = (unsigned)(int)-1;
+
+ _clusterBitsMax = 0;
- _needDeflate = false;
_isArc = false;
_unsupported = false;
- // _headerError = false;
+ _unsupportedSome = false;
+ _headerError = false;
+ _missingVol = false;
+ _isMultiVol = false;
+ _needDeflate = false;
- _tables.Clear();
_descriptorBuf.Free();
_descriptor.Clear();
_imgExt = NULL;
- Stream.Release();
+ Stream.Release(); // Stream vriable is unused
+ _extents.Clear();
return S_OK;
}
@@ -846,6 +1449,8 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
if (_unsupported)
return S_FALSE;
+ ClearStreamVars();
+ // _stream_UsePackSize = true;
if (_needDeflate)
{
@@ -867,13 +1472,18 @@ STDMETHODIMP CHandler::GetStream(UInt32 /* index */, ISequentialInStream **strea
_zlibDecoder = _zlibDecoderSpec;
}
- size_t clusterSize = (size_t)1 << _clusterBits;
+ const size_t clusterSize = (size_t)1 << _clusterBitsMax;
_cache.AllocAtLeast(clusterSize);
_cacheCompressed.AllocAtLeast(clusterSize * 2);
}
+ FOR_VECTOR (i, _extents)
+ {
+ RINOK(_extents[i].InitAndSeek());
+ }
+
CMyComPtr<ISequentialInStream> streamTemp = this;
- RINOK(InitAndSeek());
+ InitAndSeekMain();
*stream = streamTemp.Detach();
return S_OK;
COM_TRY_END