// Archive/CabIn.h #ifndef __ARCHIVE_CAB_IN_H #define __ARCHIVE_CAB_IN_H #include "../../IStream.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 { AString FileName; AString DiskName; }; struct CArchiveInfo { 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() { Clear(); } void Clear() { PerCabinetAreaSize = 0; PerFolderAreaSize = 0; PerDataBlockAreaSize = 0; } }; struct CInArchiveInfo: public CArchiveInfo { UInt32 Size; /* size of this cabinet file in bytes */ UInt32 FileHeadersOffset; // offset of the first CFFILE entry }; struct CDatabase { UInt64 StartPosition; CInArchiveInfo ArchiveInfo; CObjectVector Folders; CObjectVector Items; void Clear() { ArchiveInfo.Clear(); Folders.Clear(); Items.Clear(); } bool IsTherePrevFolder() const { for (int i = 0; i < Items.Size(); i++) if (Items[i].ContinuedFromPrev()) return true; return false; } int GetNumberOfNewFolders() const { int res = Folders.Size(); if (IsTherePrevFolder()) 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 { CMyComPtr Stream; }; struct CMvItem { int VolumeIndex; int ItemIndex; }; class CMvDatabaseEx { bool AreItemsEqual(int i1, int i2); public: CObjectVector Volumes; CRecordVector Items; CRecordVector StartFolderOfVol; CRecordVector 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(); Items.Clear(); StartFolderOfVol.Clear(); FolderStartFileIndex.Clear(); } void FillSortAndShrink(); bool Check(); }; class CInArchive { CInBuffer inBuffer; Byte Read8(); UInt16 Read16(); UInt32 Read32(); AString SafeReadName(); void Skip(UInt32 size); void ReadOtherArchive(COtherArchive &oa); public: HRESULT Open(const UInt64 *searchHeaderSizeLimit, CDatabaseEx &db); }; }} #endif