diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp new file mode 100644 index 000000000..c0bffa2d2 --- /dev/null +++ b/src/libs/7zip/win/CPP/7zip/Archive/Cab/CabIn.cpp @@ -0,0 +1,272 @@ +// Archive/CabIn.cpp + +#include "StdAfx.h" + +#include "../Common/FindSignature.h" + +#include "CabIn.h" + +namespace NArchive { +namespace NCab { + +Byte CInArchive::Read8() +{ + Byte b; + if (!inBuffer.ReadByte(b)) + throw CInArchiveException(CInArchiveException::kUnsupported); + return b; +} + +UInt16 CInArchive::Read16() +{ + UInt16 value = 0; + for (int i = 0; i < 2; i++) + { + Byte b = Read8(); + value |= (UInt16(b) << (8 * i)); + } + return value; +} + +UInt32 CInArchive::Read32() +{ + UInt32 value = 0; + for (int i = 0; i < 4; i++) + { + Byte b = Read8(); + value |= (UInt32(b) << (8 * i)); + } + return value; +} + +AString CInArchive::SafeReadName() +{ + AString name; + for (;;) + { + Byte b = Read8(); + if (b == 0) + return name; + name += (char)b; + } +} + +void CInArchive::ReadOtherArchive(COtherArchive &oa) +{ + oa.FileName = SafeReadName(); + oa.DiskName = SafeReadName(); +} + +void CInArchive::Skip(UInt32 size) +{ + while (size-- != 0) + Read8(); +} + +HRESULT CInArchive::Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db) +{ + IInStream *stream = db.Stream; + 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(); + + if (ai.ReserveBlockPresent()) + { + ai.PerCabinetAreaSize = Read16(); + ai.PerFolderAreaSize = Read8(); + ai.PerDataBlockAreaSize = Read8(); + + Skip(ai.PerCabinetAreaSize); + } + + { + if (ai.IsTherePrev()) + ReadOtherArchive(ai.PrevArc); + if (ai.IsThereNext()) + ReadOtherArchive(ai.NextArc); + } + + int i; + for (i = 0; i < ai.NumFolders; i++) + { + CFolder folder; + + folder.DataStart = Read32(); + folder.NumDataBlocks = Read16(); + folder.CompressionTypeMajor = Read8(); + folder.CompressionTypeMinor = Read8(); + + Skip(ai.PerFolderAreaSize); + db.Folders.Add(folder); + } + + RINOK(stream->Seek(db.StartPosition + ai.FileHeadersOffset, STREAM_SEEK_SET, NULL)); + + inBuffer.SetStream(stream); + inBuffer.Init(); + 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()) + return S_FALSE; + db.Items.Add(item); + } + return S_OK; +} + +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +static int CompareMvItems(const CMvItem *p1, const CMvItem *p2, void *param) +{ + const CMvDatabaseEx &mvDb = *(const CMvDatabaseEx *)param; + const CDatabaseEx &db1 = mvDb.Volumes[p1->VolumeIndex]; + const CDatabaseEx &db2 = mvDb.Volumes[p2->VolumeIndex]; + const CItem &item1 = db1.Items[p1->ItemIndex]; + 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; + int f1 = mvDb.GetFolderIndex(p1); + int f2 = mvDb.GetFolderIndex(p2); + RINOZ(MyCompare(f1, f2)); + RINOZ(MyCompare(item1.Offset, item2.Offset)); + RINOZ(MyCompare(item1.Size, item2.Size)); + RINOZ(MyCompare(p1->VolumeIndex, p2->VolumeIndex)); + return MyCompare(p1->ItemIndex, p2->ItemIndex); +} + +bool CMvDatabaseEx::AreItemsEqual(int i1, int i2) +{ + const CMvItem *p1 = &Items[i1]; + const CMvItem *p2 = &Items[i2]; + const CDatabaseEx &db1 = Volumes[p1->VolumeIndex]; + 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; +} + +void CMvDatabaseEx::FillSortAndShrink() +{ + Items.Clear(); + StartFolderOfVol.Clear(); + FolderStartFileIndex.Clear(); + int offset = 0; + for (int v = 0; v < Volumes.Size(); v++) + { + const CDatabaseEx &db = Volumes[v]; + int curOffset = offset; + if (db.IsTherePrevFolder()) + curOffset--; + StartFolderOfVol.Add(curOffset); + offset += db.GetNumberOfNewFolders(); + + CMvItem mvItem; + mvItem.VolumeIndex = v; + for (int i = 0 ; i < db.Items.Size(); i++) + { + 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); + + for (i = 0; i < Items.Size(); i++) + { + int folderIndex = GetFolderIndex(&Items[i]); + if (folderIndex >= FolderStartFileIndex.Size()) + FolderStartFileIndex.Add(i); + } +} + +bool CMvDatabaseEx::Check() +{ + for (int v = 1; v < Volumes.Size(); v++) + { + const CDatabaseEx &db1 = Volumes[v]; + if (db1.IsTherePrevFolder()) + { + const CDatabaseEx &db0 = Volumes[v - 1]; + if (db0.Folders.IsEmpty() || db1.Folders.IsEmpty()) + return false; + const CFolder &f0 = db0.Folders.Back(); + const CFolder &f1 = db1.Folders.Front(); + if (f0.CompressionTypeMajor != f1.CompressionTypeMajor || + f0.CompressionTypeMinor != f1.CompressionTypeMinor) + return false; + } + } + UInt32 beginPos = 0; + UInt64 endPos = 0; + int prevFolder = -2; + for (int i = 0; i < Items.Size(); i++) + { + const CMvItem &mvItem = Items[i]; + int fIndex = GetFolderIndex(&mvItem); + if (fIndex >= FolderStartFileIndex.Size()) + return false; + const CItem &item = Volumes[mvItem.VolumeIndex].Items[mvItem.ItemIndex]; + if (item.IsDir()) + continue; + int folderIndex = GetFolderIndex(&mvItem); + if (folderIndex != prevFolder) + prevFolder = folderIndex; + else if (item.Offset < endPos && + (item.Offset != beginPos || item.GetEndOffset() != endPos)) + return false; + beginPos = item.Offset; + endPos = item.GetEndOffset(); + } + return true; +} + +}} |