// Archive/CabIn.h #ifndef __ARCHIVE_CAB_IN_H #define __ARCHIVE_CAB_IN_H #include "../../../Common/MyBuffer.h" #include "../../../Common/MyCom.h" #include "../../Common/InBuffer.h" #include "CabItem.h" namespace NArchive { namespace NCab { struct COtherArc { AString FileName; AString DiskName; void Clear() { FileName.Empty(); DiskName.Empty(); } }; struct CArchInfo { 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() { PerCabinet_AreaSize = 0; PerFolder_AreaSize = 0; PerDataBlock_AreaSize = 0; } void Clear() { PerCabinet_AreaSize = 0; PerFolder_AreaSize = 0; PerDataBlock_AreaSize = 0; PrevArc.Clear(); NextArc.Clear(); } }; struct CInArcInfo: public CArchInfo { UInt32 Size; // size of this cabinet file in bytes UInt32 FileHeadersOffset; // offset of the first CFFILE entry bool Parse(const Byte *p); }; struct CDatabase { CRecordVector Folders; CObjectVector Items; UInt64 StartPosition; CInArcInfo ArcInfo; void Clear() { ArcInfo.Clear(); Folders.Clear(); Items.Clear(); } bool IsTherePrevFolder() const { FOR_VECTOR (i, Items) if (Items[i].ContinuedFromPrev()) return true; return false; } int GetNumberOfNewFolders() const { int res = Folders.Size(); if (IsTherePrevFolder()) res--; return res; } }; struct CDatabaseEx: public CDatabase { CMyComPtr Stream; }; struct CMvItem { unsigned VolumeIndex; unsigned ItemIndex; }; class CMvDatabaseEx { bool AreItemsEqual(unsigned i1, unsigned i2); public: CObjectVector Volumes; CRecordVector Items; CRecordVector StartFolderOfVol; // can be negative 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 { CInBufferBase _inBuffer; CByteBuffer _tempBuf; 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: bool IsArc; bool ErrorInNames; bool UnexpectedEnd; bool HeaderError; HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit); }; }} #endif