diff options
Diffstat (limited to 'CPP/7zip/Archive/Iso/IsoIn.cpp')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Iso/IsoIn.cpp | 197 |
1 files changed, 143 insertions, 54 deletions
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp index 7ed618d2..ba12acae 100755..100644 --- a/CPP/7zip/Archive/Iso/IsoIn.cpp +++ b/CPP/7zip/Archive/Iso/IsoIn.cpp @@ -2,24 +2,34 @@ #include "StdAfx.h" -#include "IsoIn.h" +#include "../../../Common/MyException.h" #include "../../Common/StreamUtils.h" +#include "IsoIn.h" + namespace NArchive { namespace NIso { +struct CUnexpectedEndException {}; +struct CHeaderErrorException {}; +struct CEndianErrorException {}; + Byte CInArchive::ReadByte() { if (m_BufferPos >= BlockSize) m_BufferPos = 0; if (m_BufferPos == 0) { - size_t processedSize = BlockSize; - if (ReadStream(_stream, m_Buffer, &processedSize) != S_OK) - throw 1; - if (processedSize != BlockSize) - throw 1; + size_t processed = BlockSize; + HRESULT res = ReadStream(_stream, m_Buffer, &processed); + if (res != S_OK) + throw CSystemException(res); + if (processed != BlockSize) + throw CUnexpectedEndException(); + UInt64 end = _position + processed; + if (PhySize < end) + PhySize = end; } Byte b = m_Buffer[m_BufferPos++]; _position++; @@ -44,16 +54,16 @@ void CInArchive::SkipZeros(size_t size) { Byte b = ReadByte(); if (b != 0) - throw 1; + throw CHeaderErrorException(); } } UInt16 CInArchive::ReadUInt16Spec() { - UInt16 value = 0; + UInt16 val = 0; for (int i = 0; i < 2; i++) - value |= ((UInt16)(ReadByte()) << (8 * i)); - return value; + val |= ((UInt16)(ReadByte()) << (8 * i)); + return val; } @@ -61,47 +71,47 @@ UInt16 CInArchive::ReadUInt16() { Byte b[4]; ReadBytes(b, 4); - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 2; i++) { if (b[i] != b[3 - i]) IncorrectBigEndian = true; - value |= ((UInt16)(b[i]) << (8 * i)); + val |= ((UInt16)(b[i]) << (8 * i)); } - return (UInt16)value; + return (UInt16)val; } UInt32 CInArchive::ReadUInt32Le() { - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 4; i++) - value |= ((UInt32)(ReadByte()) << (8 * i)); - return value; + val |= ((UInt32)(ReadByte()) << (8 * i)); + return val; } UInt32 CInArchive::ReadUInt32Be() { - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 4; i++) { - value <<= 8; - value |= ReadByte(); + val <<= 8; + val |= ReadByte(); } - return value; + return val; } UInt32 CInArchive::ReadUInt32() { Byte b[8]; ReadBytes(b, 8); - UInt32 value = 0; + UInt32 val = 0; for (int i = 0; i < 4; i++) { if (b[i] != b[7 - i]) - throw 1; - value |= ((UInt32)(b[i]) << (8 * i)); + throw CEndianErrorException(); + val |= ((UInt32)(b[i]) << (8 * i)); } - return value; + return val; } UInt32 CInArchive::ReadDigits(int numDigits) @@ -115,7 +125,7 @@ UInt32 CInArchive::ReadDigits(int numDigits) if (b == 0) // it's bug in some CD's b = '0'; else - throw 1; + throw CHeaderErrorException(); } UInt32 d = (UInt32)(b - '0'); res *= 10; @@ -158,16 +168,16 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) { r.ExtendedAttributeRecordLen = ReadByte(); if (r.ExtendedAttributeRecordLen != 0) - throw 1; + throw CHeaderErrorException(); r.ExtentLocation = ReadUInt32(); - r.DataLength = ReadUInt32(); + r.Size = ReadUInt32(); ReadRecordingDateTime(r.DateTime); r.FileFlags = ReadByte(); r.FileUnitSize = ReadByte(); r.InterleaveGapSize = ReadByte(); r.VolSequenceNumber = ReadUInt16(); Byte idLen = ReadByte(); - r.FileId.SetCapacity(idLen); + r.FileId.Alloc(idLen); ReadBytes((Byte *)r.FileId, idLen); int padSize = 1 - (idLen & 1); @@ -176,9 +186,9 @@ void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len) int curPos = 33 + idLen + padSize; if (curPos > len) - throw 1; + throw CHeaderErrorException(); int rem = len - curPos; - r.SystemUse.SetCapacity(rem); + r.SystemUse.Alloc(rem); ReadBytes((Byte *)r.SystemUse, rem); } @@ -242,15 +252,34 @@ static inline bool CheckSignature(const Byte *sig, const Byte *data) void CInArchive::SeekToBlock(UInt32 blockIndex) { - if (_stream->Seek((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize, STREAM_SEEK_SET, &_position) != S_OK) - throw 1; + HRESULT res = _stream->Seek((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize, STREAM_SEEK_SET, &_position); + if (res != S_OK) + throw CSystemException(res); m_BufferPos = 0; } +static const int kNumLevelsMax = 256; + void CInArchive::ReadDir(CDir &d, int level) { if (!d.IsDir()) return; + if (level > kNumLevelsMax) + { + TooDeepDirs = true; + return; + } + + { + FOR_VECTOR (i, UniqStartLocations) + if (UniqStartLocations[i] == d.ExtentLocation) + { + SelfLinkedDirs = true; + return; + } + UniqStartLocations.Add(d.ExtentLocation); + } + SeekToBlock(d.ExtentLocation); UInt64 startPos = _position; @@ -258,7 +287,7 @@ void CInArchive::ReadDir(CDir &d, int level) for (;;) { UInt64 offset = _position - startPos; - if (offset >= d.DataLength) + if (offset >= d.Size) break; Byte len = ReadByte(); if (len == 0) @@ -273,21 +302,44 @@ void CInArchive::ReadDir(CDir &d, int level) firstItem = false; } - for (int i = 0; i < d._subItems.Size(); i++) + FOR_VECTOR (i, d._subItems) ReadDir(d._subItems[i], level + 1); + + UniqStartLocations.DeleteBack(); } void CInArchive::CreateRefs(CDir &d) { if (!d.IsDir()) return; - for (int i = 0; i < d._subItems.Size(); i++) + for (unsigned i = 0; i < d._subItems.Size();) { CRef ref; CDir &subItem = d._subItems[i]; subItem.Parent = &d; ref.Dir = &d; - ref.Index = i; + ref.Index = i++; + ref.NumExtents = 1; + ref.TotalSize = subItem.Size; + if (subItem.IsNonFinalExtent()) + { + for (;;) + { + if (i == d._subItems.Size()) + { + HeadersError = true; + break; + } + const CDir &next = d._subItems[i]; + if (!subItem.AreMultiPartEqualWith(next)) + break; + i++; + ref.NumExtents++; + ref.TotalSize += next.Size; + if (!next.IsNonFinalExtent()) + break; + } + } Refs.Add(ref); CreateRefs(subItem); } @@ -310,13 +362,13 @@ void CInArchive::ReadBootInfo() CBootValidationEntry e; e.PlatformId = ReadByte(); if (ReadUInt16Spec() != 0) - throw 1; + throw CHeaderErrorException(); ReadBytes(e.Id, sizeof(e.Id)); /* UInt16 checkSum = */ ReadUInt16Spec(); if (ReadByte() != 0x55) - throw 1; + throw CHeaderErrorException(); if (ReadByte() != 0xAA) - throw 1; + throw CHeaderErrorException(); } b = ReadByte(); if (b == NBootEntryId::kInitialEntryBootable || b == NBootEntryId::kInitialEntryNotBootable) @@ -327,11 +379,11 @@ void CInArchive::ReadBootInfo() e.LoadSegment = ReadUInt16Spec(); e.SystemType = ReadByte(); if (ReadByte() != 0) - throw 1; + throw CHeaderErrorException(); e.SectorCount = ReadUInt16Spec(); e.LoadRBA = ReadUInt32Le(); if (ReadByte() != 0) - throw 1; + throw CHeaderErrorException(); BootEntries.Add(e); } else @@ -340,16 +392,22 @@ void CInArchive::ReadBootInfo() HRESULT CInArchive::Open2() { - Clear(); - RINOK(_stream->Seek(kStartPos, STREAM_SEEK_CUR, &_position)); + _position = 0; + RINOK(_stream->Seek(0, STREAM_SEEK_END, &_fileSize)); + if (_fileSize < kStartPos) + return S_FALSE; + RINOK(_stream->Seek(kStartPos, STREAM_SEEK_SET, &_position)); + PhySize = _position; m_BufferPos = 0; BlockSize = kBlockSize; + for (;;) { Byte sig[7]; ReadBytes(sig, 7); Byte ver = sig[6]; + if (!CheckSignature(kSig_CD001, sig + 1)) { return S_FALSE; @@ -372,9 +430,10 @@ HRESULT CInArchive::Open2() continue; */ } + // version = 2 for ISO 9660:1999? if (ver > 2) - throw S_FALSE; + return S_FALSE; if (sig[0] == NVolDescType::kTerminator) { @@ -382,7 +441,8 @@ HRESULT CInArchive::Open2() // Skip(0x800 - 7); // continue; } - switch(sig[0]) + + switch (sig[0]) { case NVolDescType::kBootRecord: { @@ -408,6 +468,7 @@ HRESULT CInArchive::Open2() break; } } + if (VolDescs.IsEmpty()) return S_FALSE; for (MainVolDescIndex = VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--) @@ -417,30 +478,58 @@ HRESULT CInArchive::Open2() const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex]; if (vd.LogicalBlockSize != kBlockSize) return S_FALSE; + + IsArc = true; + (CDirRecord &)_rootDir = vd.RootDirRecord; ReadDir(_rootDir, 0); CreateRefs(_rootDir); ReadBootInfo(); + + { + FOR_VECTOR(i, Refs) + { + const CRef &ref = Refs[i]; + for (UInt32 j = 0; j < ref.NumExtents; j++) + { + const CDir &item = ref.Dir->_subItems[ref.Index + j]; + if (!item.IsDir()) + UpdatePhySize(item.ExtentLocation, item.Size); + } + } + } + { + FOR_VECTOR(i, BootEntries) + { + const CBootInitialEntry &be = BootEntries[i]; + UpdatePhySize(be.LoadRBA, GetBootItemSize(i)); + } + } return S_OK; } HRESULT CInArchive::Open(IInStream *inStream) { + Clear(); _stream = inStream; - UInt64 pos; - RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &pos)); - RINOK(_stream->Seek(0, STREAM_SEEK_END, &_archiveSize)); - RINOK(_stream->Seek(pos, STREAM_SEEK_SET, &_position)); - HRESULT res = S_FALSE; - try { res = Open2(); } - catch(...) { Clear(); res = S_FALSE; } - _stream.Release(); - return res; + try { return Open2(); } + catch(const CSystemException &e) { return e.ErrorCode; } + catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } + catch(CHeaderErrorException &) { HeadersError = true; return S_FALSE; } + catch(CEndianErrorException &) { IncorrectBigEndian = true; return S_FALSE; } } void CInArchive::Clear() { + IsArc = false; + UnexpectedEnd = false; + HeadersError = false; IncorrectBigEndian = false; + TooDeepDirs = false; + SelfLinkedDirs = false; + + UniqStartLocations.Clear(); + Refs.Clear(); _rootDir.Clear(); VolDescs.Clear(); |