diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2015-10-18 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:56 +0300 |
commit | a663a6deb7a150f935fac7efdbf4d53d27369594 (patch) | |
tree | d1be306b33dd96050206da5774fff7bd9083ddfa /CPP/7zip | |
parent | 6543c280208393fa32cb0094f770d14c1cfb13b2 (diff) |
15.0915.09
Diffstat (limited to 'CPP/7zip')
31 files changed, 1537 insertions, 502 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(¤tTotalSize)); + + 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 §ion = Sections[(int)item.Section]; + const CSectionInfo §ion = 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 §ion = Sections[(int)item.Section]; + const CSectionInfo §ion = 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) diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp index 0e8586e9..5ca288f4 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp +++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp @@ -513,10 +513,11 @@ static int main2(int numArgs, const char *args[]) if (parser[NKey::kEOS].ThereIs || stdInMode) throw "Can not use stdin in this mode"; - if (fileSize > 0xF0000000) - throw "File is too big"; - size_t inSize = (size_t)fileSize; + + if (inSize != fileSize) + throw "File is too big"; + Byte *inBuffer = NULL; if (inSize != 0) @@ -535,7 +536,13 @@ static int main2(int numArgs, const char *args[]) if (encodeMode) { // we allocate 105% of original size for output buffer - outSize = (size_t)fileSize / 20 * 21 + (1 << 16); + UInt64 outSize64 = fileSize / 20 * 21 + (1 << 16); + + outSize = (size_t)outSize64; + + if (outSize != outSize64) + throw "File is too big"; + if (outSize != 0) { outBuffer = (Byte *)MyAlloc((size_t)outSize); @@ -561,7 +568,7 @@ static int main2(int numArgs, const char *args[]) outSize = (size_t)outSize64; if (outSize != outSize64) - throw "too big"; + throw "Unpack size is too big"; if (outSize != 0) { outBuffer = (Byte *)MyAlloc(outSize); diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp index 47f36c84..f8267a11 100644 --- a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp +++ b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp @@ -366,6 +366,10 @@ SOURCE=..\..\..\..\C\7zCrcOpt.c # End Source File # Begin Source File +SOURCE=..\..\..\..\C\7zTypes.h +# End Source File +# Begin Source File + SOURCE=..\..\..\..\C\Alloc.c # SUBTRACT CPP /YX /Yc /Yu # End Source File @@ -464,10 +468,6 @@ SOURCE=..\..\..\..\C\Threads.c SOURCE=..\..\..\..\C\Threads.h # End Source File -# Begin Source File - -SOURCE=..\..\..\..\C\Types.h -# End Source File # End Group # Begin Source File diff --git a/CPP/7zip/Common/LimitedStreams.cpp b/CPP/7zip/Common/LimitedStreams.cpp index 77665ae1..c7962167 100644 --- a/CPP/7zip/Common/LimitedStreams.cpp +++ b/CPP/7zip/Common/LimitedStreams.cpp @@ -86,26 +86,34 @@ STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSi *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) { - UInt32 blockSize = (UInt32)1 << BlockSizeLog; - UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); - UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); - UInt32 phyBlock = Vector[virtBlock]; + const UInt32 blockSize = (UInt32)1 << BlockSizeLog; + const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog); + const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1); + const UInt32 phyBlock = Vector[virtBlock]; + UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock; if (newPos != _physPos) { _physPos = newPos; RINOK(SeekToPhys()); } + _curRem = blockSize - offsetInBlock; + for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++) _curRem += (UInt32)1 << BlockSizeLog; - UInt64 rem = Size - _virtPos; - if (_curRem > rem) - _curRem = (UInt32)rem; } + if (size > _curRem) size = _curRem; HRESULT res = Stream->Read(data, size, &size); diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h index a9378491..b521eeb9 100644 --- a/CPP/7zip/Common/LimitedStreams.h +++ b/CPP/7zip/Common/LimitedStreams.h @@ -73,11 +73,11 @@ class CClusterInStream: UInt64 _physPos; UInt32 _curRem; public: - CMyComPtr<IInStream> Stream; - UInt64 StartOffset; - UInt64 Size; unsigned BlockSizeLog; + UInt64 Size; + CMyComPtr<IInStream> Stream; CRecordVector<UInt32> Vector; + UInt64 StartOffset; HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); } diff --git a/CPP/7zip/Common/MethodProps.cpp b/CPP/7zip/Common/MethodProps.cpp index 7c1e9979..a5149ab5 100644 --- a/CPP/7zip/Common/MethodProps.cpp +++ b/CPP/7zip/Common/MethodProps.cpp @@ -90,51 +90,65 @@ HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 default return ParsePropToUInt32(name, prop, numThreads); } -static HRESULT StringToDictSize(const UString &s, UInt32 &dicSize) + +static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp) { const wchar_t *end; UInt32 number = ConvertStringToUInt32(s, &end); unsigned numDigits = (unsigned)(end - s); if (numDigits == 0 || s.Len() > numDigits + 1) return E_INVALIDARG; - const unsigned kLogDictSizeLimit = 32; + if (s.Len() == numDigits) { - if (number >= kLogDictSizeLimit) + if (number >= 64) return E_INVALIDARG; - dicSize = (UInt32)1 << (unsigned)number; + if (number < 32) + destProp = (UInt32)((UInt32)1 << (unsigned)number); + else + destProp = (UInt64)((UInt64)1 << (unsigned)number); return S_OK; } + unsigned numBits; + switch (MyCharLower_Ascii(s[numDigits])) { - case 'b': dicSize = number; return S_OK; + case 'b': destProp = number; return S_OK; case 'k': numBits = 10; break; case 'm': numBits = 20; break; case 'g': numBits = 30; break; default: return E_INVALIDARG; } - if (number >= ((UInt32)1 << (kLogDictSizeLimit - numBits))) - return E_INVALIDARG; - dicSize = number << numBits; + + if (number < ((UInt32)1 << (32 - numBits))) + destProp = (UInt32)(number << numBits); + else + destProp = (UInt64)((UInt64)number << numBits); + return S_OK; } -static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, UInt32 &resValue) + +static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp) { if (prop.vt == VT_UI4) { UInt32 v = prop.ulVal; - if (v >= 32) + if (v >= 64) return E_INVALIDARG; - resValue = (UInt32)1 << v; + if (v < 32) + destProp = (UInt32)((UInt32)1 << (unsigned)v); + else + destProp = (UInt64)((UInt64)1 << (unsigned)v); return S_OK; } if (prop.vt == VT_BSTR) - return StringToDictSize(prop.bstrVal, resValue); + return StringToDictSize(prop.bstrVal, destProp); return E_INVALIDARG; } + void CProps::AddProp32(PROPID propid, UInt32 level) { CProp &prop = Props.AddNew(); @@ -275,10 +289,10 @@ static void SplitParams(const UString &srcString, UStringVector &subStrings) { subStrings.Clear(); UString s; - int len = srcString.Len(); + unsigned len = srcString.Len(); if (len == 0) return; - for (int i = 0; i < len; i++) + for (unsigned i = 0; i < len; i++) { wchar_t c = srcString[i]; if (c == L':') @@ -336,9 +350,7 @@ HRESULT CMethodProps::SetParam(const UString &name, const UString &value) if (IsLogSizeProp(prop.Id)) { - UInt32 dicSize; - RINOK(StringToDictSize(value, dicSize)); - prop.Value = dicSize; + RINOK(StringToDictSize(value, prop.Value)); } else { @@ -406,9 +418,7 @@ HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const if (IsLogSizeProp(prop.Id)) { - UInt32 dicSize; - RINOK(PROPVARIANT_to_DictSize(value, dicSize)); - prop.Value = dicSize; + RINOK(PROPVARIANT_to_DictSize(value, prop.Value)); } else { diff --git a/CPP/7zip/Compress/Lzma2Encoder.cpp b/CPP/7zip/Compress/Lzma2Encoder.cpp index dea297c4..06a11f10 100644 --- a/CPP/7zip/Compress/Lzma2Encoder.cpp +++ b/CPP/7zip/Compress/Lzma2Encoder.cpp @@ -38,7 +38,20 @@ HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzm switch (propID) { case NCoderPropID::kBlockSize: - if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.blockSize = prop.ulVal; break; + { + if (prop.vt == VT_UI4) + lzma2Props.blockSize = prop.ulVal; + else if (prop.vt == VT_UI8) + { + size_t v = (size_t)prop.uhVal.QuadPart; + if (v != prop.uhVal.QuadPart) + return E_INVALIDARG; + lzma2Props.blockSize = v; + } + else + return E_INVALIDARG; + break; + } case NCoderPropID::kNumThreads: if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.numTotalThreads = (int)(prop.ulVal); break; default: diff --git a/CPP/7zip/UI/Client7z/Client7z.cpp b/CPP/7zip/UI/Client7z/Client7z.cpp index e13061ae..c6522fe7 100644 --- a/CPP/7zip/UI/Client7z/Client7z.cpp +++ b/CPP/7zip/UI/Client7z/Client7z.cpp @@ -441,7 +441,7 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) } } - if (_outFileStream != NULL) + if (_outFileStream) { if (_processedFileInfo.MTimeDefined) _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime); @@ -499,7 +499,6 @@ public: STDMETHOD(SetCompleted)(const UInt64 *completeValue); // IUpdateCallback2 - STDMETHOD(EnumProperties)(IEnumSTATPROPSTG **enumerator); STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive); STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); @@ -551,20 +550,14 @@ STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValu return S_OK; } - -STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG ** /* enumerator */) -{ - return E_NOTIMPL; -} - STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */, Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive) { - if (newData != NULL) + if (newData) *newData = BoolToInt(true); - if (newProperties != NULL) + if (newProperties) *newProperties = BoolToInt(true); - if (indexInArchive != NULL) + if (indexInArchive) *indexInArchive = (UInt32)(Int32)-1; return S_OK; } diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index b07b1dc6..cc0b1f93 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -108,34 +108,52 @@ static const char *kHelpString = " h : Calculate hash values for files\n" " i : Show information about supported formats\n" " l : List contents of archive\n" -// " l[a|t][f] : List contents of archive\n" -// " a - with Additional fields\n" -// " t - with all fields\n" -// " f - with Full pathnames\n" " rn : Rename files in archive\n" " t : Test integrity of archive\n" " u : Update files to archive\n" " x : eXtract files with full paths\n" + "\n" "<Switches>\n" " -- : Stop switches parsing\n" " -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n" " -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n" - " -bd : Disable percentage indicator\n" + " -ao{a|s|t|u} : set Overwrite mode\n" + " -an : disable archive_name field\n" + " -bb[0-3] : set output log level\n" + " -bd : disable progress indicator\n" + " -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line\n" + " -bt : show execution time statistics\n" " -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n" " -m{Parameters} : set compression Method\n" + " -mmt[N] : set number of CPU threads\n" " -o{Directory} : set Output directory\n" #ifndef _NO_CRYPTO " -p{Password} : set Password\n" #endif " -r[-|0] : Recurse subdirectories\n" + " -sa{a|e|s} : set Archive name mode\n" + " -scc{UTF-8|WIN|DOS} : set charset for for console input/output\n" " -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n" - " -sdel : Delete files after compression\n" + " -scrc[CRC32|CRC64|SHA1|SHA256|*] : set hash function for x, e, h commands\n" + " -sdel : delete files after compression\n" + " -seml[.] : send archive by email\n" " -sfx[{name}] : Create SFX archive\n" " -si[{name}] : read data from stdin\n" + " -slp : set Large Pages mode\n" " -slt : show technical information for l (List) command\n" + " -snh : store hard links as links\n" + " -snl : store symbolic links as links\n" + " -sni : store NT security information\n" + " -sns[-] : store NTFS alternate streams\n" " -so : write data to stdout\n" + " -spd : disable wildcard matching for file names\n" + " -spe : eliminate duplication of root folder for extract command\n" + " -spf : use fully qualified file paths\n" " -ssc[-] : set sensitive case mode\n" " -ssw : compress shared files\n" + " -stl : set archive timestamp from the most recently modified file\n" + " -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n" + " -stx{Type} : exclude archive type\n" " -t{Type} : Set type of archive\n" " -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n" " -v{Size}[b|k|m|g] : Create volumes\n" diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp index 8bf40f5e..6658923f 100644 --- a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp +++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp @@ -85,7 +85,7 @@ public: CRecordVector<bool> NeedWait; ~CChildProcesses() { CloseAll(); } - void DisableWait(int index) { NeedWait[index] = false; } + void DisableWait(unsigned index) { NeedWait[index] = false; } void CloseAll() { @@ -491,7 +491,19 @@ typedef BOOL (WINAPI * ShellExecuteExWP)(LPSHELLEXECUTEINFOW lpExecInfo); static HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process) { + UString path2 = path; + + #ifdef _WIN32 + { + int dot = path2.ReverseFind_Dot(); + int separ = path2.ReverseFind_PathSepar(); + if (dot < 0 || dot < separ) + path2 += L'.'; + } + #endif + UINT32 result; + #ifndef _UNICODE if (g_IsNT) { @@ -500,14 +512,14 @@ static HRESULT StartApplication(const UString &dir, const UString &path, HWND wi execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; execInfo.hwnd = NULL; execInfo.lpVerb = NULL; - execInfo.lpFile = path; + execInfo.lpFile = path2; execInfo.lpParameters = NULL; execInfo.lpDirectory = dir.IsEmpty() ? NULL : (LPCWSTR)dir; execInfo.nShow = SW_SHOWNORMAL; execInfo.hProcess = 0; ShellExecuteExWP shellExecuteExW = (ShellExecuteExWP) ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "ShellExecuteExW"); - if (shellExecuteExW == 0) + if (!shellExecuteExW) return 0; shellExecuteExW(&execInfo); result = (UINT32)(UINT_PTR)execInfo.hInstApp; @@ -525,23 +537,24 @@ static HRESULT StartApplication(const UString &dir, const UString &path, HWND wi ; execInfo.hwnd = NULL; execInfo.lpVerb = NULL; - const CSysString sysPath = GetSystemString(path); + const CSysString sysPath = GetSystemString(path2); const CSysString sysDir = GetSystemString(dir); execInfo.lpFile = sysPath; execInfo.lpParameters = NULL; execInfo.lpDirectory = - #ifdef UNDER_CE - NULL - #else - sysDir.IsEmpty() ? NULL : (LPCTSTR)sysDir - #endif - ; + #ifdef UNDER_CE + NULL + #else + sysDir.IsEmpty() ? NULL : (LPCTSTR)sysDir + #endif + ; execInfo.nShow = SW_SHOWNORMAL; execInfo.hProcess = 0; ::ShellExecuteEx(&execInfo); result = (UINT32)(UINT_PTR)execInfo.hInstApp; process.Attach(execInfo.hProcess); } + if (result <= 32) { switch (result) @@ -553,6 +566,7 @@ static HRESULT StartApplication(const UString &dir, const UString &path, HWND wi L"7-Zip", MB_OK | MB_ICONSTOP); } } + return S_OK; } @@ -795,7 +809,7 @@ static THREAD_FUNC_DECL MyThreadFunction(void *param) for (;;) { CRecordVector<HANDLE> handles; - CRecordVector<int> indices; + CUIntVector indices; FOR_VECTOR (i, processes.Handles) { @@ -992,6 +1006,17 @@ static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILET } */ + +/* +tryInternal tryExternal + false false : unused + false true : external + true false : internal + true true : smart based on file extension: + !alwaysStart(name) : both + alwaysStart(name) : external +*/ + void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type) { const UString name = GetItemName(index); @@ -1008,7 +1033,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo bool tryAsArchive = tryInternal && (!tryExternal || !DoItemAlwaysStart(name)); - UString fullVirtPath = _currentFolderPrefix + relPath; + const UString fullVirtPath = _currentFolderPrefix + relPath; CTempDir tempDirectory; if (!tempDirectory.Create(kTempDirPrefix)) @@ -1058,6 +1083,8 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo // probably we must show some message here // return; } + if (!tryExternal) + return; } } } @@ -1126,6 +1153,7 @@ void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bo options.folder = fs2us(tempDirNorm); options.showErrorMessages = true; + HRESULT result = CopyTo(options, indices, &messages, usePassword, password); if (_parentFolders.Size() > 0) diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp index dc828e72..378ad903 100644 --- a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp +++ b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp @@ -8,12 +8,13 @@ #include "../../../Windows/Control/Static.h" #include "../../../Windows/ErrorMsg.h" -#include "ProgressDialog2.h" -#include "DialogSize.h" +#include "../GUI/ExtractRes.h" -#include "ProgressDialog2Res.h" +#include "LangUtils.h" -#include "../GUI/ExtractRes.h" +#include "DialogSize.h" +#include "ProgressDialog2.h" +#include "ProgressDialog2Res.h" using namespace NWindows; @@ -42,8 +43,6 @@ static const UINT kCreateDelay = static const DWORD kPauseSleepTime = 100; -#include "LangUtils.h" - #ifdef LANG static const UInt32 kLangIDs[] = @@ -705,10 +704,9 @@ void CProgressDialog::UpdateStatInfo(bool showAll) UInt32 curTime = ::GetTickCount(); + const UInt64 progressTotal = bytesProgressMode ? total : totalFiles; + const UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles; { - UInt64 progressTotal = bytesProgressMode ? total : totalFiles; - UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles; - if (IS_UNDEFINED_VAL(progressTotal)) { // SetPos(0); @@ -757,9 +755,9 @@ void CProgressDialog::UpdateStatInfo(bool showAll) } } - if (completed != 0) + if (progressCompleted != 0) { - if (IS_UNDEFINED_VAL(total)) + if (IS_UNDEFINED_VAL(progressTotal)) { if (IS_DEFINED_VAL(_prevRemainingSec)) { @@ -770,8 +768,8 @@ void CProgressDialog::UpdateStatInfo(bool showAll) else { UInt64 remainingTime = 0; - if (completed < total) - remainingTime = MyMultAndDiv(_elapsedTime, total - completed, completed); + if (progressCompleted < progressTotal) + remainingTime = MyMultAndDiv(_elapsedTime, progressTotal - progressCompleted, progressCompleted); UInt64 remainingSec = remainingTime / 1000; if (remainingSec != _prevRemainingSec) { @@ -783,7 +781,7 @@ void CProgressDialog::UpdateStatInfo(bool showAll) } { UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime; - UInt64 v = (completed * 1000) / elapsedTime; + UInt64 v = (progressCompleted * 1000) / elapsedTime; Byte c = 0; unsigned moveBits = 0; if (v >= ((UInt64)10000 << 10)) { moveBits = 20; c = 'M'; } @@ -811,11 +809,11 @@ void CProgressDialog::UpdateStatInfo(bool showAll) { UInt64 percent = 0; { - if (IS_DEFINED_VAL(total)) + if (IS_DEFINED_VAL(progressTotal)) { - percent = completed * 100; - if (total != 0) - percent /= total; + percent = progressCompleted * 100; + if (progressTotal != 0) + percent /= progressTotal; } } if (percent != _prevPercentValue) |