Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/kornelski/7z.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Pavlov <ipavlov@users.sourceforge.net>2014-11-23 03:00:00 +0300
committerKornel LesiƄski <kornel@geekhood.net>2016-05-28 02:16:51 +0300
commitf08f4dcc3c02464c17753b3feafcfe5243b9e236 (patch)
treeb0e1b15bc5368d92dff422e8ec0818564a2b00b8 /CPP/7zip/Archive/Cab/CabIn.cpp
parent83f8ddcc5b2161e1e3c49666265257fca8aeb12c (diff)
9.349.34
Diffstat (limited to 'CPP/7zip/Archive/Cab/CabIn.cpp')
-rw-r--r--[-rwxr-xr-x]CPP/7zip/Archive/Cab/CabIn.cpp446
1 files changed, 323 insertions, 123 deletions
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())