1 // Archive/ChmIn.h 2 3 #ifndef __ARCHIVE_CHM_IN_H 4 #define __ARCHIVE_CHM_IN_H 5 6 #include "../../../Common/MyBuffer.h" 7 #include "../../../Common/MyString.h" 8 9 #include "../../IStream.h" 10 11 #include "../../Common/InBuffer.h" 12 13 namespace NArchive { 14 namespace NChm { 15 16 struct CItem 17 { 18 UInt64 Section; 19 UInt64 Offset; 20 UInt64 Size; 21 AString Name; 22 IsFormatRelatedItemCItem23 bool IsFormatRelatedItem() const 24 { 25 if (Name.Len() < 2) 26 return false; 27 return Name[0] == ':' && Name[1] == ':'; 28 } 29 IsUserItemCItem30 bool IsUserItem() const 31 { 32 if (Name.Len() < 2) 33 return false; 34 return Name[0] == '/'; 35 } 36 IsDirCItem37 bool IsDir() const 38 { 39 if (Name.IsEmpty()) 40 return false; 41 return (Name.Back() == '/'); 42 } 43 }; 44 45 46 struct CDatabase 47 { 48 UInt64 StartPosition; 49 UInt64 ContentOffset; 50 CObjectVector<CItem> Items; 51 AString NewFormatString; 52 bool Help2Format; 53 bool NewFormat; 54 UInt64 PhySize; 55 UpdatePhySizeCDatabase56 void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; } 57 FindItemCDatabase58 int FindItem(const AString &name) const 59 { 60 FOR_VECTOR (i, Items) 61 if (Items[i].Name == name) 62 return i; 63 return -1; 64 } 65 ClearCDatabase66 void Clear() 67 { 68 NewFormat = false; 69 NewFormatString.Empty(); 70 Help2Format = false; 71 Items.Clear(); 72 StartPosition = 0; 73 PhySize = 0; 74 } 75 }; 76 77 78 const UInt32 kBlockSize = 1 << 15; 79 80 struct CResetTable 81 { 82 UInt64 UncompressedSize; 83 UInt64 CompressedSize; 84 // unsigned BlockSizeBits; 85 CRecordVector<UInt64> ResetOffsets; 86 GetCompressedSizeOfBlocksCResetTable87 bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const 88 { 89 if (blockIndex >= ResetOffsets.Size()) 90 return false; 91 UInt64 startPos = ResetOffsets[(unsigned)blockIndex]; 92 if (blockIndex + numBlocks >= ResetOffsets.Size()) 93 size = CompressedSize - startPos; 94 else 95 size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos; 96 return true; 97 } 98 GetCompressedSizeOfBlockCResetTable99 bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const 100 { 101 return GetCompressedSizeOfBlocks(blockIndex, 1, size); 102 } 103 GetNumBlocksCResetTable104 UInt64 GetNumBlocks(UInt64 size) const 105 { 106 return (size + kBlockSize - 1) / kBlockSize; 107 } 108 }; 109 110 111 struct CLzxInfo 112 { 113 UInt32 Version; 114 115 unsigned ResetIntervalBits; 116 unsigned WindowSizeBits; 117 UInt32 CacheSize; 118 119 CResetTable ResetTable; 120 GetNumDictBitsCLzxInfo121 unsigned GetNumDictBits() const 122 { 123 if (Version == 2 || Version == 3) 124 return 15 + WindowSizeBits; 125 return 0; 126 } 127 GetFolderSizeCLzxInfo128 UInt64 GetFolderSize() const { return kBlockSize << ResetIntervalBits; } GetFolderCLzxInfo129 UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); } GetFolderPosCLzxInfo130 UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); } GetBlockIndexFromFolderIndexCLzxInfo131 UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; } 132 GetOffsetOfFolderCLzxInfo133 bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const 134 { 135 UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); 136 if (blockIndex >= ResetTable.ResetOffsets.Size()) 137 return false; 138 offset = ResetTable.ResetOffsets[(unsigned)blockIndex]; 139 return true; 140 } 141 GetCompressedSizeOfFolderCLzxInfo142 bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const 143 { 144 UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex); 145 return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size); 146 } 147 }; 148 149 150 struct CMethodInfo 151 { 152 Byte Guid[16]; 153 CByteBuffer ControlData; 154 CLzxInfo LzxInfo; 155 156 bool IsLzx() const; 157 bool IsDes() const; 158 AString GetGuidString() const; 159 AString GetName() const; 160 }; 161 162 163 struct CSectionInfo 164 { 165 UInt64 Offset; 166 UInt64 CompressedSize; 167 UInt64 UncompressedSize; 168 169 AString Name; 170 CObjectVector<CMethodInfo> Methods; 171 172 bool IsLzx() const; 173 UString GetMethodName() const; 174 }; 175 176 class CFilesDatabase: public CDatabase 177 { 178 public: 179 bool LowLevel; 180 CUIntVector Indices; 181 CObjectVector<CSectionInfo> Sections; 182 GetFileSize(unsigned fileIndex)183 UInt64 GetFileSize(unsigned fileIndex) const { return Items[Indices[fileIndex]].Size; } GetFileOffset(unsigned fileIndex)184 UInt64 GetFileOffset(unsigned fileIndex) const { return Items[Indices[fileIndex]].Offset; } 185 GetFolder(unsigned fileIndex)186 UInt64 GetFolder(unsigned fileIndex) const 187 { 188 const CItem &item = Items[Indices[fileIndex]]; 189 if (item.Section < Sections.Size()) 190 { 191 const CSectionInfo §ion = Sections[(unsigned)item.Section]; 192 if (section.IsLzx()) 193 return section.Methods[0].LzxInfo.GetFolder(item.Offset); 194 } 195 return 0; 196 } 197 GetLastFolder(unsigned fileIndex)198 UInt64 GetLastFolder(unsigned fileIndex) const 199 { 200 const CItem &item = Items[Indices[fileIndex]]; 201 if (item.Section < Sections.Size()) 202 { 203 const CSectionInfo §ion = Sections[(unsigned)item.Section]; 204 if (section.IsLzx()) 205 return section.Methods[0].LzxInfo.GetFolder(item.Offset + item.Size - 1); 206 } 207 return 0; 208 } 209 HighLevelClear()210 void HighLevelClear() 211 { 212 LowLevel = true; 213 Indices.Clear(); 214 Sections.Clear(); 215 } 216 Clear()217 void Clear() 218 { 219 CDatabase::Clear(); 220 HighLevelClear(); 221 } 222 223 void SetIndices(); 224 void Sort(); 225 bool Check(); 226 bool CheckSectionRefs(); 227 }; 228 229 230 class CInArchive 231 { 232 CMyComPtr<ISequentialInStream> m_InStreamRef; 233 ::CInBuffer _inBuffer; 234 UInt64 _chunkSize; 235 bool _help2; 236 237 Byte ReadByte(); 238 void ReadBytes(Byte *data, UInt32 size); 239 void Skip(size_t size); 240 UInt16 ReadUInt16(); 241 UInt32 ReadUInt32(); 242 UInt64 ReadUInt64(); 243 UInt64 ReadEncInt(); 244 void ReadString(unsigned size, AString &s); 245 void ReadUString(unsigned size, UString &s); 246 void ReadGUID(Byte *g); 247 248 HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size); 249 250 HRESULT ReadDirEntry(CDatabase &database); 251 HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name); 252 253 public: 254 bool IsArc; 255 bool HeadersError; 256 bool UnexpectedEnd; 257 bool UnsupportedFeature; 258 CInArchive(bool help2)259 CInArchive(bool help2) { _help2 = help2; } 260 261 HRESULT OpenChm(IInStream *inStream, CDatabase &database); 262 HRESULT OpenHelp2(IInStream *inStream, CDatabase &database); 263 HRESULT OpenHighLevel(IInStream *inStream, CFilesDatabase &database); 264 HRESULT Open2(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); 265 HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, CFilesDatabase &database); 266 }; 267 268 }} 269 270 #endif 271