diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2014-11-23 03:00:00 +0300 |
---|---|---|
committer | Kornel LesiĆski <kornel@geekhood.net> | 2016-05-28 02:16:51 +0300 |
commit | f08f4dcc3c02464c17753b3feafcfe5243b9e236 (patch) | |
tree | b0e1b15bc5368d92dff422e8ec0818564a2b00b8 /CPP/7zip/Archive/Cab | |
parent | 83f8ddcc5b2161e1e3c49666265257fca8aeb12c (diff) |
9.349.34
Diffstat (limited to 'CPP/7zip/Archive/Cab')
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabBlockInStream.cpp | 191 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabBlockInStream.h | 31 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabHandler.cpp | 512 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabHandler.h | 11 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabHeader.cpp | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabHeader.h | 23 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabIn.cpp | 446 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabIn.h | 129 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabItem.h | 29 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/CabRegister.cpp | 14 | ||||
-rw-r--r--[-rwxr-xr-x] | CPP/7zip/Archive/Cab/StdAfx.h | 2 |
11 files changed, 846 insertions, 542 deletions
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp index 12c73eb5..cebec610 100755..100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp @@ -3,8 +3,7 @@ #include "StdAfx.h" #include "../../../../C/Alloc.h" - -#include "Common/Defs.h" +#include "../../../../C/CpuArch.h" #include "../../Common/StreamUtils.h" @@ -17,173 +16,73 @@ static const UInt32 kBlockSize = (1 << 16); bool CCabBlockInStream::Create() { - if (!_buffer) - _buffer = (Byte *)::MyAlloc(kBlockSize); - return (_buffer != 0); + if (!_buf) + _buf = (Byte *)::MyAlloc(kBlockSize); + return _buf != 0; } CCabBlockInStream::~CCabBlockInStream() { - MyFree(_buffer); + ::MyFree(_buf); } -class CCheckSum2 -{ - UInt32 m_Value; - int m_Pos; - Byte m_Hist[4]; -public: - CCheckSum2(): m_Value(0){}; - void Init() { m_Value = 0; m_Pos = 0; } - void Update(const void *data, UInt32 size); - void FinishDataUpdate() - { - for (int i = 0; i < m_Pos; i++) - m_Value ^= ((UInt32)(m_Hist[i])) << (8 * (m_Pos - i - 1)); - } - void UpdateUInt32(UInt32 v) { m_Value ^= v; } - UInt32 GetResult() const { return m_Value; } -}; - -void CCheckSum2::Update(const void *data, UInt32 size) +static UInt32 CheckSum(const Byte *p, UInt32 size) { - UInt32 checkSum = m_Value; - const Byte *dataPointer = (const Byte *)data; - - while (size != 0 && m_Pos != 0) - { - m_Hist[m_Pos] = *dataPointer++; - m_Pos = (m_Pos + 1) & 3; - size--; - if (m_Pos == 0) - for (int i = 0; i < 4; i++) - checkSum ^= ((UInt32)m_Hist[i]) << (8 * i); - } - - int numWords = size / 4; - - while (numWords-- != 0) + UInt32 sum = 0; + for (UInt32 i = size >> 2; i != 0; i--) { - UInt32 temp = *dataPointer++; - temp |= ((UInt32)(*dataPointer++)) << 8; - temp |= ((UInt32)(*dataPointer++)) << 16; - temp |= ((UInt32)(*dataPointer++)) << 24; - checkSum ^= temp; + sum ^= GetUi32(p); + p += 4; } - m_Value = checkSum; - size &= 3; - - while (size != 0) - { - m_Hist[m_Pos] = *dataPointer++; - m_Pos = (m_Pos + 1) & 3; - size--; - } + if (size > 2) sum ^= (UInt32)(*p++) << 16; + if (size > 1) sum ^= (UInt32)(*p++) << 8; + if (size > 0) sum ^= (UInt32)(*p++); + return sum; } -static const UInt32 kDataBlockHeaderSize = 8; - -class CTempCabInBuffer2 +HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize) { -public: - Byte Buffer[kDataBlockHeaderSize]; - UInt32 Pos; - Byte ReadByte() - { - return Buffer[Pos++]; - } - UInt32 ReadUInt32() - { - UInt32 value = 0; - for (int i = 0; i < 4; i++) - value |= (((UInt32)ReadByte()) << (8 * i)); - return value; - } - UInt16 ReadUInt16() - { - UInt16 value = 0; - for (int i = 0; i < 2; i++) - value |= (((UInt16)ReadByte()) << (8 * i)); - return value; - } -}; - -HRESULT CCabBlockInStream::PreRead(UInt32 &packSize, UInt32 &unpackSize) -{ - CTempCabInBuffer2 inBuffer; - inBuffer.Pos = 0; - RINOK(ReadStream_FALSE(_stream, inBuffer.Buffer, kDataBlockHeaderSize)) - - UInt32 checkSum = inBuffer.ReadUInt32(); - packSize = inBuffer.ReadUInt16(); - unpackSize = inBuffer.ReadUInt16(); - if (ReservedSize != 0) - { - RINOK(ReadStream_FALSE(_stream, _buffer, ReservedSize)); - } - _pos = 0; - CCheckSum2 checkSumCalc; - checkSumCalc.Init(); - UInt32 packSize2 = packSize; - if (MsZip && _size == 0) + const UInt32 kHeaderSize = 8; + const UInt32 kReservedMax = 256; + Byte header[kHeaderSize + kReservedMax]; + RINOK(ReadStream_FALSE(stream, header, kHeaderSize + ReservedSize)) + packSize = GetUi16(header + 4); + unpackSize = GetUi16(header + 6); + if (packSize > kBlockSize - _size) + return S_FALSE; + RINOK(ReadStream_FALSE(stream, _buf + _size, packSize)); + + if (MsZip) { - if (packSize < 2) - return S_FALSE; // bad block; - Byte sig[2]; - RINOK(ReadStream_FALSE(_stream, sig, 2)); - if (sig[0] != 0x43 || sig[1] != 0x4B) + if (_size == 0) + { + if (packSize < 2 || _buf[0] != 0x43 || _buf[1] != 0x4B) + return S_FALSE; + _pos = 2; + } + if (_size + packSize > ((UInt32)1 << 15) + 12) /* v9.31 fix. MSZIP specification */ return S_FALSE; - packSize2 -= 2; - checkSumCalc.Update(sig, 2); } - if (kBlockSize - _size < packSize2) - return S_FALSE; - - UInt32 curSize = packSize2; - if (curSize != 0) - { - size_t processedSizeLoc = curSize; - RINOK(ReadStream(_stream, _buffer + _size, &processedSizeLoc)); - checkSumCalc.Update(_buffer + _size, (UInt32)processedSizeLoc); - _size += (UInt32)processedSizeLoc; - if (processedSizeLoc != curSize) + if (GetUi32(header) != 0) // checkSum + if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize)) return S_FALSE; - } - TotalPackSize = _size; - checkSumCalc.FinishDataUpdate(); - - bool dataError; - if (checkSum == 0) - dataError = false; - else - { - checkSumCalc.UpdateUInt32(packSize | (((UInt32)unpackSize) << 16)); - dataError = (checkSumCalc.GetResult() != checkSum); - } - DataError |= dataError; - return dataError ? S_FALSE : S_OK; + _size += packSize; + return S_OK; } STDMETHODIMP CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize) { - if (processedSize != 0) - *processedSize = 0; - if (size == 0) - return S_OK; - if (_size != 0) - { - size = MyMin(_size, size); - memmove(data, _buffer + _pos, size); - _pos += size; - _size -= size; - if (processedSize != 0) - *processedSize = size; - return S_OK; - } - return S_OK; // no blocks data + UInt32 rem = _size - _pos; + if (size > rem) + size = rem; + memcpy(data, _buf + _pos, size); + _pos += size; + if (processedSize) + *processedSize = size; + return S_OK; } }} diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h index 1db3835b..b795ed97 100755..100644 --- a/CPP/7zip/Archive/Cab/CabBlockInStream.h +++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h @@ -1,9 +1,9 @@ -// CabBlockInStream.cpp +// CabBlockInStream.h -#ifndef __CABBLOCKINSTREAM_H -#define __CABBLOCKINSTREAM_H +#ifndef __CAB_BLOCK_IN_STREAM_H +#define __CAB_BLOCK_IN_STREAM_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" #include "../../IStream.h" namespace NArchive { @@ -13,30 +13,23 @@ class CCabBlockInStream: public ISequentialInStream, public CMyUnknownImp { - CMyComPtr<ISequentialInStream> _stream; - Byte *_buffer; - UInt32 _pos; + Byte *_buf; UInt32 _size; + UInt32 _pos; public: - UInt32 TotalPackSize; - UInt32 ReservedSize; - bool DataError; + UInt32 ReservedSize; // < 256 bool MsZip; - CCabBlockInStream(): _buffer(0), ReservedSize(0), MsZip(false), DataError(false), TotalPackSize(0) {} + MY_UNKNOWN_IMP + + CCabBlockInStream(): _buf(0), ReservedSize(0), MsZip(false) {} ~CCabBlockInStream(); bool Create(); - void SetStream(ISequentialInStream *stream) { _stream = stream; } - - void InitForNewFolder() { TotalPackSize = 0; } - void InitForNewBlock() { _size = 0; } - - MY_UNKNOWN_IMP + void InitForNewBlock() { _size = 0; _pos = 0; } + HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize); STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); - - HRESULT PreRead(UInt32 &packSize, UInt32 &unpackSize); }; }} diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp index fd707fe5..22bc93a0 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHandler.cpp +++ b/CPP/7zip/Archive/Cab/CabHandler.cpp @@ -2,15 +2,17 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "../../../../C/Alloc.h" -#include "Common/ComTry.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" -#include "Common/UTFConvert.h" +#include "../../../Common/ComTry.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" +#include "../../../Common/UTFConvert.h" -#include "Windows/PropVariant.h" -#include "Windows/Time.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/ProgressUtils.h" #include "../../Common/StreamUtils.h" @@ -39,102 +41,243 @@ enum }; #endif -static STATPROPSTG kProps[] = +static const Byte kProps[] = { - { NULL, kpidPath, VT_BSTR}, - { NULL, kpidSize, VT_UI8}, - { NULL, kpidMTime, VT_FILETIME}, - { NULL, kpidAttrib, VT_UI4}, - { NULL, kpidMethod, VT_BSTR}, - { NULL, kpidBlock, VT_I4} + kpidPath, + kpidSize, + kpidMTime, + kpidAttrib, + kpidMethod, + kpidBlock #ifdef _CAB_DETAILS , - { L"BlockReal", kpidBlockReal, VT_UI4}, - { NULL, kpidOffset, VT_UI4}, - { NULL, kpidVolume, VT_UI4} + // kpidBlockReal, // L"BlockReal", + kpidOffset, + kpidVolume #endif }; -static const char *kMethods[] = +static const Byte kArcProps[] = { - "None", - "MSZip", - "Quantum", - "LZX" + kpidTotalPhySize, + kpidMethod, + // kpidSolid, + kpidNumBlocks, + kpidNumVolumes, + kpidVolumeIndex, + kpidId }; -static const int kNumMethods = sizeof(kMethods) / sizeof(kMethods[0]); -static const char *kUnknownMethod = "Unknown"; +IMP_IInArchive_Props +IMP_IInArchive_ArcProps -static STATPROPSTG kArcProps[] = +static const char *kMethods[] = { - { NULL, kpidMethod, VT_BSTR}, - // { NULL, kpidSolid, VT_BOOL}, - { NULL, kpidNumBlocks, VT_UI4}, - { NULL, kpidNumVolumes, VT_UI4} + "None" + , "MSZip" + , "Quantum" + , "LZX" }; -IMP_IInArchive_Props -IMP_IInArchive_ArcProps +static const unsigned kMethodNameBufSize = 32; // "Quantum:255" + +static void SetMethodName(char *s, unsigned method, unsigned param) +{ + if (method < ARRAY_SIZE(kMethods)) + { + s = MyStpCpy(s, kMethods[method]); + if (method != NHeader::NMethod::kLZX && + method != NHeader::NMethod::kQuantum) + return; + *s++ = ':'; + method = param; + } + ConvertUInt32ToString(method, s); +} STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; - switch(propID) + NCOM::CPropVariant prop; + switch (propID) { case kpidMethod: { - AString resString; - CRecordVector<Byte> ids; - int i; - for (int v = 0; v < m_Database.Volumes.Size(); v++) + UInt32 mask = 0; + UInt32 params[2] = { 0, 0 }; { - const CDatabaseEx &de = m_Database.Volumes[v]; - for (i = 0; i < de.Folders.Size(); i++) - ids.AddToUniqueSorted(de.Folders[i].GetCompressionMethod()); + FOR_VECTOR (v, m_Database.Volumes) + { + const CRecordVector<CFolder> &folders = m_Database.Volumes[v].Folders; + FOR_VECTOR (i, folders) + { + const CFolder &folder = folders[i]; + unsigned method = folder.GetMethod(); + mask |= ((UInt32)1 << method); + if (method == NHeader::NMethod::kLZX || + method == NHeader::NMethod::kQuantum) + { + unsigned di = (method == NHeader::NMethod::kQuantum) ? 0 : 1; + if (params[di] < folder.MethodMinor) + params[di] = folder.MethodMinor; + } + } + } } - for (i = 0; i < ids.Size(); i++) + AString s; + for (unsigned i = 0; i < kNumMethodsMax; i++) { - Byte id = ids[i]; - AString method = (id < kNumMethods) ? kMethods[id] : kUnknownMethod; - if (!resString.IsEmpty()) - resString += ' '; - resString += method; + if ((mask & (1 << i)) == 0) + continue; + if (!s.IsEmpty()) + s += ' '; + char temp[kMethodNameBufSize]; + SetMethodName(temp, i, params[i == NHeader::NMethod::kQuantum ? 0 : 1]); + s += temp; } - prop = resString; + prop = s; break; } // case kpidSolid: prop = _database.IsSolid(); break; case kpidNumBlocks: { UInt32 numFolders = 0; - for (int v = 0; v < m_Database.Volumes.Size(); v++) + FOR_VECTOR (v, m_Database.Volumes) numFolders += m_Database.Volumes[v].Folders.Size(); prop = numFolders; break; } - case kpidNumVolumes: + + case kpidTotalPhySize: { + if (m_Database.Volumes.Size() > 1) + { + UInt64 sum = 0; + FOR_VECTOR (v, m_Database.Volumes) + sum += m_Database.Volumes[v].ArcInfo.Size; + prop = sum; + } + break; + } + + case kpidNumVolumes: prop = (UInt32)m_Database.Volumes.Size(); break; + + case kpidVolumeIndex: + { + if (m_Database.Volumes.Size() == 1) + { + const CDatabaseEx &db = m_Database.Volumes[0]; + const CInArcInfo &ai = db.ArcInfo; + prop = (UInt32)ai.CabinetNumber; + } + break; + } + + case kpidId: + { + if (m_Database.Volumes.Size() != 0) + { + prop = (UInt32)m_Database.Volumes[0].ArcInfo.SetID; + } + break; + } + + case kpidOffset: + /* + if (m_Database.Volumes.Size() == 1) + prop = m_Database.Volumes[0].StartPosition; + */ + prop = _offset; + break; + + case kpidPhySize: + /* + if (m_Database.Volumes.Size() == 1) + prop = (UInt64)m_Database.Volumes[0].ArcInfo.Size; + */ + prop = (UInt64)_phySize; + break; + + case kpidErrorFlags: + { + UInt32 v = 0; + if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; + if (_errorInHeaders) v |= kpv_ErrorFlags_HeadersError; + if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd; + prop = v; + break; + } + + case kpidError: + if (!_errorMessage.IsEmpty()) + prop = _errorMessage; + break; + + case kpidName: + { + if (m_Database.Volumes.Size() == 1) + { + const CDatabaseEx &db = m_Database.Volumes[0]; + const CInArcInfo &ai = db.ArcInfo; + if (ai.SetID != 0) + { + AString s; + char temp[32]; + ConvertUInt32ToString(ai.SetID, temp); + s += temp; + ConvertUInt32ToString(ai.CabinetNumber + 1, temp); + s += '_'; + s += temp; + s += ".cab"; + prop = s; + } + /* + // that code is incomplete. It gcan give accurate name of volume + char s[32]; + ConvertUInt32ToString(ai.CabinetNumber + 2, s); + unsigned len = MyStringLen(s); + if (ai.IsThereNext()) + { + AString fn = ai.NextArc.FileName; + if (fn.Len() > 4 && StringsAreEqualNoCase_Ascii(fn.RightPtr(4), ".cab")) + fn.DeleteFrom(fn.Len() - 4); + if (len < fn.Len()) + { + if (strcmp(s, fn.RightPtr(len)) == 0) + { + AString s2 = fn; + s2.DeleteFrom(fn.Len() - len); + ConvertUInt32ToString(ai.CabinetNumber + 1, s); + s2 += s; + s2 += ".cab"; + prop = GetUnicodeString(s2); + } + } + } + */ + } + break; } + + // case kpidShortComment: } prop.Detach(value); return S_OK; COM_TRY_END } -STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) { COM_TRY_BEGIN - NWindows::NCOM::CPropVariant prop; + NCOM::CPropVariant prop; const CMvItem &mvItem = m_Database.Items[index]; const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; - int itemIndex = mvItem.ItemIndex; + unsigned itemIndex = mvItem.ItemIndex; const CItem &item = db.Items[itemIndex]; - switch(propID) + switch (propID) { case kpidPath: { @@ -146,9 +289,10 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va prop = (const wchar_t *)NItemName::WinNameToOSName(unicodeName); break; } + case kpidIsDir: prop = item.IsDir(); break; case kpidSize: prop = item.Size; break; - case kpidAttrib: prop = item.GetWinAttributes(); break; + case kpidAttrib: prop = item.GetWinAttrib(); break; case kpidMTime: { @@ -168,24 +312,17 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va { UInt32 realFolderIndex = item.GetFolderIndex(db.Folders.Size()); const CFolder &folder = db.Folders[realFolderIndex]; - int methodIndex = folder.GetCompressionMethod(); - AString method = (methodIndex < kNumMethods) ? kMethods[methodIndex] : kUnknownMethod; - if (methodIndex == NHeader::NCompressionMethodMajor::kLZX || - methodIndex == NHeader::NCompressionMethodMajor::kQuantum) - { - method += ':'; - char temp[32]; - ConvertUInt64ToString(folder.CompressionTypeMinor, temp); - method += temp; - } - prop = method; + char s[kMethodNameBufSize];; + SetMethodName(s, folder.GetMethod(), folder.MethodMinor); + prop = s; break; } + case kpidBlock: prop = (Int32)m_Database.GetFolderIndex(&mvItem); break; #ifdef _CAB_DETAILS - case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; + // case kpidBlockReal: prop = (UInt32)item.FolderIndex; break; case kpidOffset: prop = (UInt32)item.Offset; break; case kpidVolume: prop = (UInt32)mvItem.VolumeIndex; break; @@ -196,39 +333,13 @@ STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *va COM_TRY_END } -/* -class CProgressImp: public CProgressVirt -{ - CMyComPtr<IArchiveOpenCallback> m_OpenArchiveCallback; -public: - STDMETHOD(SetTotal)(const UInt64 *numFiles); - STDMETHOD(SetCompleted)(const UInt64 *numFiles); - void Init(IArchiveOpenCallback *openArchiveCallback) - { m_OpenArchiveCallback = openArchiveCallback; } -}; - -STDMETHODIMP CProgressImp::SetTotal(const UInt64 *numFiles) -{ - if (m_OpenArchiveCallback) - return m_OpenArchiveCallback->SetCompleted(numFiles, NULL); - return S_OK; -} - -STDMETHODIMP CProgressImp::SetCompleted(const UInt64 *numFiles) -{ - if (m_OpenArchiveCallback) - return m_OpenArchiveCallback->SetCompleted(numFiles, NULL); - return S_OK; -} -*/ - STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback) { COM_TRY_BEGIN Close(); - HRESULT res = S_FALSE; + CInArchive archive; CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback; callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback); @@ -236,96 +347,169 @@ STDMETHODIMP CHandler::Open(IInStream *inStream, CMyComPtr<IInStream> nextStream = inStream; bool prevChecked = false; UInt64 numItems = 0; - try + unsigned numTempVolumes = 0; + // try { - while (nextStream != 0) + while (nextStream != NULL) { CDatabaseEx db; db.Stream = nextStream; - res = archive.Open(maxCheckStartPosition, db); - if (res == S_OK) + HRESULT res = archive.Open(db, maxCheckStartPosition); + _errorInHeaders |= archive.HeaderError; + _errorInHeaders |= archive.ErrorInNames; + _unexpectedEnd |= archive.UnexpectedEnd; + + if (res == S_OK && !m_Database.Volumes.IsEmpty()) { - if (!m_Database.Volumes.IsEmpty()) + const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo; + unsigned cabNumber = db.ArcInfo.CabinetNumber; + if (lastArc.SetID != db.ArcInfo.SetID) + res = S_FALSE; + else if (prevChecked) + { + if (cabNumber != lastArc.CabinetNumber + 1) + res = S_FALSE; + } + else if (cabNumber >= lastArc.CabinetNumber) + res = S_FALSE; + else if (numTempVolumes != 0) { - const CDatabaseEx &dbPrev = m_Database.Volumes[prevChecked ? m_Database.Volumes.Size() - 1 : 0]; - if (dbPrev.ArchiveInfo.SetID != db.ArchiveInfo.SetID || - dbPrev.ArchiveInfo.CabinetNumber + (prevChecked ? 1: - 1) != - db.ArchiveInfo.CabinetNumber) + const CArchInfo &prevArc = m_Database.Volumes[numTempVolumes - 1].ArcInfo; + if (cabNumber != prevArc.CabinetNumber + 1) res = S_FALSE; } } + + if (archive.IsArc || res == S_OK) + { + _isArc = true; + if (m_Database.Volumes.IsEmpty()) + { + _offset = db.StartPosition; + _phySize = db.ArcInfo.Size; + } + } + if (res == S_OK) - m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : 0, db); - else if (res != S_FALSE) - return res; + { + numItems += db.Items.Size(); + m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : numTempVolumes, db); + if (!prevChecked && m_Database.Volumes.Size() > 1) + { + numTempVolumes++; + if (db.ArcInfo.CabinetNumber + 1 == m_Database.Volumes[numTempVolumes].ArcInfo.CabinetNumber) + numTempVolumes = 0; + } + } else { + if (res != S_FALSE) + return res; if (m_Database.Volumes.IsEmpty()) return S_FALSE; if (prevChecked) break; prevChecked = true; + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } } - numItems += db.Items.Size(); RINOK(callback->SetCompleted(&numItems, NULL)); - nextStream = 0; + nextStream = NULL; + for (;;) { - const COtherArchive *otherArchive = 0; + const COtherArc *otherArc = NULL; if (!prevChecked) { - const CInArchiveInfo &ai = m_Database.Volumes.Front().ArchiveInfo; - if (ai.IsTherePrev()) - otherArchive = &ai.PrevArc; + if (numTempVolumes == 0) + { + const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo; + if (ai.IsTherePrev()) + otherArc = &ai.PrevArc; + else + prevChecked = true; + } else - prevChecked = true; + { + const CInArcInfo &ai = m_Database.Volumes[numTempVolumes - 1].ArcInfo; + if (ai.IsThereNext()) + otherArc = &ai.NextArc; + else + { + prevChecked = true; + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } + } } - if (otherArchive == 0) + if (!otherArc) { - const CInArchiveInfo &ai = m_Database.Volumes.Back().ArchiveInfo; + const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo; if (ai.IsThereNext()) - otherArchive = &ai.NextArc; + otherArc = &ai.NextArc; } - if (!otherArchive) + if (!otherArc) break; - const UString fullName = MultiByteToUnicodeString(otherArchive->FileName, CP_ACP); if (!openVolumeCallback) break; - + // printf("\n%s", otherArc->FileName); + const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP); HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream); if (result == S_OK) break; if (result != S_FALSE) return result; + + if (!_errorMessage.IsEmpty()) + _errorMessage += L"\n"; + _errorMessage += L"Can't open volume: "; + _errorMessage += fullName; + if (prevChecked) break; prevChecked = true; + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; + } } + + } // read nextStream iteration + + if (numTempVolumes != 0) + { + m_Database.Volumes.DeleteFrontal(numTempVolumes); + numTempVolumes = 0; } - if (res == S_OK) + if (m_Database.Volumes.IsEmpty()) + return S_FALSE; + else { m_Database.FillSortAndShrink(); if (!m_Database.Check()) - res = S_FALSE; + return S_FALSE; } } - catch(...) - { - res = S_FALSE; - } - if (res != S_OK) - { - Close(); - return res; - } COM_TRY_END return S_OK; } STDMETHODIMP CHandler::Close() { + _errorMessage.Empty(); + _isArc = false; + _errorInHeaders = false; + _unexpectedEnd = false; + // _mainVolIndex = -1; + _phySize = 0; + _offset = 0; + m_Database.Clear(); return S_OK; } @@ -348,8 +532,8 @@ private: bool TempBufMode; UInt32 m_BufStartFolderOffset; - int m_StartIndex; - int m_CurrentIndex; + unsigned m_StartIndex; + unsigned m_CurrentIndex; CMyComPtr<IArchiveExtractCallback> m_ExtractCallback; bool m_TestMode; @@ -379,7 +563,7 @@ public: void Init( const CMvDatabaseEx *database, const CRecordVector<bool> *extractStatuses, - int startIndex, + unsigned startIndex, UInt64 folderSize, IArchiveExtractCallback *extractCallback, bool testMode); @@ -393,7 +577,7 @@ public: void CFolderOutStream::Init( const CMvDatabaseEx *database, const CRecordVector<bool> *extractStatuses, - int startIndex, + unsigned startIndex, UInt64 folderSize, IArchiveExtractCallback *extractCallback, bool testMode) @@ -436,7 +620,7 @@ HRESULT CFolderOutStream::OpenFile() const CMvItem &mvItem = m_Database->Items[m_StartIndex + m_CurrentIndex]; const CItem &item = m_Database->Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; int numExtractItems = 0; - int curIndex; + unsigned curIndex; for (curIndex = m_CurrentIndex; curIndex < m_ExtractStatuses->Size(); curIndex++) { const CMvItem &mvItem2 = m_Database->Items[m_StartIndex + curIndex]; @@ -559,7 +743,7 @@ HRESULT CFolderOutStream::Write2(const void *data, UInt32 size, UInt32 *processe if (!TempBuf && TempBufMode && m_RealOutStream) { - RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(CloseFileWithResOp(NExtract::NOperationResult::kUnsupportedMethod)); } else { @@ -638,7 +822,7 @@ HRESULT CFolderOutStream::Unsupported() if (result != S_FALSE && result != S_OK) return result; m_RealOutStream.Release(); - RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnSupportedMethod)); + RINOK(m_ExtractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod)); m_CurrentIndex++; } return S_OK; @@ -649,7 +833,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, Int32 testModeSpec, IArchiveExtractCallback *extractCallback) { COM_TRY_BEGIN - bool allFilesMode = (numItems == (UInt32)-1); + bool allFilesMode = (numItems == (UInt32)(Int32)-1); if (allFilesMode) numItems = m_Database.Items.Size(); if (numItems == 0) @@ -709,7 +893,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CMvItem &mvItem = m_Database.Items[index]; const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex]; - int itemIndex = mvItem.ItemIndex; + unsigned itemIndex = mvItem.ItemIndex; const CItem &item = db.Items[itemIndex]; i++; @@ -747,7 +931,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, extractStatuses.Add(true); startIndex++; UInt64 curUnpack = item.GetEndOffset(); - for(;i < numItems; i++) + for (; i < numItems; i++) { int indexNext = allFilesMode ? i : indices[i]; const CMvItem &mvItem = m_Database.Items[indexNext]; @@ -779,11 +963,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, cabBlockInStreamSpec->MsZip = false; HRESULT res = S_OK; - switch(folder.GetCompressionMethod()) + switch (folder.GetMethod()) { - case NHeader::NCompressionMethodMajor::kNone: + case NHeader::NMethod::kNone: break; - case NHeader::NCompressionMethodMajor::kMSZip: + case NHeader::NMethod::kMSZip: if (!deflateDecoder) { deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder; @@ -791,21 +975,21 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } cabBlockInStreamSpec->MsZip = true; break; - case NHeader::NCompressionMethodMajor::kLZX: + case NHeader::NMethod::kLZX: if (!lzxDecoder) { lzxDecoderSpec = new NCompress::NLzx::CDecoder; lzxDecoder = lzxDecoderSpec; } - res = lzxDecoderSpec->SetParams(folder.CompressionTypeMinor); + res = lzxDecoderSpec->SetParams(folder.MethodMinor); break; - case NHeader::NCompressionMethodMajor::kQuantum: + case NHeader::NMethod::kQuantum: if (!quantumDecoder) { quantumDecoderSpec = new NCompress::NQuantum::CDecoder; quantumDecoder = quantumDecoderSpec; } - res = quantumDecoderSpec->SetParams(folder.CompressionTypeMinor); + res = quantumDecoderSpec->SetParams(folder.MethodMinor); break; default: res = E_INVALIDARG; @@ -820,9 +1004,8 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } RINOK(res); - cabBlockInStreamSpec->InitForNewFolder(); { - int volIndex = mvItem.VolumeIndex; + unsigned volIndex = mvItem.VolumeIndex; int locFolderIndex = item.GetFolderIndex(db.Folders.Size()); bool keepHistory = false; bool keepInputBuffer = false; @@ -838,8 +1021,7 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, const CFolder &folder = db.Folders[locFolderIndex]; if (f == 0) { - cabBlockInStreamSpec->SetStream(db.Stream); - cabBlockInStreamSpec->ReservedSize = db.ArchiveInfo.GetDataBlockReserveSize(); + cabBlockInStreamSpec->ReservedSize = db.ArcInfo.GetDataBlockReserveSize(); RINOK(db.Stream->Seek(db.StartPosition + folder.DataStart, STREAM_SEEK_SET, NULL)); } if (f == folder.NumDataBlocks) @@ -851,13 +1033,11 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, } f++; - cabBlockInStreamSpec->DataError = false; - if (!keepInputBuffer) cabBlockInStreamSpec->InitForNewBlock(); UInt32 packSize, unpackSize; - res = cabBlockInStreamSpec->PreRead(packSize, unpackSize); + res = cabBlockInStreamSpec->PreRead(db.Stream, packSize, unpackSize); if (res == S_FALSE) break; RINOK(res); @@ -878,22 +1058,36 @@ STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems, if (unpackRemain > kBlockSizeMax) unpackRemain = kBlockSizeMax; if (unpackRemain > unpackSize) - unpackRemain = unpackSize; + unpackRemain = unpackSize; - switch(folder.GetCompressionMethod()) + switch (folder.GetMethod()) { - case NHeader::NCompressionMethodMajor::kNone: + case NHeader::NMethod::kNone: res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; - case NHeader::NCompressionMethodMajor::kMSZip: - deflateDecoderSpec->SetKeepHistory(keepHistory); + case NHeader::NMethod::kMSZip: + deflateDecoderSpec->Set_KeepHistory(keepHistory); + /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block. + But PyCabArc can create CAB archives that doesn't have finish marker at the end of block. + Cabarc probably ignores such errors in cab archives. + Maybe we also should ignore that error? + Or we should extract full file and show the warning? */ + deflateDecoderSpec->Set_NeedFinishInput(true); res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); + if (res == S_OK) + { + if (!deflateDecoderSpec->IsFinished()) + res = S_FALSE; + if (!deflateDecoderSpec->IsFinalBlock()) + res = S_FALSE; + } + break; - case NHeader::NCompressionMethodMajor::kLZX: + case NHeader::NMethod::kLZX: lzxDecoderSpec->SetKeepHistory(keepHistory); res = lzxDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; - case NHeader::NCompressionMethodMajor::kQuantum: + case NHeader::NMethod::kQuantum: quantumDecoderSpec->SetKeepHistory(keepHistory); res = quantumDecoder->Code(cabBlockInStream, outStream, NULL, &unpackRemain, NULL); break; diff --git a/CPP/7zip/Archive/Cab/CabHandler.h b/CPP/7zip/Archive/Cab/CabHandler.h index 1edcd11e..6f44b875 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHandler.h +++ b/CPP/7zip/Archive/Cab/CabHandler.h @@ -3,8 +3,10 @@ #ifndef __CAB_HANDLER_H #define __CAB_HANDLER_H -#include "Common/MyCom.h" +#include "../../../Common/MyCom.h" + #include "../IArchive.h" + #include "CabIn.h" namespace NArchive { @@ -21,6 +23,13 @@ public: private: CMvDatabaseEx m_Database; + UString _errorMessage; + bool _isArc; + bool _errorInHeaders; + bool _unexpectedEnd; + // int _mainVolIndex; + UInt32 _phySize; + UInt64 _offset; }; }} diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp index 0cba1b0b..0cba1b0b 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHeader.cpp +++ b/CPP/7zip/Archive/Cab/CabHeader.cpp diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h index 0f0d2af3..9ec0760a 100755..100644 --- a/CPP/7zip/Archive/Cab/CabHeader.h +++ b/CPP/7zip/Archive/Cab/CabHeader.h @@ -3,7 +3,7 @@ #ifndef __ARCHIVE_CAB_HEADER_H #define __ARCHIVE_CAB_HEADER_H -#include "Common/Types.h" +#include "../../../Common/MyTypes.h" namespace NArchive { namespace NCab { @@ -12,17 +12,14 @@ namespace NHeader { const unsigned kMarkerSize = 8; extern Byte kMarker[kMarkerSize]; -namespace NArchive +namespace NArcFlags { - namespace NFlags - { - const int kPrevCabinet = 0x0001; - const int kNextCabinet = 0x0002; - const int kReservePresent = 0x0004; - } + const unsigned kPrevCabinet = 1; + const unsigned kNextCabinet = 2; + const unsigned kReservePresent = 4; } -namespace NCompressionMethodMajor +namespace NMethod { const Byte kNone = 0; const Byte kMSZip = 1; @@ -30,13 +27,13 @@ namespace NCompressionMethodMajor const Byte kLZX = 3; } -const int kFileNameIsUTFAttributeMask = 0x80; +const unsigned kFileNameIsUtf8_Mask = 0x80; namespace NFolderIndex { - const int kContinuedFromPrev = 0xFFFD; - const int kContinuedToNext = 0xFFFE; - const int kContinuedPrevAndNext = 0xFFFF; + const unsigned kContinuedFromPrev = 0xFFFD; + const unsigned kContinuedToNext = 0xFFFE; + const unsigned kContinuedPrevAndNext = 0xFFFF; } }}} diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp index c0bffa2d..c499f05f 100755..100644 --- a/CPP/7zip/Archive/Cab/CabIn.cpp +++ b/CPP/7zip/Archive/Cab/CabIn.cpp @@ -2,154 +2,353 @@ #include "StdAfx.h" -#include "../Common/FindSignature.h" +// #include <stdio.h> + +#include "../../../../C/CpuArch.h" + +#include "../../Common/LimitedStreams.h" +#include "../../Common/StreamUtils.h" #include "CabIn.h" +#define Get16(p) GetUi16(p) +#define Get32(p) GetUi32(p) + namespace NArchive { namespace NCab { -Byte CInArchive::Read8() +struct CUnexpectedEndException {}; + +void CInArchive::Skip(unsigned size) { - Byte b; - if (!inBuffer.ReadByte(b)) - throw CInArchiveException(CInArchiveException::kUnsupported); - return b; + if (_inBuffer.Skip(size) != size) + throw CUnexpectedEndException(); } -UInt16 CInArchive::Read16() +void CInArchive::Read(Byte *data, unsigned size) { - UInt16 value = 0; - for (int i = 0; i < 2; i++) - { - Byte b = Read8(); - value |= (UInt16(b) << (8 * i)); - } - return value; + if (_inBuffer.ReadBytes(data, size) != size) + throw CUnexpectedEndException(); } -UInt32 CInArchive::Read32() +void CInArchive::ReadName(AString &s) { - UInt32 value = 0; - for (int i = 0; i < 4; i++) + for (size_t i = 0; i < ((size_t)1 << 13); i++) { - Byte b = Read8(); - value |= (UInt32(b) << (8 * i)); + Byte b; + if (!_inBuffer.ReadByte(b)) + throw CUnexpectedEndException(); + if (b == 0) + { + memcpy(s.GetBuffer((unsigned)i), _tempBuf, i); + s.ReleaseBuffer((unsigned)i); + return; + } + if (_tempBuf.Size() == i) + _tempBuf.ChangeSize_KeepData(i * 2, i); + _tempBuf[i] = b; } - return value; -} - -AString CInArchive::SafeReadName() -{ - AString name; + for (;;) { - Byte b = Read8(); + Byte b; + if (!_inBuffer.ReadByte(b)) + throw CUnexpectedEndException(); if (b == 0) - return name; - name += (char)b; + break; } + + ErrorInNames = true; + s = "[ERROR-LONG-PATH]"; } -void CInArchive::ReadOtherArchive(COtherArchive &oa) +void CInArchive::ReadOtherArc(COtherArc &oa) { - oa.FileName = SafeReadName(); - oa.DiskName = SafeReadName(); + ReadName(oa.FileName); + ReadName(oa.DiskName); } -void CInArchive::Skip(UInt32 size) +struct CSignatureFinder +{ + Byte *Buf; + UInt32 Pos; + UInt32 End; + const Byte *Signature; + UInt32 SignatureSize; + + UInt32 _HeaderSize; + UInt32 _AlignSize; + UInt32 _BufUseCapacity; + + ISequentialInStream *Stream; + UInt64 Processed; // Global offset of start of Buf + + const UInt64 *SearchLimit; + + UInt32 GetTotalCapacity(UInt32 basicSize, UInt32 headerSize) + { + _HeaderSize = headerSize; + for (_AlignSize = (1 << 5); _AlignSize < _HeaderSize; _AlignSize <<= 1); + _BufUseCapacity = basicSize + _AlignSize; + return _BufUseCapacity + 16; + } + + /* + returns: + S_OK - signature found (at Pos) + S_FALSE - signature not found + */ + HRESULT Find(); +}; + +HRESULT CSignatureFinder::Find() { - while (size-- != 0) - Read8(); + for (;;) + { + Buf[End] = Signature[0]; // it's for fast search; + + while (End - Pos >= _HeaderSize) + { + const Byte *p = Buf + Pos; + Byte b = Signature[0]; + for (;;) + { + if (*p == b) break; p++; + if (*p == b) break; p++; + } + Pos = (UInt32)(p - Buf); + if (End - Pos < _HeaderSize) + { + Pos = End - _HeaderSize + 1; + break; + } + UInt32 i; + for (i = 1; i < SignatureSize && p[i] == Signature[i]; i++); + if (i == SignatureSize) + return S_OK; + Pos++; + } + + if (Pos >= _AlignSize) + { + UInt32 num = (Pos & ~(_AlignSize - 1)); + Processed += num; + Pos -= num; + End -= num; + memmove(Buf, Buf + num, End); + } + UInt32 rem = _BufUseCapacity - End; + if (SearchLimit) + { + if (Processed + Pos > *SearchLimit) + return S_FALSE; + UInt64 rem2 = *SearchLimit - (Processed + End) + _HeaderSize; + if (rem > rem2) + rem = (UInt32)rem2; + } + + UInt32 processedSize; + if (Processed == 0 && rem == _BufUseCapacity - _HeaderSize) + rem -= _AlignSize; // to make reads more aligned. + RINOK(Stream->Read(Buf + End, rem, &processedSize)); + if (processedSize == 0) + return S_FALSE; + End += processedSize; + } } -HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db) +bool CInArcInfo::Parse(const Byte *p) +{ + if (Get32(p + 0x0C) != 0 || + Get32(p + 0x14) != 0) + return false; + Size = Get32(p + 8); + if (Size < 36) + return false; + Flags = Get16(p + 0x1E); + if (Flags > 7) + return false; + FileHeadersOffset = Get32(p + 0x10); + if (FileHeadersOffset != 0 && FileHeadersOffset > Size) + return false; + VersionMinor = p[0x18]; + VersionMajor = p[0x19]; + NumFolders = Get16(p + 0x1A); + NumFiles = Get16(p + 0x1C); + return true; +} + +HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) { - IInStream *stream = db.Stream; + IsArc = false; + ErrorInNames = false; + UnexpectedEnd = false; + HeaderError = false; + db.Clear(); - RINOK(stream->Seek(0, STREAM_SEEK_SET, &db.StartPosition)); - - RINOK(FindSignatureInStream(stream, NHeader::kMarker, NHeader::kMarkerSize, - searchHeaderSizeLimit, db.StartPosition)); - - RINOK(stream->Seek(db.StartPosition + NHeader::kMarkerSize, STREAM_SEEK_SET, NULL)); - if (!inBuffer.Create(1 << 17)) - return E_OUTOFMEMORY; - inBuffer.SetStream(stream); - inBuffer.Init(); - - CInArchiveInfo &ai = db.ArchiveInfo; - - ai.Size = Read32(); - if (Read32() != 0) - return S_FALSE; - ai.FileHeadersOffset = Read32(); - if (Read32() != 0) - return S_FALSE; - - ai.VersionMinor = Read8(); - ai.VersionMajor = Read8(); - ai.NumFolders = Read16(); - ai.NumFiles = Read16(); - ai.Flags = Read16(); - if (ai.Flags > 7) - return S_FALSE; - ai.SetID = Read16(); - ai.CabinetNumber = Read16(); + RINOK(db.Stream->Seek(0, STREAM_SEEK_CUR, &db.StartPosition)); + // UInt64 temp = db.StartPosition; - if (ai.ReserveBlockPresent()) + CByteBuffer buffer; + CInArcInfo &ai = db.ArcInfo; + UInt64 startInBuf = 0; + + CLimitedSequentialInStream *limitedStreamSpec = NULL; + CMyComPtr<ISequentialInStream> limitedStream; + + // for (int iii = 0; iii < 10000; iii++) { - ai.PerCabinetAreaSize = Read16(); - ai.PerFolderAreaSize = Read8(); - ai.PerDataBlockAreaSize = Read8(); + // db.StartPosition = temp; RINOK(db.Stream->Seek(db.StartPosition, STREAM_SEEK_SET, NULL)); + + const UInt32 kMainHeaderSize = 32; + Byte header[kMainHeaderSize]; + const UInt32 kBufSize = 1 << 15; + RINOK(ReadStream_FALSE(db.Stream, header, kMainHeaderSize)); + if (memcmp(header, NHeader::kMarker, NHeader::kMarkerSize) == 0 && ai.Parse(header)) + { + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStream = limitedStreamSpec; + limitedStreamSpec->SetStream(db.Stream); + limitedStreamSpec->Init(ai.Size - NHeader::kMarkerSize); + buffer.Alloc(kBufSize); + memcpy(buffer, header, kMainHeaderSize); + UInt32 numProcessedBytes; + RINOK(limitedStream->Read(buffer + kMainHeaderSize, kBufSize - kMainHeaderSize, &numProcessedBytes)); + _inBuffer.SetBuf(buffer, (UInt32)kBufSize, kMainHeaderSize + numProcessedBytes, kMainHeaderSize); + } + else + { + if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0) + return S_FALSE; + + CSignatureFinder finder; + + finder.Stream = db.Stream; + finder.Signature = NHeader::kMarker; + finder.SignatureSize = NHeader::kMarkerSize; + finder.SearchLimit = searchHeaderSizeLimit; - Skip(ai.PerCabinetAreaSize); + buffer.Alloc(finder.GetTotalCapacity(kBufSize, kMainHeaderSize)); + finder.Buf = buffer; + + memcpy(buffer, header, kMainHeaderSize); + finder.Processed = db.StartPosition; + finder.End = kMainHeaderSize; + finder.Pos = 1; + + for (;;) + { + RINOK(finder.Find()); + if (ai.Parse(finder.Buf + finder.Pos)) + { + db.StartPosition = finder.Processed + finder.Pos; + limitedStreamSpec = new CLimitedSequentialInStream; + limitedStreamSpec->SetStream(db.Stream); + limitedStream = limitedStreamSpec; + UInt32 remInFinder = finder.End - finder.Pos; + if (ai.Size <= remInFinder) + { + limitedStreamSpec->Init(0); + finder.End = finder.Pos + ai.Size; + } + else + limitedStreamSpec->Init(ai.Size - remInFinder); + + startInBuf = finder.Pos; + _inBuffer.SetBuf(buffer, (UInt32)kBufSize, finder.End, finder.Pos + kMainHeaderSize); + break; + } + finder.Pos++; + } + } } + + IsArc = true; + _inBuffer.SetStream(limitedStream); + if (_tempBuf.Size() == 0) + _tempBuf.Alloc(1 << 12); + + Byte p[16]; + unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0); + Read(p, nextSize); + ai.SetID = Get16(p); + ai.CabinetNumber = Get16(p + 2); + + if (ai.ReserveBlockPresent()) { - if (ai.IsTherePrev()) - ReadOtherArchive(ai.PrevArc); - if (ai.IsThereNext()) - ReadOtherArchive(ai.NextArc); + ai.PerCabinet_AreaSize = Get16(p + 4); + ai.PerFolder_AreaSize = p[6]; + ai.PerDataBlock_AreaSize = p[7]; + Skip(ai.PerCabinet_AreaSize); } + + if (ai.IsTherePrev()) ReadOtherArc(ai.PrevArc); + if (ai.IsThereNext()) ReadOtherArc(ai.NextArc); - int i; + UInt32 i; + db.Folders.ClearAndReserve(ai.NumFolders); for (i = 0; i < ai.NumFolders; i++) { + Read(p, 8); CFolder folder; - - folder.DataStart = Read32(); - folder.NumDataBlocks = Read16(); - folder.CompressionTypeMajor = Read8(); - folder.CompressionTypeMinor = Read8(); - - Skip(ai.PerFolderAreaSize); - db.Folders.Add(folder); + folder.DataStart = Get32(p); + folder.NumDataBlocks = Get16(p + 4); + folder.MethodMajor = p[6]; + folder.MethodMinor = p[7]; + Skip(ai.PerFolder_AreaSize); + db.Folders.AddInReserved(folder); } - RINOK(stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); + // for (int iii = 0; iii < 10000; iii++) { + + if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset) + { + // printf("\n!!! Seek Error !!!!\n"); + // fflush(stdout); + RINOK(db.Stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); + limitedStreamSpec->Init(ai.Size - ai.FileHeadersOffset); + _inBuffer.Init(); + } - inBuffer.SetStream(stream); - inBuffer.Init(); + db.Items.ClearAndReserve(ai.NumFiles); for (i = 0; i < ai.NumFiles; i++) { - CItem item; - item.Size = Read32(); - item.Offset = Read32(); - item.FolderIndex = Read16(); - UInt16 pureDate = Read16(); - UInt16 pureTime = Read16(); - item.Time = ((UInt32(pureDate) << 16)) | pureTime; - item.Attributes = Read16(); - item.Name = SafeReadName(); - int folderIndex = item.GetFolderIndex(db.Folders.Size()); - if (folderIndex >= db.Folders.Size()) + Read(p, 16); + CItem &item = db.Items.AddNewInReserved(); + item.Size = Get32(p); + item.Offset = Get32(p + 4); + item.FolderIndex = Get16(p + 8); + UInt16 pureDate = Get16(p + 10); + UInt16 pureTime = Get16(p + 12); + item.Time = (((UInt32)pureDate << 16)) | pureTime; + item.Attributes = Get16(p + 14); + + ReadName(item.Name); + if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size()) + { + HeaderError = true; return S_FALSE; - db.Items.Add(item); + } } + + // } + return S_OK; } +HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit) +{ + try + { + return Open2(db, searchHeaderSizeLimit); + } + catch(const CInBufferException &e) { return e.ErrorCode; } + catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; } +} + + + #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) @@ -161,10 +360,8 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) const CItem &item2 = db2.Items[p2->ItemIndex];; bool isDir1 = item1.IsDir(); bool isDir2 = item2.IsDir(); - if (isDir1 && !isDir2) - return -1; - if (isDir2 && !isDir1) - return 1; + if (isDir1 && !isDir2) return -1; + if (isDir2 && !isDir1) return 1; int f1 = mvDb.GetFolderIndex(p1); int f2 = mvDb.GetFolderIndex(p2); RINOZ(MyCompare(f1, f2)); @@ -174,7 +371,7 @@ static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) return MyCompare(p1->ItemIndex, p2->ItemIndex); } -bool CMvDatabaseEx::AreItemsEqual(int i1, int i2) +bool CMvDatabaseEx::AreItemsEqual(unsigned i1, unsigned i2) { const CMvItem *p1 = &Items[i1]; const CMvItem *p2 = &Items[i2]; @@ -182,10 +379,10 @@ bool CMvDatabaseEx::AreItemsEqual(int i1, int i2) const CDatabaseEx &db2 = Volumes[p2->VolumeIndex]; const CItem &item1 = db1.Items[p1->ItemIndex]; const CItem &item2 = db2.Items[p2->ItemIndex];; - return GetFolderIndex(p1) == GetFolderIndex(p2) && - item1.Offset == item2.Offset && - item1.Size == item2.Size && - item1.Name == item2.Name; + return GetFolderIndex(p1) == GetFolderIndex(p2) + && item1.Offset == item2.Offset + && item1.Size == item2.Size + && item1.Name == item2.Name; } void CMvDatabaseEx::FillSortAndShrink() @@ -194,7 +391,7 @@ void CMvDatabaseEx::FillSortAndShrink() StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); int offset = 0; - for (int v = 0; v < Volumes.Size(); v++) + FOR_VECTOR (v, Volumes) { const CDatabaseEx &db = Volumes[v]; int curOffset = offset; @@ -205,32 +402,35 @@ void CMvDatabaseEx::FillSortAndShrink() CMvItem mvItem; mvItem.VolumeIndex = v; - for (int i = 0 ; i < db.Items.Size(); i++) + FOR_VECTOR (i, db.Items) { mvItem.ItemIndex = i; Items.Add(mvItem); } } - Items.Sort(CompareMvItems, (void *)this); - int j = 1; - int i; - for (i = 1; i < Items.Size(); i++) - if (!AreItemsEqual(i, i -1)) - Items[j++] = Items[i]; - Items.DeleteFrom(j); + if (Items.Size() > 1) + { + Items.Sort(CompareMvItems, (void *)this); + unsigned j = 1; + unsigned i = 1; + for (; i < Items.Size(); i++) + if (!AreItemsEqual(i, i - 1)) + Items[j++] = Items[i]; + Items.DeleteFrom(j); + } - for (i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) { int folderIndex = GetFolderIndex(&Items[i]); - if (folderIndex >= FolderStartFileIndex.Size()) + if (folderIndex >= (int)FolderStartFileIndex.Size()) FolderStartFileIndex.Add(i); } } bool CMvDatabaseEx::Check() { - for (int v = 1; v < Volumes.Size(); v++) + for (unsigned v = 1; v < Volumes.Size(); v++) { const CDatabaseEx &db1 = Volumes[v]; if (db1.IsTherePrevFolder()) @@ -240,19 +440,19 @@ bool CMvDatabaseEx::Check() return false; const CFolder &f0 = db0.Folders.Back(); const CFolder &f1 = db1.Folders.Front(); - if (f0.CompressionTypeMajor != f1.CompressionTypeMajor || - f0.CompressionTypeMinor != f1.CompressionTypeMinor) + if (f0.MethodMajor != f1.MethodMajor || + f0.MethodMinor != f1.MethodMinor) return false; } } UInt32 beginPos = 0; UInt64 endPos = 0; int prevFolder = -2; - for (int i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) { const CMvItem &mvItem = Items[i]; int fIndex = GetFolderIndex(&mvItem); - if (fIndex >= FolderStartFileIndex.Size()) + if (fIndex >= (int)FolderStartFileIndex.Size()) return false; const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; if (item.IsDir()) diff --git a/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h index 1e9b188b..4fdab77b 100755..100644 --- a/CPP/7zip/Archive/Cab/CabIn.h +++ b/CPP/7zip/Archive/Cab/CabIn.h @@ -3,96 +3,88 @@ #ifndef __ARCHIVE_CAB_IN_H #define __ARCHIVE_CAB_IN_H -#include "../../IStream.h" +#include "../../../Common/MyBuffer.h" +#include "../../../Common/MyCom.h" + #include "../../Common/InBuffer.h" -#include "CabHeader.h" + #include "CabItem.h" namespace NArchive { namespace NCab { -class CInArchiveException -{ -public: - enum CCauseType - { - kUnexpectedEndOfArchive = 0, - kIncorrectArchive, - kUnsupported - } Cause; - CInArchiveException(CCauseType cause) : Cause(cause) {} -}; - -struct COtherArchive +struct COtherArc { AString FileName; AString DiskName; }; -struct CArchiveInfo +struct CArchInfo { - Byte VersionMinor; /* cabinet file format version, minor */ - Byte VersionMajor; /* cabinet file format version, major */ - UInt16 NumFolders; /* number of CFFOLDER entries in this cabinet */ - UInt16 NumFiles; /* number of CFFILE entries in this cabinet */ - UInt16 Flags; /* cabinet file option indicators */ - UInt16 SetID; /* must be the same for all cabinets in a set */ - UInt16 CabinetNumber; /* number of this cabinet file in a set */ - - bool ReserveBlockPresent() const { return (Flags & NHeader::NArchive::NFlags::kReservePresent) != 0; } - - bool IsTherePrev() const { return (Flags & NHeader::NArchive::NFlags::kPrevCabinet) != 0; } - bool IsThereNext() const { return (Flags & NHeader::NArchive::NFlags::kNextCabinet) != 0; } - - UInt16 PerCabinetAreaSize; // (optional) size of per-cabinet reserved area - Byte PerFolderAreaSize; // (optional) size of per-folder reserved area - Byte PerDataBlockAreaSize; // (optional) size of per-datablock reserved area - - Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlockAreaSize : 0); } - - COtherArchive PrevArc; - COtherArchive NextArc; - - CArchiveInfo() + Byte VersionMinor; // cabinet file format version, minor + Byte VersionMajor; // cabinet file format version, major + UInt32 NumFolders; // number of CFFOLDER entries in this cabinet + UInt32 NumFiles; // number of CFFILE entries in this cabinet + UInt32 Flags; // cabinet file option indicators + UInt32 SetID; // must be the same for all cabinets in a set + UInt32 CabinetNumber; // number of this cabinet file in a set + + UInt16 PerCabinet_AreaSize; // (optional) size of per-cabinet reserved area + Byte PerFolder_AreaSize; // (optional) size of per-folder reserved area + Byte PerDataBlock_AreaSize; // (optional) size of per-datablock reserved area + + COtherArc PrevArc; // prev link can skip some volumes !!! + COtherArc NextArc; + + bool ReserveBlockPresent() const { return (Flags & NHeader::NArcFlags::kReservePresent) != 0; } + bool IsTherePrev() const { return (Flags & NHeader::NArcFlags::kPrevCabinet) != 0; } + bool IsThereNext() const { return (Flags & NHeader::NArcFlags::kNextCabinet) != 0; } + Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlock_AreaSize : 0); } + + CArchInfo() { Clear(); } void Clear() { - PerCabinetAreaSize = 0; - PerFolderAreaSize = 0; - PerDataBlockAreaSize = 0; + PerCabinet_AreaSize = 0; + PerFolder_AreaSize = 0; + PerDataBlock_AreaSize = 0; } }; -struct CInArchiveInfo: public CArchiveInfo +struct CInArcInfo: public CArchInfo { - UInt32 Size; /* size of this cabinet file in bytes */ + UInt32 Size; // size of this cabinet file in bytes UInt32 FileHeadersOffset; // offset of the first CFFILE entry + + bool Parse(const Byte *p); }; struct CDatabase { - UInt64 StartPosition; - CInArchiveInfo ArchiveInfo; - CObjectVector<CFolder> Folders; + CRecordVector<CFolder> Folders; CObjectVector<CItem> Items; + UInt64 StartPosition; + CInArcInfo ArcInfo; void Clear() { - ArchiveInfo.Clear(); + ArcInfo.Clear(); Folders.Clear(); Items.Clear(); } + bool IsTherePrevFolder() const { - for (int i = 0; i < Items.Size(); i++) + FOR_VECTOR (i, Items) if (Items[i].ContinuedFromPrev()) return true; return false; } + int GetNumberOfNewFolders() const { int res = Folders.Size(); @@ -100,8 +92,6 @@ struct CDatabase res--; return res; } - UInt32 GetFileOffset(int index) const { return Items[index].Offset; } - UInt32 GetFileSize(int index) const { return Items[index].Size; } }; struct CDatabaseEx: public CDatabase @@ -111,25 +101,27 @@ struct CDatabaseEx: public CDatabase struct CMvItem { - int VolumeIndex; - int ItemIndex; + unsigned VolumeIndex; + unsigned ItemIndex; }; class CMvDatabaseEx { - bool AreItemsEqual(int i1, int i2); + bool AreItemsEqual(unsigned i1, unsigned i2); + public: CObjectVector<CDatabaseEx> Volumes; CRecordVector<CMvItem> Items; - CRecordVector<int> StartFolderOfVol; - CRecordVector<int> FolderStartFileIndex; - + CRecordVector<int> StartFolderOfVol; // can be negative + CRecordVector<unsigned> FolderStartFileIndex; + int GetFolderIndex(const CMvItem *mvi) const { const CDatabaseEx &db = Volumes[mvi->VolumeIndex]; return StartFolderOfVol[mvi->VolumeIndex] + db.Items[mvi->ItemIndex].GetFolderIndex(db.Folders.Size()); } + void Clear() { Volumes.Clear(); @@ -137,23 +129,30 @@ public: StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); } + void FillSortAndShrink(); bool Check(); }; + class CInArchive { - CInBuffer inBuffer; + CInBufferBase _inBuffer; + CByteBuffer _tempBuf; - Byte Read8(); - UInt16 Read16(); - UInt32 Read32(); - AString SafeReadName(); - void Skip(UInt32 size); - void ReadOtherArchive(COtherArchive &oa); + void Skip(unsigned size); + void Read(Byte *data, unsigned size); + void ReadName(AString &s); + void ReadOtherArc(COtherArc &oa); + HRESULT Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); public: - HRESULT Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db); + bool IsArc; + bool ErrorInNames; + bool UnexpectedEnd; + bool HeaderError; + + HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); }; }} diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h index 63a1e856..eda62bda 100755..100644 --- a/CPP/7zip/Archive/Cab/CabItem.h +++ b/CPP/7zip/Archive/Cab/CabItem.h @@ -3,20 +3,23 @@ #ifndef __ARCHIVE_CAB_ITEM_H #define __ARCHIVE_CAB_ITEM_H -#include "Common/Types.h" -#include "Common/MyString.h" +#include "../../../Common/MyString.h" + #include "CabHeader.h" namespace NArchive { namespace NCab { +const unsigned kNumMethodsMax = 16; + struct CFolder { UInt32 DataStart; // offset of the first CFDATA block in this folder UInt16 NumDataBlocks; // number of CFDATA blocks in this folder - Byte CompressionTypeMajor; - Byte CompressionTypeMinor; - Byte GetCompressionMethod() const { return (Byte)(CompressionTypeMajor & 0xF); } + Byte MethodMajor; + Byte MethodMinor; + + Byte GetMethod() const { return (Byte)(MethodMajor & 0xF); } }; struct CItem @@ -25,27 +28,27 @@ struct CItem UInt32 Offset; UInt32 Size; UInt32 Time; - UInt16 FolderIndex; + UInt32 FolderIndex; UInt16 Flags; UInt16 Attributes; UInt64 GetEndOffset() const { return (UInt64)Offset + Size; } - UInt32 GetWinAttributes() const { return (Attributes & ~NHeader::kFileNameIsUTFAttributeMask); } - bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUTFAttributeMask) != 0; } + UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; } + bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 0; } bool IsDir() const { return (Attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } bool ContinuedFromPrev() const { return - (FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev) || - (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext); + FolderIndex == NHeader::NFolderIndex::kContinuedFromPrev || + FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; } bool ContinuedToNext() const { return - (FolderIndex == NHeader::NFolderIndex::kContinuedToNext) || - (FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext); + FolderIndex == NHeader::NFolderIndex::kContinuedToNext || + FolderIndex == NHeader::NFolderIndex::kContinuedPrevAndNext; } int GetFolderIndex(int numFolders) const @@ -53,7 +56,7 @@ struct CItem if (ContinuedFromPrev()) return 0; if (ContinuedToNext()) - return (numFolders - 1); + return numFolders - 1; return FolderIndex; } }; diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp index 15fe4099..acad4c4a 100755..100644 --- a/CPP/7zip/Archive/Cab/CabRegister.cpp +++ b/CPP/7zip/Archive/Cab/CabRegister.cpp @@ -5,9 +5,19 @@ #include "../../Common/RegisterArc.h" #include "CabHandler.h" -static IInArchive *CreateArc() { return new NArchive::NCab::CHandler; } + +namespace NArchive { +namespace NCab { + +IMP_CreateArcIn static CArcInfo g_ArcInfo = - { L"Cab", L"cab", 0, 8, { 0x4D, 0x53, 0x43, 0x46 }, 4, false, CreateArc, 0 }; + { "Cab", "cab", 0, 8, + 8, { 'M', 'S', 'C', 'F', 0, 0, 0, 0 }, + 0, + NArcInfoFlags::kFindSignature, + CreateArc }; REGISTER_ARC(Cab) + +}} diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h index e7fb6986..2854ff3e 100755..100644 --- a/CPP/7zip/Archive/Cab/StdAfx.h +++ b/CPP/7zip/Archive/Cab/StdAfx.h @@ -3,6 +3,6 @@ #ifndef __STDAFX_H #define __STDAFX_H -#include "../../../Common/MyWindows.h" +#include "../../../Common/Common.h" #endif |