271 lines
6.0 KiB
C
271 lines
6.0 KiB
C
|
// Archive/ChmIn.h
|
||
|
|
||
|
#ifndef __ARCHIVE_CHM_IN_H
|
||
|
#define __ARCHIVE_CHM_IN_H
|
||
|
|
||
|
#include "../../../Common/MyBuffer.h"
|
||
|
#include "../../../Common/MyString.h"
|
||
|
|
||
|
#include "../../IStream.h"
|
||
|
|
||
|
#include "../../Common/InBuffer.h"
|
||
|
|
||
|
namespace NArchive {
|
||
|
namespace NChm {
|
||
|
|
||
|
struct CItem
|
||
|
{
|
||
|
UInt64 Section;
|
||
|
UInt64 Offset;
|
||
|
UInt64 Size;
|
||
|
AString Name;
|
||
|
|
||
|
bool IsFormatRelatedItem() const
|
||
|
{
|
||
|
if (Name.Len() < 2)
|
||
|
return false;
|
||
|
return Name[0] == ':' && Name[1] == ':';
|
||
|
}
|
||
|
|
||
|
bool IsUserItem() const
|
||
|
{
|
||
|
if (Name.Len() < 2)
|
||
|
return false;
|
||
|
return Name[0] == '/';
|
||
|
}
|
||
|
|
||
|
bool IsDir() const
|
||
|
{
|
||
|
if (Name.IsEmpty())
|
||
|
return false;
|
||
|
return (Name.Back() == '/');
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
struct CDatabase
|
||
|
{
|
||
|
UInt64 StartPosition;
|
||
|
UInt64 ContentOffset;
|
||
|
CObjectVector<CItem> Items;
|
||
|
AString NewFormatString;
|
||
|
bool Help2Format;
|
||
|
bool NewFormat;
|
||
|
UInt64 PhySize;
|
||
|
|
||
|
void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; }
|
||
|
|
||
|
int FindItem(const AString &name) const
|
||
|
{
|
||
|
FOR_VECTOR (i, Items)
|
||
|
if (Items[i].Name == name)
|
||
|
return i;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
void Clear()
|
||
|
{
|
||
|
NewFormat = false;
|
||
|
NewFormatString.Empty();
|
||
|
Help2Format = false;
|
||
|
Items.Clear();
|
||
|
StartPosition = 0;
|
||
|
PhySize = 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
const UInt32 kBlockSize = 1 << 15;
|
||
|
|
||
|
struct CResetTable
|
||
|
{
|
||
|
UInt64 UncompressedSize;
|
||
|
UInt64 CompressedSize;
|
||
|
// unsigned BlockSizeBits;
|
||
|
CRecordVector<UInt64> ResetOffsets;
|
||
|
|
||
|
bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
|
||
|
{
|
||
|
if (blockIndex >= ResetOffsets.Size())
|
||
|
return false;
|
||
|
UInt64 startPos = ResetOffsets[(unsigned)blockIndex];
|
||
|
if (blockIndex + numBlocks >= ResetOffsets.Size())
|
||
|
size = CompressedSize - startPos;
|
||
|
else
|
||
|
size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
|
||
|
{
|
||
|
return GetCompressedSizeOfBlocks(blockIndex, 1, size);
|
||
|
}
|
||
|
|
||
|
UInt64 GetNumBlocks(UInt64 size) const
|
||
|
{
|
||
|
return (size + kBlockSize - 1) / kBlockSize;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
struct CLzxInfo
|
||
|
{
|
||
|
UInt32 Version;
|
||
|
|
||
|
unsigned ResetIntervalBits;
|
||
|
unsigned WindowSizeBits;
|
||
|
UInt32 CacheSize;
|
||
|
|
||
|
CResetTable ResetTable;
|
||
|
|
||
|
unsigned GetNumDictBits() const
|
||
|
{
|
||
|
if (Version == 2 || Version == 3)
|
||
|
return 15 + WindowSizeBits;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UInt64 GetFolderSize() const { return kBlockSize << ResetIntervalBits; }
|
||
|
UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); }
|
||
|
UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); }
|
||
|
UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; }
|
||
|
|
||
|
bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const
|
||
|
{
|
||
|
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
|
||
|
if (blockIndex >= ResetTable.ResetOffsets.Size())
|
||
|
return false;
|
||
|
offset = ResetTable.ResetOffsets[(unsigned)blockIndex];
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
|
||
|
{
|
||
|
UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
|
||
|
return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
struct CMethodInfo
|
||
|
{
|
||
|
GUID Guid;
|
||
|
CByteBuffer ControlData;
|
||
|
CLzxInfo LzxInfo;
|
||
|
|
||
|
bool IsLzx() const;
|
||
|
bool IsDes() const;
|
||
|
AString GetGuidString() const;
|
||
|
UString GetName() const;
|
||
|
};
|
||
|
|
||
|
|
||
|
struct CSectionInfo
|
||
|
{
|
||
|
UInt64 Offset;
|
||
|
UInt64 CompressedSize;
|
||
|
UInt64 UncompressedSize;
|
||
|
|
||
|
AString Name;
|
||
|
CObjectVector<CMethodInfo> Methods;
|
||
|
|
||
|
bool IsLzx() const;
|
||
|
UString GetMethodName() const;
|
||
|
};
|
||
|
|
||
|
class CFilesDatabase: public CDatabase
|
||
|
{
|
||
|
public:
|
||
|
bool LowLevel;
|
||
|
CUIntVector Indices;
|
||
|
CObjectVector<CSectionInfo> Sections;
|
||
|
|
||
|
UInt64 GetFileSize(unsigned fileIndex) const { return Items[Indices[fileIndex]].Size; }
|
||
|
UInt64 GetFileOffset(unsigned fileIndex) const { return Items[Indices[fileIndex]].Offset; }
|
||
|
|
||
|
UInt64 GetFolder(unsigned fileIndex) const
|
||
|
{
|
||
|
const CItem &item = Items[Indices[fileIndex]];
|
||
|
if (item.Section < Sections.Size())
|
||
|
{
|
||
|
const CSectionInfo §ion = Sections[(unsigned)item.Section];
|
||
|
if (section.IsLzx())
|
||
|
return section.Methods[0].LzxInfo.GetFolder(item.Offset);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
UInt64 GetLastFolder(unsigned fileIndex) const
|
||
|
{
|
||
|
const CItem &item = Items[Indices[fileIndex]];
|
||
|
if (item.Section < Sections.Size())
|
||
|
{
|
||
|
const CSectionInfo §ion = Sections[(unsigned)item.Section];
|
||
|
if (section.IsLzx())
|
||
|
return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void HighLevelClear()
|
||
|
{
|
||
|
LowLevel = true;
|
||
|
Indices.Clear();
|
||
|
Sections.Clear();
|
||
|
}
|
||
|
|
||
|
void Clear()
|
||
|
{
|
||
|
CDatabase::Clear();
|
||
|
HighLevelClear();
|
||
|
}
|
||
|
|
||
|
void SetIndices();
|
||
|
void Sort();
|
||
|
bool Check();
|
||
|
bool CheckSectionRefs();
|
||
|
};
|
||
|
|
||
|
|
||
|
class CInArchive
|
||
|
{
|
||
|
CMyComPtr<ISequentialInStream> m_InStreamRef;
|
||
|
::CInBuffer _inBuffer;
|
||
|
UInt64 _chunkSize;
|
||
|
bool _help2;
|
||
|
|
||
|
Byte ReadByte();
|
||
|
void ReadBytes(Byte *data, UInt32 size);
|
||
|
void Skip(size_t size);
|
||
|
UInt16 ReadUInt16();
|
||
|
UInt32 ReadUInt32();
|
||
|
UInt64 ReadUInt64();
|
||
|
UInt64 ReadEncInt();
|
||
|
void ReadString(unsigned size, AString &s);
|
||
|
void ReadUString(unsigned size, UString &s);
|
||
|
void ReadGUID(GUID &g);
|
||
|
|
||
|
HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size);
|
||
|
|
||
|
HRESULT ReadDirEntry(CDatabase &database);
|
||
|
HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name);
|
||
|
|
||
|
public:
|
||
|
bool IsArc;
|
||
|
bool HeadersError;
|
||
|
bool UnexpectedEnd;
|
||
|
bool UnsupportedFeature;
|
||
|
|
||
|
CInArchive(bool help2) { _help2 = help2; }
|
||
|
|
||
|
HRESULT OpenChm(IInStream *inStream, CDatabase &database);
|
||
|
HRESULT OpenHelp2(IInStream *inStream, CDatabase &database);
|
||
|
HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database);
|
||
|
HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
|
||
|
HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database);
|
||
|
};
|
||
|
|
||
|
}}
|
||
|
|
||
|
#endif
|