1// 7zIn.h
2
3#ifndef __7Z_IN_H
4#define __7Z_IN_H
5
6#include "../../../Common/MyCom.h"
7
8#include "../../../Windows/PropVariant.h"
9
10#include "../../IPassword.h"
11#include "../../IStream.h"
12
13#include "../../Common/CreateCoder.h"
14#include "../../Common/InBuffer.h"
15
16#include "7zItem.h"
17
18namespace NArchive {
19namespace N7z {
20
21/*
22  We don't need to init isEncrypted and passwordIsDefined
23  We must upgrade them only */
24
25#ifdef _NO_CRYPTO
26#define _7Z_DECODER_CRYPRO_VARS_DECL
27#define _7Z_DECODER_CRYPRO_VARS
28#else
29#define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined
30#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined
31#endif
32
33struct CParsedMethods
34{
35  Byte Lzma2Prop;
36  UInt32 LzmaDic;
37  CRecordVector<UInt64> IDs;
38
39  CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
40};
41
42struct CFolders
43{
44  CNum NumPackStreams;
45  CNum NumFolders;
46
47  CObjArray<UInt64> PackPositions; // NumPackStreams + 1
48  // CUInt32DefVector PackCRCs; // we don't use PackCRCs now
49
50  CUInt32DefVector FolderCRCs;              // NumFolders
51  CObjArray<CNum> NumUnpackStreamsVector;  // NumFolders
52
53  CObjArray<UInt64> CoderUnpackSizes;      // including unpack sizes of bind coders
54  CObjArray<CNum> FoToCoderUnpackSizes;    // NumFolders + 1
55  CObjArray<CNum> FoStartPackStreamIndex;  // NumFolders + 1
56  CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders
57
58  CObjArray<size_t> FoCodersDataOffset;    // NumFolders + 1
59  CByteBuffer CodersData;
60
61  CParsedMethods ParsedMethods;
62
63  void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const;
64
65  unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const
66  {
67    return FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex];
68  }
69
70  UInt64 GetFolderUnpackSize(unsigned folderIndex) const
71  {
72    return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]];
73  }
74
75  UInt64 GetStreamPackSize(unsigned index) const
76  {
77    return PackPositions[index + 1] - PackPositions[index];
78  }
79
80  void Clear()
81  {
82    NumPackStreams = 0;
83    PackPositions.Free();
84    // PackCRCs.Clear();
85
86    NumFolders = 0;
87    FolderCRCs.Clear();
88    NumUnpackStreamsVector.Free();
89    CoderUnpackSizes.Free();
90    FoToCoderUnpackSizes.Free();
91    FoStartPackStreamIndex.Free();
92    FoToMainUnpackSizeIndex.Free();
93    FoCodersDataOffset.Free();
94    CodersData.Free();
95  }
96};
97
98struct CDatabase: public CFolders
99{
100  CRecordVector<CFileItem> Files;
101
102  CUInt64DefVector CTime;
103  CUInt64DefVector ATime;
104  CUInt64DefVector MTime;
105  CUInt64DefVector StartPos;
106  CRecordVector<bool> IsAnti;
107  /*
108  CRecordVector<bool> IsAux;
109  CByteBuffer SecureBuf;
110  CRecordVector<UInt32> SecureIDs;
111  */
112
113  CByteBuffer NamesBuf;
114  CObjArray<size_t> NameOffsets; // numFiles + 1, offsets of utf-16 symbols
115
116  /*
117  void ClearSecure()
118  {
119    SecureBuf.Free();
120    SecureIDs.Clear();
121  }
122  */
123
124  void Clear()
125  {
126    CFolders::Clear();
127    // ClearSecure();
128
129    NamesBuf.Free();
130    NameOffsets.Free();
131
132    Files.Clear();
133    CTime.Clear();
134    ATime.Clear();
135    MTime.Clear();
136    StartPos.Clear();
137    IsAnti.Clear();
138    // IsAux.Clear();
139  }
140
141  bool IsSolid() const
142  {
143    for (CNum i = 0; i < NumFolders; i++)
144      if (NumUnpackStreamsVector[i] > 1)
145        return true;
146    return false;
147  }
148  bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
149  // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
150
151  const void * GetName(unsigned index) const
152  {
153    if (!NameOffsets || !NamesBuf)
154      return NULL;
155    return (const void *)((const Byte *)NamesBuf + NameOffsets[index] * 2);
156  };
157
158  void GetPath(unsigned index, UString &path) const;
159  HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw();
160};
161
162struct CInArchiveInfo
163{
164  CArchiveVersion Version;
165  UInt64 StartPosition;
166  UInt64 StartPositionAfterHeader;
167  UInt64 DataStartPosition;
168  UInt64 DataStartPosition2;
169  CRecordVector<UInt64> FileInfoPopIDs;
170
171  void Clear()
172  {
173    StartPosition = 0;
174    StartPositionAfterHeader = 0;
175    DataStartPosition = 0;
176    DataStartPosition2 = 0;
177    FileInfoPopIDs.Clear();
178  }
179};
180
181struct CDbEx: public CDatabase
182{
183  CInArchiveInfo ArcInfo;
184  CRecordVector<CNum> FolderStartFileIndex;
185  CRecordVector<CNum> FileIndexToFolderIndexMap;
186
187  UInt64 HeadersSize;
188  UInt64 PhySize;
189
190  /*
191  CRecordVector<size_t> SecureOffsets;
192  bool IsTree;
193  bool ThereAreAltStreams;
194  */
195
196  bool IsArc;
197  bool PhySizeWasConfirmed;
198
199  bool ThereIsHeaderError;
200  bool UnexpectedEnd;
201  // bool UnsupportedVersion;
202
203  bool StartHeaderWasRecovered;
204  bool UnsupportedFeatureWarning;
205  bool UnsupportedFeatureError;
206
207  /*
208  void ClearSecureEx()
209  {
210    ClearSecure();
211    SecureOffsets.Clear();
212  }
213  */
214
215  void Clear()
216  {
217    IsArc = false;
218    PhySizeWasConfirmed = false;
219
220    ThereIsHeaderError = false;
221    UnexpectedEnd = false;
222    // UnsupportedVersion = false;
223
224    StartHeaderWasRecovered = false;
225    UnsupportedFeatureError = false;
226    UnsupportedFeatureWarning = false;
227
228    /*
229    IsTree = false;
230    ThereAreAltStreams = false;
231    */
232
233    CDatabase::Clear();
234
235    // SecureOffsets.Clear();
236    ArcInfo.Clear();
237    FolderStartFileIndex.Clear();
238    FileIndexToFolderIndexMap.Clear();
239
240    HeadersSize = 0;
241    PhySize = 0;
242  }
243
244  void FillLinks();
245
246  UInt64 GetFolderStreamPos(unsigned folderIndex, unsigned indexInFolder) const
247  {
248    return ArcInfo.DataStartPosition +
249        PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
250  }
251
252  UInt64 GetFolderFullPackSize(unsigned folderIndex) const
253  {
254    return
255      PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
256      PackPositions[FoStartPackStreamIndex[folderIndex]];
257  }
258
259  UInt64 GetFolderPackStreamSize(unsigned folderIndex, unsigned streamIndex) const
260  {
261    unsigned i = FoStartPackStreamIndex[folderIndex] + streamIndex;
262    return PackPositions[i + 1] - PackPositions[i];
263  }
264
265  UInt64 GetFilePackSize(CNum fileIndex) const
266  {
267    CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
268    if (folderIndex != kNumNoIndex)
269      if (FolderStartFileIndex[folderIndex] == fileIndex)
270        return GetFolderFullPackSize(folderIndex);
271    return 0;
272  }
273};
274
275const unsigned kNumBufLevelsMax = 4;
276
277struct CInByte2
278{
279  const Byte *_buffer;
280public:
281  size_t _size;
282  size_t _pos;
283
284  size_t GetRem() const { return _size - _pos; }
285  const Byte *GetPtr() const { return _buffer + _pos; }
286  void Init(const Byte *buffer, size_t size)
287  {
288    _buffer = buffer;
289    _size = size;
290    _pos = 0;
291  }
292  Byte ReadByte();
293  void ReadBytes(Byte *data, size_t size);
294  void SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; }
295  void SkipData(UInt64 size);
296
297  void SkipData();
298  void SkipRem() { _pos = _size; }
299  UInt64 ReadNumber();
300  CNum ReadNum();
301  UInt32 ReadUInt32();
302  UInt64 ReadUInt64();
303
304  void ParseFolder(CFolder &folder);
305};
306
307class CStreamSwitch;
308
309const UInt32 kHeaderSize = 32;
310
311class CInArchive
312{
313  friend class CStreamSwitch;
314
315  CMyComPtr<IInStream> _stream;
316
317  unsigned _numInByteBufs;
318  CInByte2 _inByteVector[kNumBufLevelsMax];
319
320  CInByte2 *_inByteBack;
321  bool ThereIsHeaderError;
322
323  UInt64 _arhiveBeginStreamPosition;
324  UInt64 _fileEndPosition;
325
326  Byte _header[kHeaderSize];
327
328  UInt64 HeadersSize;
329
330  void AddByteStream(const Byte *buffer, size_t size);
331
332  void DeleteByteStream(bool needUpdatePos)
333  {
334    _numInByteBufs--;
335    if (_numInByteBufs > 0)
336    {
337      _inByteBack = &_inByteVector[_numInByteBufs - 1];
338      if (needUpdatePos)
339        _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos;
340    }
341  }
342
343private:
344  HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
345
346  void ReadBytes(Byte *data, size_t size) { _inByteBack->ReadBytes(data, size); }
347  Byte ReadByte() { return _inByteBack->ReadByte(); }
348  UInt64 ReadNumber() { return _inByteBack->ReadNumber(); }
349  CNum ReadNum() { return _inByteBack->ReadNum(); }
350  UInt64 ReadID() { return _inByteBack->ReadNumber(); }
351  UInt32 ReadUInt32() { return _inByteBack->ReadUInt32(); }
352  UInt64 ReadUInt64() { return _inByteBack->ReadUInt64(); }
353  void SkipData(UInt64 size) { _inByteBack->SkipData(size); }
354  void SkipData() { _inByteBack->SkipData(); }
355  void WaitId(UInt64 id);
356
357  void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
358  void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs);
359
360  void ReadPackInfo(CFolders &f);
361
362  void ReadUnpackInfo(
363      const CObjectVector<CByteBuffer> *dataVector,
364      CFolders &folders);
365
366  void ReadSubStreamsInfo(
367      CFolders &folders,
368      CRecordVector<UInt64> &unpackSizes,
369      CUInt32DefVector &digests);
370
371  void ReadStreamsInfo(
372      const CObjectVector<CByteBuffer> *dataVector,
373      UInt64 &dataOffset,
374      CFolders &folders,
375      CRecordVector<UInt64> &unpackSizes,
376      CUInt32DefVector &digests);
377
378  void ReadBoolVector(unsigned numItems, CBoolVector &v);
379  void ReadBoolVector2(unsigned numItems, CBoolVector &v);
380  void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
381      CUInt64DefVector &v, unsigned numItems);
382  HRESULT ReadAndDecodePackedStreams(
383      DECL_EXTERNAL_CODECS_LOC_VARS
384      UInt64 baseOffset, UInt64 &dataOffset,
385      CObjectVector<CByteBuffer> &dataVector
386      _7Z_DECODER_CRYPRO_VARS_DECL
387      );
388  HRESULT ReadHeader(
389      DECL_EXTERNAL_CODECS_LOC_VARS
390      CDbEx &db
391      _7Z_DECODER_CRYPRO_VARS_DECL
392      );
393  HRESULT ReadDatabase2(
394      DECL_EXTERNAL_CODECS_LOC_VARS
395      CDbEx &db
396      _7Z_DECODER_CRYPRO_VARS_DECL
397      );
398public:
399  CInArchive(): _numInByteBufs(0) { }
400  HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
401  void Close();
402
403  HRESULT ReadDatabase(
404      DECL_EXTERNAL_CODECS_LOC_VARS
405      CDbEx &db
406      _7Z_DECODER_CRYPRO_VARS_DECL
407      );
408};
409
410}}
411
412#endif
413