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>2015-10-18 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:56 +0300
commita663a6deb7a150f935fac7efdbf4d53d27369594 (patch)
treed1be306b33dd96050206da5774fff7bd9083ddfa /CPP/7zip/Archive
parent6543c280208393fa32cb0094f770d14c1cfb13b2 (diff)
15.0915.09
Diffstat (limited to 'CPP/7zip/Archive')
-rw-r--r--CPP/7zip/Archive/ApmHandler.cpp10
-rw-r--r--CPP/7zip/Archive/Chm/ChmHandler.cpp42
-rw-r--r--CPP/7zip/Archive/Chm/ChmIn.cpp15
-rw-r--r--CPP/7zip/Archive/Chm/ChmIn.h14
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp4
-rw-r--r--CPP/7zip/Archive/ExtHandler.cpp476
-rw-r--r--CPP/7zip/Archive/FatHandler.cpp24
-rw-r--r--CPP/7zip/Archive/GptHandler.cpp11
-rw-r--r--CPP/7zip/Archive/HandlerCont.cpp56
-rw-r--r--CPP/7zip/Archive/HandlerCont.h27
-rw-r--r--CPP/7zip/Archive/Iso/IsoHandler.cpp8
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.cpp8
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.h8
-rw-r--r--CPP/7zip/Archive/MbrHandler.cpp11
-rw-r--r--CPP/7zip/Archive/MubHandler.cpp11
-rw-r--r--CPP/7zip/Archive/NtfsHandler.cpp10
-rw-r--r--CPP/7zip/Archive/RpmHandler.cpp9
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.cpp2
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.h6
-rw-r--r--CPP/7zip/Archive/VmdkHandler.cpp1034
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.cpp4
21 files changed, 1375 insertions, 415 deletions
diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp
index fcd686aa..51719d53 100644
--- a/CPP/7zip/Archive/ApmHandler.cpp
+++ b/CPP/7zip/Archive/ApmHandler.cpp
@@ -83,8 +83,14 @@ class CHandler: public CHandlerCont
HRESULT ReadTables(IInStream *stream);
UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
- virtual UInt64 GetItemPos(UInt32 index) const { return BlocksToBytes(_items[index].StartBlock); }
- virtual UInt64 GetItemSize(UInt32 index) const { return BlocksToBytes(_items[index].NumBlocks); }
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const
+ {
+ const CItem &item = _items[index];
+ pos = BlocksToBytes(item.StartBlock);
+ size = BlocksToBytes(item.NumBlocks);
+ return NExtract::NOperationResult::kOK;
+ }
+
public:
INTERFACE_IInArchive_Cont(;)
};
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp
index 3e29fd00..2a72e8e9 100644
--- a/CPP/7zip/Archive/Chm/ChmHandler.cpp
+++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp
@@ -101,6 +101,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
+
if (m_Database.NewFormat)
{
switch (propID)
@@ -112,12 +113,15 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
prop.Detach(value);
return S_OK;
}
- int entryIndex;
+
+ unsigned entryIndex;
if (m_Database.LowLevel)
entryIndex = index;
else
entryIndex = m_Database.Indices[index];
+
const CItem &item = m_Database.Items[entryIndex];
+
switch (propID)
{
case kpidPath:
@@ -161,6 +165,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
#endif
}
+
prop.Detach(value);
return S_OK;
COM_TRY_END
@@ -244,9 +249,9 @@ public:
UInt64 m_PosInFolder;
UInt64 m_PosInSection;
const CRecordVector<bool> *m_ExtractStatuses;
- int m_StartIndex;
- int m_CurrentIndex;
- int m_NumFiles;
+ unsigned m_StartIndex;
+ unsigned m_CurrentIndex;
+ unsigned m_NumFiles;
private:
const CFilesDatabase *m_Database;
@@ -298,7 +303,7 @@ HRESULT CChmFolderOutStream::WriteEmptyFiles()
{
if (m_FileIsOpen)
return S_OK;
- for (;m_CurrentIndex < m_NumFiles; m_CurrentIndex++)
+ for (; m_CurrentIndex < m_NumFiles; m_CurrentIndex++)
{
UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex);
if (fileSize != 0)
@@ -368,7 +373,7 @@ HRESULT CChmFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *proce
// return E_FAIL;
}
- int fullIndex = m_StartIndex + m_CurrentIndex;
+ unsigned fullIndex = m_StartIndex + m_CurrentIndex;
m_RemainFileSize = m_Database->GetFileSize(fullIndex);
UInt64 fileOffset = m_Database->GetFileOffset(fullIndex);
if (fileOffset < m_PosInSection)
@@ -408,7 +413,7 @@ HRESULT CChmFolderOutStream::FlushCorrupted(UInt64 maxSize)
{
const UInt32 kBufferSize = (1 << 10);
Byte buffer[kBufferSize];
- for (int i = 0; i < kBufferSize; i++)
+ for (unsigned i = 0; i < kBufferSize; i++)
buffer[i] = 0;
if (maxSize > m_FolderSize)
maxSize = m_FolderSize;
@@ -531,9 +536,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
for (i = 0; i < numItems; i++)
{
UInt32 index = allFilesMode ? i : indices[i];
- int entryIndex = m_Database.Indices[index];
- const CItem &item = m_Database.Items[entryIndex];
- UInt64 sectionIndex = item.Section;
+ const CItem &item = m_Database.Items[m_Database.Indices[index]];
+ const UInt64 sectionIndex = item.Section;
if (item.IsDir() || item.Size == 0)
continue;
if (sectionIndex == 0)
@@ -567,14 +571,17 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
CByteBuffer packBuf;
- for (i = 0; i < numItems;)
+ for (i = 0;;)
{
RINOK(extractCallback->SetCompleted(&currentTotalSize));
+
+ if (i >= numItems)
+ break;
+
UInt32 index = allFilesMode ? i : indices[i];
i++;
- int entryIndex = m_Database.Indices[index];
- const CItem &item = m_Database.Items[entryIndex];
- UInt64 sectionIndex = item.Section;
+ const CItem &item = m_Database.Items[m_Database.Indices[index]];
+ const UInt64 sectionIndex = item.Section;
Int32 askMode= testMode ?
NExtract::NAskMode::kTest :
NExtract::NAskMode::kExtract;
@@ -645,7 +652,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 folderIndex = m_Database.GetFolder(index);
- UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
+ const UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
RINOK(lzxDecoderSpec->SetParams_and_Alloc(lzxInfo.GetNumDictBits()));
const CItem *lastItem = &item;
@@ -673,9 +680,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
for (; i < numItems; i++)
{
- UInt32 nextIndex = allFilesMode ? i : indices[i];
- int entryIndex = m_Database.Indices[nextIndex];
- const CItem &nextItem = m_Database.Items[entryIndex];
+ const UInt32 nextIndex = allFilesMode ? i : indices[i];
+ const CItem &nextItem = m_Database.Items[m_Database.Indices[nextIndex]];
if (nextItem.Section != sectionIndex)
break;
UInt64 nextFolderIndex = m_Database.GetFolder(nextIndex);
diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp
index d7556b89..6bdf2af4 100644
--- a/CPP/7zip/Archive/Chm/ChmIn.cpp
+++ b/CPP/7zip/Archive/Chm/ChmIn.cpp
@@ -656,7 +656,7 @@ static AString GetSectionPrefix(const AString &name)
#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
-static int CompareFiles(const int *p1, const int *p2, void *param)
+static int CompareFiles(const unsigned *p1, const unsigned *p2, void *param)
{
const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
const CItem &item1 = items[*p1];
@@ -731,7 +731,7 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
RINOK(DecompressStream(inStream, database, kNameList));
/* UInt16 length = */ ReadUInt16();
UInt16 numSections = ReadUInt16();
- for (int i = 0; i < numSections; i++)
+ for (unsigned i = 0; i < numSections; i++)
{
CSectionInfo section;
UInt16 nameLen = ReadUInt16();
@@ -766,10 +766,10 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
RINOK(DecompressStream(inStream, database, transformPrefix + kTransformList));
if ((_chunkSize & 0xF) != 0)
return S_FALSE;
- int numGuids = (int)(_chunkSize / 0x10);
+ unsigned numGuids = (unsigned)(_chunkSize / 0x10);
if (numGuids < 1)
return S_FALSE;
- for (int i = 0; i < numGuids; i++)
+ for (unsigned i = 0; i < numGuids; i++)
{
CMethodInfo method;
ReadGUID(method.Guid);
@@ -803,14 +803,17 @@ HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
return S_FALSE;
{
- int n = GetLog(ReadUInt32());
+ // There is bug in VC6, if we use function call as parameter for inline function
+ UInt32 val32 = ReadUInt32();
+ int n = GetLog(val32);
if (n < 0 || n > 16)
return S_FALSE;
li.ResetIntervalBits = n;
}
{
- int n = GetLog(ReadUInt32());
+ UInt32 val32 = ReadUInt32();
+ int n = GetLog(val32);
if (n < 0 || n > 16)
return S_FALSE;
li.WindowSizeBits = n;
diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h
index dc5e8263..60852852 100644
--- a/CPP/7zip/Archive/Chm/ChmIn.h
+++ b/CPP/7zip/Archive/Chm/ChmIn.h
@@ -177,25 +177,25 @@ class CFilesDatabase: public CDatabase
{
public:
bool LowLevel;
- CRecordVector<int> Indices;
+ CUIntVector Indices;
CObjectVector<CSectionInfo> Sections;
- UInt64 GetFileSize(int fileIndex) const { return Items[Indices[fileIndex]].Size; }
- UInt64 GetFileOffset(int fileIndex) const { return Items[Indices[fileIndex]].Offset; }
+ UInt64 GetFileSize(unsigned fileIndex) const { return Items[Indices[fileIndex]].Size; }
+ UInt64 GetFileOffset(unsigned fileIndex) const { return Items[Indices[fileIndex]].Offset; }
- UInt64 GetFolder(int fileIndex) const
+ UInt64 GetFolder(unsigned fileIndex) const
{
const CItem &item = Items[Indices[fileIndex]];
- const CSectionInfo &section = Sections[(int)item.Section];
+ const CSectionInfo &section = Sections[(unsigned)item.Section];
if (section.IsLzx())
return section.Methods[0].LzxInfo.GetFolder(item.Offset);
return 0;
}
- UInt64 GetLastFolder(int fileIndex) const
+ UInt64 GetLastFolder(unsigned fileIndex) const
{
const CItem &item = Items[Indices[fileIndex]];
- const CSectionInfo &section = Sections[(int)item.Section];
+ const CSectionInfo &section = Sections[(unsigned)item.Section];
if (section.IsLzx())
return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1);
return 0;
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
index e24074a5..3a4834cd 100644
--- a/CPP/7zip/Archive/ComHandler.cpp
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -433,9 +433,9 @@ HRESULT CDatabase::Open(IInStream *inStream)
SectorSizeBits = sectorSizeBits;
MiniSectorSizeBits = miniSectorSizeBits;
- if (sectorSizeBits > 28 ||
+ if (sectorSizeBits > 24 ||
sectorSizeBits < 7 ||
- miniSectorSizeBits > 28 ||
+ miniSectorSizeBits > 24 ||
miniSectorSizeBits < 2 ||
miniSectorSizeBits > sectorSizeBits)
return S_FALSE;
diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp
index 6d8101f5..a9d0facb 100644
--- a/CPP/7zip/Archive/ExtHandler.cpp
+++ b/CPP/7zip/Archive/ExtHandler.cpp
@@ -4,6 +4,11 @@
// #define SHOW_DEBUG_INFO
+// #include <stdio.h>
+// #define PRF2(x) x
+
+#define PRF2(x)
+
#ifdef SHOW_DEBUG_INFO
#include <stdio.h>
#define PRF(x) x
@@ -23,7 +28,6 @@
#include "../../Windows/PropVariantUtils.h"
#include "../../Windows/TimeUtils.h"
-#include "../Common/LimitedStreams.h"
#include "../Common/ProgressUtils.h"
#include "../Common/RegisterArc.h"
#include "../Common/StreamObjects.h"
@@ -300,7 +304,7 @@ struct CHeader
// UInt64 NumBlocksSuper;
UInt64 NumFreeBlocks;
UInt32 NumFreeInodes;
- UInt32 FirstDataBlock;
+ // UInt32 FirstDataBlock;
UInt32 BlocksPerGroup;
UInt32 ClustersPerGroup;
@@ -349,6 +353,7 @@ struct CHeader
bool IsOldRev() const { return RevLevel == EXT4_GOOD_OLD_REV; }
UInt64 GetNumGroups() const { return (NumBlocks + BlocksPerGroup - 1) / BlocksPerGroup; }
+ UInt64 GetNumGroups2() const { return ((UInt64)NumInodes + InodesPerGroup - 1) / InodesPerGroup; }
bool IsThereFileType() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_FILETYPE) != 0; }
bool Is64Bit() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0; }
@@ -367,6 +372,15 @@ static int inline GetLog(UInt32 num)
return -1;
}
+static bool inline IsEmptyData(const Byte *data, unsigned size)
+{
+ for (unsigned i = 0; i < size; i++)
+ if (data[i] != 0)
+ return false;
+ return true;
+}
+
+
bool CHeader::Parse(const Byte *p)
{
if (GetUi16(p + 0x38) != 0xEF53)
@@ -375,21 +389,25 @@ bool CHeader::Parse(const Byte *p)
LE_32 (0x18, BlockBits);
LE_32 (0x1C, ClusterBits);
- if (ClusterBits != 0 && BlockBits != ClusterBits)
+ if (ClusterBits != 0 && BlockBits != ClusterBits)
return false;
- if (BlockBits > 16 - 10) return false;
+ if (BlockBits > 16 - 10)
+ return false;
BlockBits += 10;
- if (ClusterBits > 16) return false;
LE_32 (0x00, NumInodes);
LE_32 (0x04, NumBlocks);
// LE_32 (0x08, NumBlocksSuper);
LE_32 (0x0C, NumFreeBlocks);
LE_32 (0x10, NumFreeInodes);
- LE_32 (0x14, FirstDataBlock);
- if (FirstDataBlock != 0)
+ if (NumInodes < 2 || NumInodes <= NumFreeInodes)
+ return false;
+
+ UInt32 FirstDataBlock;
+ LE_32 (0x14, FirstDataBlock);
+ if (FirstDataBlock != (unsigned)(BlockBits == 10 ? 1 : 0))
return false;
LE_32 (0x20, BlocksPerGroup);
@@ -397,10 +415,18 @@ bool CHeader::Parse(const Byte *p)
if (BlocksPerGroup != ClustersPerGroup)
return false;
- if (BlocksPerGroup != ((UInt32)1 << (BlockBits + 3)))
+ if (BlocksPerGroup == 0)
return false;
+ if (BlocksPerGroup != ((UInt32)1 << (BlockBits + 3)))
+ {
+ // it's allowed in ext2
+ // return false;
+ }
LE_32 (0x28, InodesPerGroup);
+
+ if (InodesPerGroup < 1 || InodesPerGroup > NumInodes)
+ return false;
LE_32 (0x2C, MountTime);
LE_32 (0x30, WriteTime);
@@ -485,6 +511,9 @@ bool CHeader::Parse(const Byte *p)
if (NumFreeBlocks > NumBlocks)
return false;
+ if (GetNumGroups() != GetNumGroups2())
+ return false;
+
return true;
}
@@ -612,7 +641,7 @@ struct CExtTime
struct CNode
{
- Int32 ParentNode; // in _nodes[], -1 if not dir
+ Int32 ParentNode; // in _refs[], -1 if not dir
int ItemIndex; // in _items[]
int SymLinkIndex; // in _symLinks[]
int DirIndex; // in _dirs[]
@@ -621,7 +650,6 @@ struct CNode
UInt16 Uid;
UInt16 Gid;
// UInt16 Checksum;
- bool IsEmpty;
UInt64 FileSize;
CExtTime MTime;
@@ -662,6 +690,7 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
MTime.Extra = 0;
ATime.Extra = 0;
CTime.Extra = 0;
+ CTime.Val = 0;
// InodeChangeTime.Extra = 0;
// DTime.Extra = 0;
@@ -692,14 +721,21 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
FileSize |= ((UInt64)highSize << 32);
}
+ // UInt32 fragmentAddress;
// LE_32 (0x70, fragmentAddress);
// osd2
{
// Linux;
+ // ext2:
+ // Byte FragmentNumber = p[0x74];
+ // Byte FragmentSize = p[0x74 + 1];
+
+ // ext4:
UInt32 numBlocksHigh;
LE_16 (0x74, numBlocksHigh);
NumBlocks |= (UInt64)numBlocksHigh << 32;
+
HI_16 (0x74 + 4, Uid);
HI_16 (0x74 + 6, Gid);
/*
@@ -738,8 +774,8 @@ bool CNode::Parse(const Byte *p, const CHeader &_h)
struct CItem
{
- unsigned Node; // in _nodes[]
- int ParentNode; // in _nodes[]
+ unsigned Node; // in _refs[]
+ int ParentNode; // in _refs[]
int SymLinkItemIndex; // in _items[], if the Node contains SymLink to existing dir
Byte Type;
@@ -778,6 +814,7 @@ class CHandler:
public CMyUnknownImp
{
CObjectVector<CItem> _items;
+ CIntVector _refs;
CRecordVector<CNode> _nodes;
CObjectVector<CUIntVector> _dirs; // each CUIntVector contains indexes in _items[] only for dir items;
AStringVector _symLinks;
@@ -789,6 +826,7 @@ class CHandler:
UInt64 _phySize;
bool _isArc;
bool _headersError;
+ bool _headersWarning;
bool _linksError;
bool _isUTF;
@@ -831,14 +869,14 @@ class CHandler:
}
HRESULT SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size);
- HRESULT ParseDir(const Byte *data, size_t size, unsigned nodeIndex);
+ HRESULT ParseDir(const Byte *data, size_t size, unsigned iNodeDir);
int FindTargetItem_for_SymLink(unsigned dirNode, const AString &path) const;
HRESULT FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector<UInt32> &blocks);
HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks);
HRESULT FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &extents, int parentDepth);
- HRESULT GetStream_Node(UInt32 nodeIndex, ISequentialInStream **stream);
+ HRESULT GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream);
HRESULT ExtractNode(unsigned nodeIndex, CByteBuffer &data);
void ClearRefs();
@@ -860,13 +898,13 @@ public:
-HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
+HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned iNodeDir)
{
bool isThereSelfLink = false;
- PRF(printf("\n\n========= node = %5d size = %5d", nodeIndex, size));
+ PRF(printf("\n\n========= node = %5d size = %5d", (unsigned)iNodeDir, (unsigned)size));
- CNode &nodeDir = _nodes[nodeIndex];
+ CNode &nodeDir = _nodes[_refs[iNodeDir]];
nodeDir.DirIndex = _dirs.Size();
CUIntVector &dir = _dirs.AddNew();
int parentNode = -1;
@@ -891,7 +929,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
if (nameLen + 8 > recLen)
return S_FALSE;
- if (iNode >= _nodes.Size())
+ if (iNode >= _refs.Size())
return S_FALSE;
item.Clear();
@@ -901,7 +939,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
else if (type != 0)
return S_FALSE;
- item.ParentNode = nodeIndex;
+ item.ParentNode = iNodeDir;
item.Node = iNode;
item.Name.SetFrom_CalcLen((const char *)(p + 8), nameLen);
@@ -922,7 +960,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
return S_FALSE;
*/
- PRF(printf("\n EMPTY %6d %d %s", recLen, type, (const char *)item.Name));
+ PRF(printf("\n EMPTY %6d %d %s", (unsigned)recLen, (unsigned)type, (const char *)item.Name));
if (type == 0xDE)
{
// checksum
@@ -930,9 +968,10 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
continue;
}
- CNode &node = _nodes[iNode];
- if (node.IsEmpty)
+ int nodeIndex = _refs[iNode];
+ if (nodeIndex < 0)
return S_FALSE;
+ CNode &node = _nodes[nodeIndex];
if (_h.IsThereFileType() && type != 0)
{
@@ -944,7 +983,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
node.NumLinksCalced++;
- PRF(printf("\n%s %6d %s", item.IsDir() ? "DIR " : " ", item.Node, (const char *)item.Name));
+ PRF(printf("\n%s %6d %s", item.IsDir() ? "DIR " : " ", (unsigned)item.Node, (const char *)item.Name));
if (item.Name[0] == '.')
{
@@ -953,7 +992,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
if (isThereSelfLink)
return S_FALSE;
isThereSelfLink = true;
- if (nodeIndex != nodeIndex)
+ if (iNode != iNodeDir)
return S_FALSE;
continue;
}
@@ -964,7 +1003,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
return S_FALSE;
if (!node.IsDir())
return S_FALSE;
- if (iNode == nodeIndex && iNode != k_INODE_ROOT)
+ if (iNode == iNodeDir && iNode != k_INODE_ROOT)
return S_FALSE;
parentNode = iNode;
@@ -978,7 +1017,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
}
}
- if (iNode == nodeIndex)
+ if (iNode == iNodeDir)
return S_FALSE;
if (parentNode < 0)
@@ -987,8 +1026,8 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
if (node.IsDir())
{
if (node.ParentNode < 0)
- node.ParentNode = nodeIndex;
- else if ((unsigned)node.ParentNode != nodeIndex)
+ node.ParentNode = iNodeDir;
+ else if ((unsigned)node.ParentNode != iNodeDir)
return S_FALSE;
const unsigned itemIndex = _items.Size();
dir.Add(itemIndex);
@@ -1005,7 +1044,7 @@ HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned nodeIndex)
}
-int CHandler::FindTargetItem_for_SymLink(unsigned nodeIndex, const AString &path) const
+int CHandler::FindTargetItem_for_SymLink(unsigned iNode, const AString &path) const
{
unsigned pos = 0;
@@ -1014,8 +1053,8 @@ int CHandler::FindTargetItem_for_SymLink(unsigned nodeIndex, const AString &path
if (path[0] == '/')
{
- nodeIndex = k_INODE_ROOT;
- if (nodeIndex >= _nodes.Size())
+ iNode = k_INODE_ROOT;
+ if (iNode >= _refs.Size())
return -1;
pos = 1;
}
@@ -1024,7 +1063,7 @@ int CHandler::FindTargetItem_for_SymLink(unsigned nodeIndex, const AString &path
while (pos != path.Len())
{
- const CNode &node = _nodes[nodeIndex];
+ const CNode &node = _nodes[_refs[iNode]];
int slash = path.Find('/', pos);
if (slash < 0)
@@ -1046,9 +1085,9 @@ int CHandler::FindTargetItem_for_SymLink(unsigned nodeIndex, const AString &path
{
if (node.ParentNode < 0)
return -1;
- if (nodeIndex == k_INODE_ROOT)
+ if (iNode == k_INODE_ROOT)
return -1;
- nodeIndex = node.ParentNode;
+ iNode = node.ParentNode;
continue;
}
}
@@ -1065,13 +1104,13 @@ int CHandler::FindTargetItem_for_SymLink(unsigned nodeIndex, const AString &path
const CItem &item = _items[dir[i]];
if (item.Name == s)
{
- nodeIndex = item.Node;
+ iNode = item.Node;
break;
}
}
}
- return _nodes[nodeIndex].ItemIndex;
+ return _nodes[_refs[iNode]].ItemIndex;
}
@@ -1178,7 +1217,10 @@ HRESULT CHandler::Open2(IInStream *inStream)
UInt32 numReserveInodes = _h.NumInodes - _h.NumFreeInodes + 1;
// numReserveInodes = _h.NumInodes + 1;
if (numReserveInodes != 0)
+ {
_nodes.Reserve(numReserveInodes);
+ _refs.Reserve(numReserveInodes);
+ }
UInt32 numNodes = _h.InodesPerGroup;
if (numNodes > _h.NumInodes)
@@ -1195,6 +1237,8 @@ HRESULT CHandler::Open2(IInStream *inStream)
nodesMap.Alloc(blockSize);
unsigned globalNodeIndex = 0;
+ // unsigned numEmpty = 0;
+ unsigned numEmpty_in_Maps = 0;
FOR_VECTOR (gi, groups)
{
@@ -1203,40 +1247,40 @@ HRESULT CHandler::Open2(IInStream *inStream)
const CGroupDescriptor &gd = groups[gi];
- PRF(printf("\n\ng%6d block = %6x\n", gi, gd.InodeTable));
+ PRF(printf("\n\ng%6d block = %6x\n", gi, (unsigned)gd.InodeTable));
RINOK(SeekAndRead(inStream, gd.InodeBitmap, nodesMap, blockSize));
RINOK(SeekAndRead(inStream, gd.InodeTable, nodesData, nodesDataSize));
+
+ unsigned numEmpty_in_Map = 0;
for (size_t n = 0; n < numNodes && globalNodeIndex < _h.NumInodes; n++, globalNodeIndex++)
{
if ((nodesMap[n >> 3] & ((unsigned)1 << (n & 7))) == 0)
+ {
+ numEmpty_in_Map++;
continue;
+ }
const Byte *p = nodesData + (size_t)n * _h.InodeSize;
- unsigned j = 0;
- for (j = 0; j < _h.InodeSize; j++)
- if (p[j] != 0)
- break;
-
- if (j == _h.InodeSize)
+ if (IsEmptyData(p, _h.InodeSize))
{
- if (_nodes.Size() >= _h.FirstInode)
+ if (globalNodeIndex + 1 >= _h.FirstInode)
{
+ _headersError = true;
// return S_FALSE;
}
continue;
}
CNode node;
- node.IsEmpty = false;
PRF(printf("\nnode = %5d ", (unsigned)n));
if (!node.Parse(p, _h))
return S_FALSE;
- // PRF(printf("\n %6d", n));
+ // PRF(printf("\n %6d", (unsigned)n));
/*
SetUi32(p + 0x7C, 0)
SetUi32(p + 0x82, 0)
@@ -1249,19 +1293,36 @@ HRESULT CHandler::Open2(IInStream *inStream)
if (crc != node.Checksum) return S_FALSE;
*/
- while (_nodes.Size() < globalNodeIndex + 1)
+ while (_refs.Size() < globalNodeIndex + 1)
{
- CNode node2;
- node2.IsEmpty = true;
- _nodes.Add(node2);
+ // numEmpty++;
+ _refs.Add(-1);
}
- _nodes.Add(node);
+ _refs.Add(_nodes.Add(node));
+ }
+
+
+ numEmpty_in_Maps += numEmpty_in_Map;
+
+ if (numEmpty_in_Map != gd.NumFreeInodes)
+ {
+ _headersWarning = true;
+ // return S_FALSE;
}
}
- if (_nodes.Size() <= k_INODE_ROOT)
+ if (numEmpty_in_Maps != _h.NumFreeInodes)
+ {
+ // some ext2 examples has incorrect value in _h.NumFreeInodes.
+ // so we disable check;
+ _headersWarning = true;
+ }
+
+ if (_refs.Size() <= k_INODE_ROOT)
return S_FALSE;
+
+ // printf("\n numReserveInodes = %6d, _refs.Size() = %d, numEmpty = %7d\n", numReserveInodes, _refs.Size(), (unsigned)numEmpty);
}
}
@@ -1272,14 +1333,17 @@ HRESULT CHandler::Open2(IInStream *inStream)
CByteBuffer dataBuf;
- FOR_VECTOR (i, _nodes)
+ FOR_VECTOR (i, _refs)
{
+ int nodeIndex = _refs[i];
{
- const CNode &node = _nodes[i];
- if (node.IsEmpty || !node.IsDir())
+ if (nodeIndex < 0)
+ continue;
+ const CNode &node = _nodes[nodeIndex];
+ if (!node.IsDir())
continue;
}
- RINOK(ExtractNode(i, dataBuf));
+ RINOK(ExtractNode(nodeIndex, dataBuf));
if (dataBuf.Size() == 0)
{
// _headersError = true;
@@ -1292,18 +1356,19 @@ HRESULT CHandler::Open2(IInStream *inStream)
RINOK(CheckProgress());
}
- if (_nodes[k_INODE_ROOT].ParentNode != k_INODE_ROOT)
+ if (_nodes[_refs[k_INODE_ROOT]].ParentNode != k_INODE_ROOT)
return S_FALSE;
}
{
// ---------- Check NumLinks and unreferenced dir nodes ----------
- FOR_VECTOR (i, _nodes)
+ FOR_VECTOR (i, _refs)
{
- const CNode &node = _nodes[i];
- if (node.IsEmpty)
+ int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
continue;
+ const CNode &node = _nodes[nodeIndex];
if (node.NumLinks != node.NumLinksCalced)
{
@@ -1331,19 +1396,23 @@ HRESULT CHandler::Open2(IInStream *inStream)
{
// ---------- Check that there is no loops in parents list ----------
- unsigned numNodes = _nodes.Size();
+ unsigned numNodes = _refs.Size();
CIntArr UsedByNode(numNodes);
{
- for (unsigned i = 0; i < numNodes; i++)
- UsedByNode[i] = -1;
+ {
+ for (unsigned i = 0; i < numNodes; i++)
+ UsedByNode[i] = -1;
+ }
}
- FOR_VECTOR (i, _nodes)
+ FOR_VECTOR (i, _refs)
{
{
- CNode &node = _nodes[i];
- if (node.IsEmpty
- || node.ParentNode < 0 // not dir
+ int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
+ continue;
+ const CNode &node = _nodes[nodeIndex];
+ if (node.ParentNode < 0 // not dir
|| i == k_INODE_ROOT)
continue;
}
@@ -1352,9 +1421,10 @@ HRESULT CHandler::Open2(IInStream *inStream)
for (;;)
{
- CNode &node = _nodes[c];
- if (node.IsEmpty)
+ int nodeIndex = _refs[c];
+ if (nodeIndex < 0)
return S_FALSE;
+ CNode &node = _nodes[nodeIndex];
if (UsedByNode[c] != -1)
{
@@ -1380,14 +1450,17 @@ HRESULT CHandler::Open2(IInStream *inStream)
CByteBuffer data;
unsigned i;
- for (i = 0; i < _nodes.Size(); i++)
+ for (i = 0; i < _refs.Size(); i++)
{
- CNode &node = _nodes[i];
- if (node.IsEmpty || !node.IsLink())
+ int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
+ continue;
+ CNode &node = _nodes[nodeIndex];
+ if (!node.IsLink())
continue;
if (node.FileSize > ((UInt32)1 << 14))
continue;
- if (ExtractNode(i, data) == S_OK && data.Size() != 0)
+ if (ExtractNode(nodeIndex, data) == S_OK && data.Size() != 0)
{
s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size());
if (s.Len() == data.Size())
@@ -1402,7 +1475,7 @@ HRESULT CHandler::Open2(IInStream *inStream)
for (i = 0; i < _items.Size(); i++)
{
CItem &item = _items[i];
- int sym = _nodes[item.Node].SymLinkIndex;
+ int sym = _nodes[_refs[item.Node]].SymLinkIndex;
if (sym >= 0 && item.ParentNode >= 0)
{
item.SymLinkItemIndex = FindTargetItem_for_SymLink(item.ParentNode, _symLinks[sym]);
@@ -1425,11 +1498,12 @@ HRESULT CHandler::Open2(IInStream *inStream)
bool useSys = false;
bool useUnknown = false;
- for (unsigned i = 0; i < _nodes.Size(); i++)
+ FOR_VECTOR (i, _refs)
{
- const CNode &node = _nodes[i];
- if (node.IsEmpty)
+ int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
continue;
+ const CNode &node = _nodes[nodeIndex];
if (node.NumLinksCalced == 0 /* || i > 100 && i < 150 */) // for debug
{
@@ -1509,6 +1583,7 @@ void CHandler::ClearRefs()
_stream.Release();
_items.Clear();
_nodes.Clear();
+ _refs.Clear();
_auxItems.Clear();
_symLinks.Clear();
_dirs.Clear();
@@ -1524,6 +1599,7 @@ STDMETHODIMP CHandler::Close()
_phySize = 0;
_isArc = false;
_headersError = false;
+ _headersWarning = false;
_linksError = false;
_isUTF = true;
@@ -1562,7 +1638,7 @@ void CHandler::GetPath(unsigned index, AString &s) const
return;
}
- const CNode &node = _nodes[item.ParentNode];
+ const CNode &node = _nodes[_refs[item.ParentNode]];
if (node.ItemIndex < 0)
return;
index = node.ItemIndex;
@@ -1585,7 +1661,7 @@ bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack) const
}
const CItem &item = _items[index];
- const CNode &node = _nodes[item.Node];
+ const CNode &node = _nodes[_refs[item.Node]];
// if (!node.IsFlags_EXTENTS())
{
@@ -1766,22 +1842,29 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
case kpidId:
{
- char s[16 * 2 + 2];
- for (unsigned i = 0; i < 16; i++)
- PrintHex(_h.Uuid[i], s + i * 2);
- s[16 * 2] = 0;
- prop = s;
+ if (!IsEmptyData(_h.Uuid, 16))
+ {
+ char s[16 * 2 + 2];
+ for (unsigned i = 0; i < 16; i++)
+ PrintHex(_h.Uuid[i], s + i * 2);
+ s[16 * 2] = 0;
+ prop = s;
+ }
break;
}
case kpidCodePage: if (_isUTF) prop = "UTF-8"; break;
- case kpidVolumeName: StringToProp(_isUTF, _h.VolName, sizeof(_h.VolName), prop); break;
+
+ case kpidShortComment:
+ case kpidVolumeName:
+ StringToProp(_isUTF, _h.VolName, sizeof(_h.VolName), prop); break;
+
case kpidLastMount: StringToProp(_isUTF, _h.LastMount, sizeof(_h.LastMount), prop); break;
case kpidCharacts: FLAGS_TO_PROP(g_FeatureCompat_Flags, _h.FeatureCompat, prop); break;
case kpidFeatureIncompat: FLAGS_TO_PROP(g_FeatureIncompat_Flags, _h.FeatureIncompat, prop); break;
case kpidFeatureRoCompat: FLAGS_TO_PROP(g_FeatureRoCompat_Flags, _h.FeatureRoCompat, prop); break;
- case kpidWrittenKB: prop = _h.WrittenKB; break;
+ case kpidWrittenKB: if (_h.WrittenKB != 0) prop = _h.WrittenKB; break;
case kpidPhySize: prop = _phySize; break;
@@ -1797,6 +1880,15 @@ STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
prop = v;
break;
}
+
+ case kpidWarningFlags:
+ {
+ UInt32 v = 0;
+ if (_headersWarning) v |= kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
}
prop.Detach(value);
@@ -1846,7 +1938,7 @@ STDMETHODIMP CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentTyp
}
else
{
- int itemIndex = _nodes[item.ParentNode].ItemIndex;
+ int itemIndex = _nodes[_refs[item.ParentNode]].ItemIndex;
if (itemIndex >= 0)
*parent = itemIndex;
}
@@ -1952,7 +2044,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
const CItem &item = _items[index];
- const CNode &node = _nodes[item.Node];
+ const CNode &node = _nodes[_refs[item.Node]];
bool isDir = node.IsDir();
switch (propID)
@@ -1987,7 +2079,7 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
{
bool isDir2 = isDir;
if (item.SymLinkItemIndex >= 0)
- isDir2 = _nodes[_items[item.SymLinkItemIndex].Node].IsDir();
+ isDir2 = _nodes[_refs[_items[item.SymLinkItemIndex].Node]].IsDir();
prop = isDir2;
break;
}
@@ -2050,6 +2142,118 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *val
}
+class CClusterInStream2:
+ public IInStream,
+ public CMyUnknownImp
+{
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt32 _curRem;
+public:
+ unsigned BlockBits;
+ UInt64 Size;
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<UInt32> Vector;
+
+ HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
+
+ HRESULT InitAndSeek()
+ {
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = 0;
+ if (Vector.Size() > 0)
+ {
+ _physPos = (Vector[0] << BlockBits);
+ return SeekToPhys();
+ }
+ return S_OK;
+ }
+
+ MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
+
+ STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
+ STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+};
+
+
+STDMETHODIMP CClusterInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return S_OK;
+ {
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+
+ if (_curRem == 0)
+ {
+ const UInt32 blockSize = (UInt32)1 << BlockBits;
+ const UInt32 virtBlock = (UInt32)(_virtPos >> BlockBits);
+ const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ const UInt32 phyBlock = Vector[virtBlock];
+
+ if (phyBlock == 0)
+ {
+ UInt32 cur = blockSize - offsetInBlock;
+ if (cur > size)
+ cur = size;
+ memset(data, 0, cur);
+ _virtPos += cur;
+ if (processedSize)
+ *processedSize = cur;
+ return S_OK;
+ }
+
+ UInt64 newPos = ((UInt64)phyBlock << BlockBits) + offsetInBlock;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys());
+ }
+
+ _curRem = blockSize - offsetInBlock;
+
+ for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
+ _curRem += (UInt32)1 << BlockBits;
+ }
+
+ if (size > _curRem)
+ size = _curRem;
+ HRESULT res = Stream->Read(data, size, &size);
+ if (processedSize)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+STDMETHODIMP CClusterInStream2::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ if (_virtPos != (UInt64)offset)
+ _curRem = 0;
+ _virtPos = offset;
+ if (newPosition)
+ *newPosition = offset;
+ return S_OK;
+}
+
+
class CExtInStream:
public IInStream,
public CMyUnknownImp
@@ -2057,8 +2261,8 @@ class CExtInStream:
UInt64 _virtPos;
UInt64 _phyPos;
public:
- UInt64 _size;
unsigned BlockBits;
+ UInt64 Size;
CMyComPtr<IInStream> Stream;
CRecordVector<CExtent> Extents;
@@ -2080,11 +2284,13 @@ STDMETHODIMP CExtInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
{
if (processedSize)
*processedSize = 0;
- if (_virtPos >= _size)
+ if (_virtPos >= Size)
return S_OK;
- UInt64 rem = _size - _virtPos;
- if (size > rem)
- size = (UInt32)rem;
+ {
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
if (size == 0)
return S_OK;
@@ -2155,7 +2361,7 @@ STDMETHODIMP CExtInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosi
{
case STREAM_SEEK_SET: break;
case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += _size; break;
+ case STREAM_SEEK_END: offset += Size; break;
default: return STG_E_INVALIDFUNCTION;
}
if (offset < 0)
@@ -2174,6 +2380,8 @@ HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBloc
CByteBuffer &tempBuf = _tempBufs[level];
tempBuf.Alloc(blockSize);
+ PRF2(printf("\n level = %d, block = %7d", level, (unsigned)block));
+
RINOK(SeekAndRead(_stream, block, tempBuf, blockSize));
const Byte *p = tempBuf;
@@ -2184,16 +2392,34 @@ HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBloc
if (blocks.Size() == numBlocks)
break;
UInt32 val = GetUi32(p + 4 * i);
- if (val == 0 || val >= _h.NumBlocks)
+ if (val >= _h.NumBlocks)
return S_FALSE;
if (level != 0)
{
+ if (val == 0)
+ {
+ /*
+ size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level));
+ PRF2(printf("\n num empty = %3d", (unsigned)num));
+ for (size_t k = 0; k < num; k++)
+ {
+ blocks.Add(0);
+ if (blocks.Size() == numBlocks)
+ return S_OK;
+ }
+ continue;
+ */
+ return S_FALSE;
+ }
+
RINOK(FillFileBlocks2(val, level - 1, numBlocks, blocks));
continue;
}
- PRF(printf("\n i = %3d, start = %5d ", (unsigned)val));
+ PRF2(printf("\n i = %3d, blocks.Size() = %6d, block = %5d ", i, blocks.Size(), (unsigned)val));
+
+ PRF(printf("\n i = %3d, start = %5d ", (unsigned)i, (unsigned)val));
blocks.Add(val);
}
@@ -2206,28 +2432,44 @@ static const unsigned kNumDirectNodeBlocks = 12;
HRESULT CHandler::FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks)
{
+ // ext2 supports zero blocks (blockIndex == 0).
+
blocks.ClearAndReserve(numBlocks);
- unsigned i;
-
- for (i = 0; i < kNumDirectNodeBlocks; i++)
+ for (unsigned i = 0; i < kNumDirectNodeBlocks; i++)
{
if (i == numBlocks)
return S_OK;
UInt32 val = GetUi32(p + 4 * i);
- if (val == 0 || val >= _h.NumBlocks)
+ if (val >= _h.NumBlocks)
return S_FALSE;
blocks.Add(val);
}
- for (i = 0; i < 3; i++)
+ for (unsigned level = 0; level < 3; level++)
{
if (blocks.Size() == numBlocks)
break;
- UInt32 val = GetUi32(p + 4 * (kNumDirectNodeBlocks + i));
- if (val == 0 || val >= _h.NumBlocks)
+ UInt32 val = GetUi32(p + 4 * (kNumDirectNodeBlocks + level));
+ if (val >= _h.NumBlocks)
+ return S_FALSE;
+
+ if (val == 0)
+ {
+ /*
+ size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level + 1));
+ for (size_t k = 0; k < num; k++)
+ {
+ blocks.Add(0);
+ if (blocks.Size() == numBlocks)
+ return S_OK;
+ }
+ continue;
+ */
return S_FALSE;
- RINOK(FillFileBlocks2(val, i, numBlocks, blocks));
+ }
+
+ RINOK(FillFileBlocks2(val, level, numBlocks, blocks));
}
return S_OK;
@@ -2331,7 +2573,7 @@ HRESULT CHandler::FillExtents(const Byte *p, size_t size, CRecordVector<CExtent>
}
-HRESULT CHandler::GetStream_Node(UInt32 nodeIndex, ISequentialInStream **stream)
+HRESULT CHandler::GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream)
{
COM_TRY_BEGIN
@@ -2341,7 +2583,12 @@ HRESULT CHandler::GetStream_Node(UInt32 nodeIndex, ISequentialInStream **stream)
if (!node.IsFlags_EXTENTS())
{
- // maybe sparse file can have NumBlocks == 0 ?
+ // maybe sparse file can have (node.NumBlocks == 0) ?
+
+ /* The following code doesn't work correctly for some CentOS images,
+ where there are nodes with inline data and (node.NumBlocks != 0).
+ If you know better way to detect inline data, please notify 7-Zip developers. */
+
if (node.NumBlocks == 0 && node.FileSize < kNodeBlockFieldSize)
{
Create_BufInStream_WithNewBuffer(node.Block, (size_t)node.FileSize, stream);
@@ -2365,7 +2612,7 @@ HRESULT CHandler::GetStream_Node(UInt32 nodeIndex, ISequentialInStream **stream)
streamTemp = streamSpec;
streamSpec->BlockBits = _h.BlockBits;
- streamSpec->_size = node.FileSize;
+ streamSpec->Size = node.FileSize;
streamSpec->Stream = _stream;
RINOK(FillExtents(node.Block, kNodeBlockFieldSize, streamSpec->Extents, -1));
@@ -2421,11 +2668,10 @@ HRESULT CHandler::GetStream_Node(UInt32 nodeIndex, ISequentialInStream **stream)
if (numBlocks != numBlocks64)
return S_FALSE;
- CClusterInStream *streamSpec = new CClusterInStream;
+ CClusterInStream2 *streamSpec = new CClusterInStream2;
streamTemp = streamSpec;
- streamSpec->BlockSizeLog = _h.BlockBits;
- streamSpec->StartOffset = 0;
+ streamSpec->BlockBits = _h.BlockBits;
streamSpec->Size = node.FileSize;
streamSpec->Stream = _stream;
@@ -2477,7 +2723,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
if (index >= _items.Size())
continue;
const CItem &item = _items[index];
- const CNode &node = _nodes[item.Node];
+ const CNode &node = _nodes[_refs[item.Node]];
if (!node.IsDir())
totalSize += node.FileSize;
}
@@ -2520,7 +2766,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
const CItem &item = _items[index];
- const CNode &node = _nodes[item.Node];
+ const CNode &node = _nodes[_refs[item.Node]];
if (node.IsDir())
{
@@ -2583,7 +2829,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
*stream = NULL;
if (index >= _items.Size())
return S_FALSE;
- return GetStream_Node(_items[index].Node, stream);
+ return GetStream_Node(_refs[_items[index].Node], stream);
}
@@ -2601,7 +2847,7 @@ API_FUNC_static_IsArc IsArc_Ext(const Byte *p, size_t size)
static const Byte k_Signature[] = { 0x53, 0xEF };
REGISTER_ARC_I(
- "Ext", "ext ext3 ext4", 0, 0xC7,
+ "Ext", "ext ext2 ext3 ext4 img", 0, 0xC7,
k_Signature,
0x438,
0,
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
index e16a8860..e8340f1d 100644
--- a/CPP/7zip/Archive/FatHandler.cpp
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -133,15 +133,23 @@ bool CHeader::Parse(const Byte *p)
default: return false;
}
{
- int s = GetLog(Get16(p + 11));
- if (s < 9 || s > 12)
- return false;
- SectorSizeLog = (Byte)s;
- s = GetLog(p[13]);
- if (s < 0)
- return false;
- SectorsPerClusterLog = (Byte)s;
+ {
+ UInt32 val32 = Get16(p + 11);
+ int s = GetLog(val32);
+ if (s < 9 || s > 12)
+ return false;
+ SectorSizeLog = (Byte)s;
+ }
+ {
+ UInt32 val32 = p[13];
+ int s = GetLog(val32);
+ if (s < 0)
+ return false;
+ SectorsPerClusterLog = (Byte)s;
+ }
ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog);
+ if (ClusterSizeLog > 24)
+ return false;
}
NumReservedSectors = Get16(p + 14);
diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp
index 2e0e7a57..e54b1477 100644
--- a/CPP/7zip/Archive/GptHandler.cpp
+++ b/CPP/7zip/Archive/GptHandler.cpp
@@ -156,8 +156,15 @@ class CHandler: public CHandlerCont
CByteBuffer _buffer;
HRESULT Open2(IInStream *stream);
- virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].GetPos(); }
- virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].GetSize(); }
+
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const
+ {
+ const CPartition &item = _items[index];
+ pos = item.GetPos();
+ size = item.GetSize();
+ return NExtract::NOperationResult::kOK;
+ }
+
public:
INTERFACE_IInArchive_Cont(;)
};
diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp
index ca9153b8..c2d5c70c 100644
--- a/CPP/7zip/Archive/HandlerCont.cpp
+++ b/CPP/7zip/Archive/HandlerCont.cpp
@@ -28,7 +28,11 @@ STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
UInt64 totalSize = 0;
UInt32 i;
for (i = 0; i < numItems; i++)
- totalSize += GetItemSize(allFilesMode ? i : indices[i]);
+ {
+ UInt64 pos, size;
+ GetItem_ExtractInfo(allFilesMode ? i : indices[i], pos, size);
+ totalSize += size;
+ }
extractCallback->SetTotal(totalSize);
totalSize = 0;
@@ -56,21 +60,31 @@ STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
Int32 index = allFilesMode ? i : indices[i];
RINOK(extractCallback->GetStream(index, &outStream, askMode));
- UInt64 size = GetItemSize(index);
+
+ UInt64 pos, size;
+ int opRes = GetItem_ExtractInfo(index, pos, size);
totalSize += size;
if (!testMode && !outStream)
continue;
+
RINOK(extractCallback->PrepareOperation(askMode));
- RINOK(_stream->Seek(GetItemPos(index), STREAM_SEEK_SET, NULL));
- streamSpec->Init(size);
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ RINOK(_stream->Seek(pos, STREAM_SEEK_SET, NULL));
+ streamSpec->Init(size);
+
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
+
+ opRes = NExtract::NOperationResult::kDataError;
+
+ if (copyCoderSpec->TotalSize == size)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (copyCoderSpec->TotalSize < size)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ }
+
outStream.Release();
- int opRes = NExtract::NOperationResult::kDataError;
- if (copyCoderSpec->TotalSize == size)
- opRes = NExtract::NOperationResult::kOK;
- else if (copyCoderSpec->TotalSize < size)
- opRes = NExtract::NOperationResult::kUnexpectedEnd;
RINOK(extractCallback->SetOperationResult(opRes));
}
@@ -81,13 +95,22 @@ STDMETHODIMP CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
STDMETHODIMP CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream)
{
COM_TRY_BEGIN
- // const CPartition &item = _items[index];
- return CreateLimitedInStream(_stream, GetItemPos(index), GetItemSize(index), stream);
+ *stream = NULL;
+ UInt64 pos, size;
+ if (GetItem_ExtractInfo(index, pos, size) != NExtract::NOperationResult::kOK)
+ return S_FALSE;
+ return CreateLimitedInStream(_stream, pos, size, stream);
COM_TRY_END
}
+CHandlerImg::CHandlerImg():
+ _imgExt(NULL)
+{
+ ClearStreamVars();
+}
+
STDMETHODIMP CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
{
switch (seekOrigin)
@@ -190,6 +213,8 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
int opRes = NExtract::NOperationResult::kDataError;
+ ClearStreamVars();
+
CMyComPtr<ISequentialInStream> inStream;
HRESULT hres = GetStream(0, &inStream);
if (hres == S_FALSE)
@@ -205,6 +230,13 @@ STDMETHODIMP CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
{
if (copyCoderSpec->TotalSize == _size)
opRes = NExtract::NOperationResult::kOK;
+
+ if (_stream_unavailData)
+ opRes = NExtract::NOperationResult::kUnavailable;
+ else if (_stream_unsupportedMethod)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (_stream_dataError)
+ opRes = NExtract::NOperationResult::kDataError;
else if (copyCoderSpec->TotalSize < _size)
opRes = NExtract::NOperationResult::kUnexpectedEnd;
}
diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h
index 58b45d54..50a72895 100644
--- a/CPP/7zip/Archive/HandlerCont.h
+++ b/CPP/7zip/Archive/HandlerCont.h
@@ -30,8 +30,8 @@ class CHandlerCont:
protected:
CMyComPtr<IInStream> _stream;
- virtual UInt64 GetItemPos(UInt32 index) const = 0;
- virtual UInt64 GetItemSize(UInt32 index) const = 0;
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const = 0;
+
public:
MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
INTERFACE_IInArchive_Cont(PURE)
@@ -39,6 +39,9 @@ public:
STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY;
STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
+
+ // destructor must be virtual for this class
+ virtual ~CHandlerCont() {}
};
@@ -68,6 +71,22 @@ protected:
UInt64 _size;
CMyComPtr<IInStream> Stream;
const char *_imgExt;
+
+ bool _stream_unavailData;
+ bool _stream_unsupportedMethod;
+ bool _stream_dataError;
+ // bool _stream_UsePackSize;
+ // UInt64 _stream_PackSize;
+
+ void ClearStreamVars()
+ {
+ _stream_unavailData = false;
+ _stream_unsupportedMethod = false;
+ _stream_dataError = false;
+ // _stream_UsePackSize = false;
+ // _stream_PackSize = 0;
+ }
+
virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0;
virtual void CloseAtError();
@@ -83,6 +102,10 @@ public:
STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) = 0;
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
+
+ CHandlerImg();
+ // destructor must be virtual for this class
+ virtual ~CHandlerImg() {}
};
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp
index 713764d9..91bf1a25 100644
--- a/CPP/7zip/Archive/Iso/IsoHandler.cpp
+++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -323,7 +323,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
{
lps->InSize = lps->OutSize = currentTotalSize + offset;
const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
- RINOK(_stream->Seek((UInt64)item2.ExtentLocation * _archive.BlockSize, STREAM_SEEK_SET, NULL));
+ RINOK(_stream->Seek((UInt64)item2.ExtentLocation * kBlockSize, STREAM_SEEK_SET, NULL));
streamSpec->Init(item2.Size);
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != item2.Size)
@@ -336,7 +336,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
}
else
{
- RINOK(_stream->Seek(blockIndex * _archive.BlockSize, STREAM_SEEK_SET, NULL));
+ RINOK(_stream->Seek((UInt64)blockIndex * kBlockSize, STREAM_SEEK_SET, NULL));
streamSpec->Init(currentItemSize);
RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress));
if (copyCoderSpec->TotalSize != currentItemSize)
@@ -379,7 +379,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
if (item.Size == 0)
continue;
CSeekExtent se;
- se.Phy = (UInt64)item.ExtentLocation * _archive.BlockSize;
+ se.Phy = (UInt64)item.ExtentLocation * kBlockSize;
se.Virt = virtOffset;
extentStreamSpec->Extents.Add(se);
virtOffset += item.Size;
@@ -405,7 +405,7 @@ STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
blockIndex = be.LoadRBA;
}
- return CreateLimitedInStream(_stream, blockIndex * _archive.BlockSize, currentItemSize, stream);
+ return CreateLimitedInStream(_stream, (UInt64)blockIndex * kBlockSize, currentItemSize, stream);
COM_TRY_END
}
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
index 39034b63..1c7dd11e 100644
--- a/CPP/7zip/Archive/Iso/IsoIn.cpp
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -88,15 +88,15 @@ AString CBootInitialEntry::GetName() const
Byte CInArchive::ReadByte()
{
- if (m_BufferPos >= BlockSize)
+ if (m_BufferPos >= kBlockSize)
m_BufferPos = 0;
if (m_BufferPos == 0)
{
- size_t processed = BlockSize;
+ size_t processed = kBlockSize;
HRESULT res = ReadStream(_stream, m_Buffer, &processed);
if (res != S_OK)
throw CSystemException(res);
- if (processed != BlockSize)
+ if (processed != kBlockSize)
throw CUnexpectedEndException();
UInt64 end = _position + processed;
if (PhySize < end)
@@ -511,7 +511,7 @@ HRESULT CInArchive::Open2()
PhySize = _position;
m_BufferPos = 0;
- BlockSize = kBlockSize;
+ // BlockSize = kBlockSize;
for (;;)
{
diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h
index c2007bce..5c1a4bcf 100644
--- a/CPP/7zip/Archive/Iso/IsoIn.h
+++ b/CPP/7zip/Archive/Iso/IsoIn.h
@@ -282,7 +282,7 @@ public:
CRecordVector<CRef> Refs;
CObjectVector<CVolumeDescriptor> VolDescs;
int MainVolDescIndex;
- UInt32 BlockSize;
+ // UInt32 BlockSize;
CObjectVector<CBootInitialEntry> BootEntries;
bool IsArc;
@@ -297,8 +297,8 @@ public:
void UpdatePhySize(UInt32 blockIndex, UInt64 size)
{
- UInt64 alignedSize = (size + BlockSize - 1) & ~((UInt64)BlockSize - 1);
- UInt64 end = blockIndex * BlockSize + alignedSize;
+ const UInt64 alignedSize = (size + kBlockSize - 1) & ~((UInt64)kBlockSize - 1);
+ const UInt64 end = (UInt64)blockIndex * kBlockSize + alignedSize;
if (PhySize < end)
PhySize = end;
}
@@ -315,7 +315,7 @@ public:
size = (1440 << 10);
else if (be.BootMediaType == NBootMediaType::k2d88Floppy)
size = (2880 << 10);
- UInt64 startPos = (UInt64)be.LoadRBA * BlockSize;
+ UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize;
if (startPos < _fileSize)
{
if (_fileSize - startPos < size)
diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp
index 93b615d2..b92755ae 100644
--- a/CPP/7zip/Archive/MbrHandler.cpp
+++ b/CPP/7zip/Archive/MbrHandler.cpp
@@ -158,6 +158,7 @@ static const CPartType kPartTypes[] =
{ 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" },
{ 0x82, 0, "Solaris x86 / Linux swap" },
{ 0x83, 0, "Linux" },
+ { 0x8E, "lvm", "Linux LVM" },
{ 0xA5, 0, "BSD slice" },
{ 0xBE, 0, "Solaris 8 boot" },
{ 0xBF, 0, "New Solaris x86" },
@@ -189,8 +190,14 @@ class CHandler: public CHandlerCont
UInt64 _totalSize;
CByteBuffer _buffer;
- virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].Part.GetPos(); }
- virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].Size; }
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const
+ {
+ const CItem &item = _items[index];
+ pos = item.Part.GetPos();
+ size = item.Size;
+ return NExtract::NOperationResult::kOK;
+ }
+
HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level);
public:
INTERFACE_IInArchive_Cont(;)
diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp
index 05ea4d9f..56b8aa32 100644
--- a/CPP/7zip/Archive/MubHandler.cpp
+++ b/CPP/7zip/Archive/MubHandler.cpp
@@ -56,8 +56,15 @@ class CHandler: public CHandlerCont
CItem _items[kNumFilesMax];
HRESULT Open2(IInStream *stream);
- virtual UInt64 GetItemPos(UInt32 index) const { return _items[index].Offset; }
- virtual UInt64 GetItemSize(UInt32 index) const { return _items[index].Size; }
+
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const
+ {
+ const CItem &item = _items[index];
+ pos = item.Offset;
+ size = item.Size;
+ return NExtract::NOperationResult::kOK;
+ }
+
public:
INTERFACE_IInArchive_Cont(;)
};
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
index 70023fe4..fa4bbc9c 100644
--- a/CPP/7zip/Archive/NtfsHandler.cpp
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -576,20 +576,20 @@ class CInStream:
UInt64 _physPos;
UInt64 _curRem;
bool _sparseMode;
- size_t _compressedPos;
- UInt64 _tags[kNumCacheChunks];
+
unsigned _chunkSizeLog;
+ UInt64 _tags[kNumCacheChunks];
CByteBuffer _inBuf;
CByteBuffer _outBuf;
public:
- CMyComPtr<IInStream> Stream;
UInt64 Size;
UInt64 InitializedSize;
unsigned BlockSizeLog;
unsigned CompressionUnit;
- bool InUse;
CRecordVector<CExtent> Extents;
+ bool InUse;
+ CMyComPtr<IInStream> Stream;
HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
@@ -597,11 +597,11 @@ public:
HRESULT InitAndSeek(unsigned compressionUnit)
{
CompressionUnit = compressionUnit;
+ _chunkSizeLog = BlockSizeLog + CompressionUnit;
if (compressionUnit != 0)
{
UInt32 cuSize = GetCuSize();
_inBuf.Alloc(cuSize);
- _chunkSizeLog = BlockSizeLog + CompressionUnit;
_outBuf.Alloc(kNumCacheChunks << _chunkSizeLog);
}
for (size_t i = 0; i < kNumCacheChunks; i++)
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp
index f3ae78aa..08df1ae7 100644
--- a/CPP/7zip/Archive/RpmHandler.cpp
+++ b/CPP/7zip/Archive/RpmHandler.cpp
@@ -226,8 +226,13 @@ class CHandler: public CHandlerCont
HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader);
HRESULT Open2(ISequentialInStream *stream);
- virtual UInt64 GetItemPos(UInt32) const { return _headersSize; }
- virtual UInt64 GetItemSize(UInt32) const { return _size; }
+ virtual int GetItem_ExtractInfo(UInt32 /* index */, UInt64 &pos, UInt64 &size) const
+ {
+ pos = _headersSize;
+ size = _size;
+ return NExtract::NOperationResult::kOK;
+ }
+
public:
INTERFACE_IInArchive_Cont(;)
};
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
index 62df64dc..6be035cb 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.cpp
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -564,7 +564,7 @@ HRESULT CInArchive::ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &la
return S_OK;
}
-HRESULT CInArchive::FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed)
+HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed)
{
if ((_numRefs & 0xFFF) == 0)
{
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
index 23693a71..3851062e 100644
--- a/CPP/7zip/Archive/Udf/UdfIn.h
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -252,7 +252,7 @@ struct CItem
bool IsInline;
CByteBuffer InlineData;
CRecordVector<CMyExtent> Extents;
- CRecordVector<int> SubFiles;
+ CUIntVector SubFiles;
void Parse(const Byte *buf);
@@ -282,7 +282,7 @@ struct CItem
struct CRef
{
int Parent;
- int FileIndex;
+ unsigned FileIndex;
};
@@ -346,7 +346,7 @@ class CInArchive
HRESULT ReadItem(int volIndex, int fsIndex, const CLongAllocDesc &lad, int numRecurseAllowed);
HRESULT Open2();
- HRESULT FillRefs(CFileSet &fs, int fileIndex, int parent, int numRecurseAllowed);
+ HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed);
UInt64 _processedProgressBytes;
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
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
index d4b321dc..3128939e 100644
--- a/CPP/7zip/Archive/Zip/ZipUpdate.cpp
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -723,7 +723,7 @@ static HRESULT Update2(
CThreads threads;
CRecordVector<HANDLE> compressingCompletedEvents;
- CRecordVector<int> threadIndices; // list threads in order of updateItems
+ CUIntVector threadIndices; // list threads in order of updateItems
{
RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize)));
@@ -759,7 +759,7 @@ static HRESULT Update2(
while (itemIndex < updateItems.Size())
{
- if ((UInt32)threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
+ if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
{
CUpdateItem &ui = updateItems[mtItemIndex++];
if (!ui.NewData)