rlm@1
|
1 // 7zIn.cpp
|
rlm@1
|
2
|
rlm@1
|
3 #include "StdAfx.h"
|
rlm@1
|
4
|
rlm@1
|
5 extern "C"
|
rlm@1
|
6 {
|
rlm@1
|
7 #include "../../../../C/7zCrc.h"
|
rlm@1
|
8 #include "../../../../C/CpuArch.h"
|
rlm@1
|
9 }
|
rlm@1
|
10
|
rlm@1
|
11 #include "../../Common/StreamObjects.h"
|
rlm@1
|
12 #include "../../Common/StreamUtils.h"
|
rlm@1
|
13
|
rlm@1
|
14 #include "7zDecode.h"
|
rlm@1
|
15 #include "7zIn.h"
|
rlm@1
|
16
|
rlm@1
|
17 #define Get16(p) GetUi16(p)
|
rlm@1
|
18 #define Get32(p) GetUi32(p)
|
rlm@1
|
19 #define Get64(p) GetUi64(p)
|
rlm@1
|
20
|
rlm@1
|
21 // define FORMAT_7Z_RECOVERY if you want to recover multivolume archives with empty StartHeader
|
rlm@1
|
22 #ifndef _SFX
|
rlm@1
|
23 #define FORMAT_7Z_RECOVERY
|
rlm@1
|
24 #endif
|
rlm@1
|
25
|
rlm@1
|
26 namespace NArchive {
|
rlm@1
|
27 namespace N7z {
|
rlm@1
|
28
|
rlm@1
|
29 static void BoolVector_Fill_False(CBoolVector &v, int size)
|
rlm@1
|
30 {
|
rlm@1
|
31 v.Clear();
|
rlm@1
|
32 v.Reserve(size);
|
rlm@1
|
33 for (int i = 0; i < size; i++)
|
rlm@1
|
34 v.Add(false);
|
rlm@1
|
35 }
|
rlm@1
|
36
|
rlm@1
|
37 static bool BoolVector_GetAndSet(CBoolVector &v, UInt32 index)
|
rlm@1
|
38 {
|
rlm@1
|
39 if (index >= (UInt32)v.Size())
|
rlm@1
|
40 return true;
|
rlm@1
|
41 bool res = v[index];
|
rlm@1
|
42 v[index] = true;
|
rlm@1
|
43 return res;
|
rlm@1
|
44 }
|
rlm@1
|
45
|
rlm@1
|
46 bool CFolder::CheckStructure() const
|
rlm@1
|
47 {
|
rlm@1
|
48 const int kNumCodersMax = sizeof(UInt32) * 8; // don't change it
|
rlm@1
|
49 const int kMaskSize = sizeof(UInt32) * 8; // it must be >= kNumCodersMax
|
rlm@1
|
50 const int kNumBindsMax = 32;
|
rlm@1
|
51
|
rlm@1
|
52 if (Coders.Size() > kNumCodersMax || BindPairs.Size() > kNumBindsMax)
|
rlm@1
|
53 return false;
|
rlm@1
|
54
|
rlm@1
|
55 {
|
rlm@1
|
56 CBoolVector v;
|
rlm@1
|
57 BoolVector_Fill_False(v, BindPairs.Size() + PackStreams.Size());
|
rlm@1
|
58
|
rlm@1
|
59 int i;
|
rlm@1
|
60 for (i = 0; i < BindPairs.Size(); i++)
|
rlm@1
|
61 if (BoolVector_GetAndSet(v, BindPairs[i].InIndex))
|
rlm@1
|
62 return false;
|
rlm@1
|
63 for (i = 0; i < PackStreams.Size(); i++)
|
rlm@1
|
64 if (BoolVector_GetAndSet(v, PackStreams[i]))
|
rlm@1
|
65 return false;
|
rlm@1
|
66
|
rlm@1
|
67 BoolVector_Fill_False(v, UnpackSizes.Size());
|
rlm@1
|
68 for (i = 0; i < BindPairs.Size(); i++)
|
rlm@1
|
69 if (BoolVector_GetAndSet(v, BindPairs[i].OutIndex))
|
rlm@1
|
70 return false;
|
rlm@1
|
71 }
|
rlm@1
|
72
|
rlm@1
|
73 UInt32 mask[kMaskSize];
|
rlm@1
|
74 int i;
|
rlm@1
|
75 for (i = 0; i < kMaskSize; i++)
|
rlm@1
|
76 mask[i] = 0;
|
rlm@1
|
77
|
rlm@1
|
78 {
|
rlm@1
|
79 CIntVector inStreamToCoder, outStreamToCoder;
|
rlm@1
|
80 for (i = 0; i < Coders.Size(); i++)
|
rlm@1
|
81 {
|
rlm@1
|
82 CNum j;
|
rlm@1
|
83 const CCoderInfo &coder = Coders[i];
|
rlm@1
|
84 for (j = 0; j < coder.NumInStreams; j++)
|
rlm@1
|
85 inStreamToCoder.Add(i);
|
rlm@1
|
86 for (j = 0; j < coder.NumOutStreams; j++)
|
rlm@1
|
87 outStreamToCoder.Add(i);
|
rlm@1
|
88 }
|
rlm@1
|
89
|
rlm@1
|
90 for (i = 0; i < BindPairs.Size(); i++)
|
rlm@1
|
91 {
|
rlm@1
|
92 const CBindPair &bp = BindPairs[i];
|
rlm@1
|
93 mask[inStreamToCoder[bp.InIndex]] |= (1 << outStreamToCoder[bp.OutIndex]);
|
rlm@1
|
94 }
|
rlm@1
|
95 }
|
rlm@1
|
96
|
rlm@1
|
97 for (i = 0; i < kMaskSize; i++)
|
rlm@1
|
98 for (int j = 0; j < kMaskSize; j++)
|
rlm@1
|
99 if (((1 << j) & mask[i]) != 0)
|
rlm@1
|
100 mask[i] |= mask[j];
|
rlm@1
|
101
|
rlm@1
|
102 for (i = 0; i < kMaskSize; i++)
|
rlm@1
|
103 if (((1 << i) & mask[i]) != 0)
|
rlm@1
|
104 return false;
|
rlm@1
|
105
|
rlm@1
|
106 return true;
|
rlm@1
|
107 }
|
rlm@1
|
108
|
rlm@1
|
109 class CInArchiveException {};
|
rlm@1
|
110
|
rlm@1
|
111 static void ThrowException() { throw CInArchiveException(); }
|
rlm@1
|
112 static inline void ThrowEndOfData() { ThrowException(); }
|
rlm@1
|
113 static inline void ThrowUnsupported() { ThrowException(); }
|
rlm@1
|
114 static inline void ThrowIncorrect() { ThrowException(); }
|
rlm@1
|
115 static inline void ThrowUnsupportedVersion() { ThrowException(); }
|
rlm@1
|
116
|
rlm@1
|
117 /*
|
rlm@1
|
118 class CInArchiveException
|
rlm@1
|
119 {
|
rlm@1
|
120 public:
|
rlm@1
|
121 enum CCauseType
|
rlm@1
|
122 {
|
rlm@1
|
123 kUnsupportedVersion = 0,
|
rlm@1
|
124 kUnsupported,
|
rlm@1
|
125 kIncorrect,
|
rlm@1
|
126 kEndOfData,
|
rlm@1
|
127 } Cause;
|
rlm@1
|
128 CInArchiveException(CCauseType cause): Cause(cause) {};
|
rlm@1
|
129 };
|
rlm@1
|
130
|
rlm@1
|
131 static void ThrowException(CInArchiveException::CCauseType c) { throw CInArchiveException(c); }
|
rlm@1
|
132 static void ThrowEndOfData() { ThrowException(CInArchiveException::kEndOfData); }
|
rlm@1
|
133 static void ThrowUnsupported() { ThrowException(CInArchiveException::kUnsupported); }
|
rlm@1
|
134 static void ThrowIncorrect() { ThrowException(CInArchiveException::kIncorrect); }
|
rlm@1
|
135 static void ThrowUnsupportedVersion() { ThrowException(CInArchiveException::kUnsupportedVersion); }
|
rlm@1
|
136 */
|
rlm@1
|
137
|
rlm@1
|
138 class CStreamSwitch
|
rlm@1
|
139 {
|
rlm@1
|
140 CInArchive *_archive;
|
rlm@1
|
141 bool _needRemove;
|
rlm@1
|
142 public:
|
rlm@1
|
143 CStreamSwitch(): _needRemove(false) {}
|
rlm@1
|
144 ~CStreamSwitch() { Remove(); }
|
rlm@1
|
145 void Remove();
|
rlm@1
|
146 void Set(CInArchive *archive, const Byte *data, size_t size);
|
rlm@1
|
147 void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
|
rlm@1
|
148 void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
|
rlm@1
|
149 };
|
rlm@1
|
150
|
rlm@1
|
151 void CStreamSwitch::Remove()
|
rlm@1
|
152 {
|
rlm@1
|
153 if (_needRemove)
|
rlm@1
|
154 {
|
rlm@1
|
155 _archive->DeleteByteStream();
|
rlm@1
|
156 _needRemove = false;
|
rlm@1
|
157 }
|
rlm@1
|
158 }
|
rlm@1
|
159
|
rlm@1
|
160 void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size)
|
rlm@1
|
161 {
|
rlm@1
|
162 Remove();
|
rlm@1
|
163 _archive = archive;
|
rlm@1
|
164 _archive->AddByteStream(data, size);
|
rlm@1
|
165 _needRemove = true;
|
rlm@1
|
166 }
|
rlm@1
|
167
|
rlm@1
|
168 void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
|
rlm@1
|
169 {
|
rlm@1
|
170 Set(archive, byteBuffer, byteBuffer.GetCapacity());
|
rlm@1
|
171 }
|
rlm@1
|
172
|
rlm@1
|
173 void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
|
rlm@1
|
174 {
|
rlm@1
|
175 Remove();
|
rlm@1
|
176 Byte external = archive->ReadByte();
|
rlm@1
|
177 if (external != 0)
|
rlm@1
|
178 {
|
rlm@1
|
179 int dataIndex = (int)archive->ReadNum();
|
rlm@1
|
180 if (dataIndex < 0 || dataIndex >= dataVector->Size())
|
rlm@1
|
181 ThrowIncorrect();
|
rlm@1
|
182 Set(archive, (*dataVector)[dataIndex]);
|
rlm@1
|
183 }
|
rlm@1
|
184 }
|
rlm@1
|
185
|
rlm@1
|
186 Byte CInByte2::ReadByte()
|
rlm@1
|
187 {
|
rlm@1
|
188 if (_pos >= _size)
|
rlm@1
|
189 ThrowEndOfData();
|
rlm@1
|
190 return _buffer[_pos++];
|
rlm@1
|
191 }
|
rlm@1
|
192
|
rlm@1
|
193 void CInByte2::ReadBytes(Byte *data, size_t size)
|
rlm@1
|
194 {
|
rlm@1
|
195 if (size > _size - _pos)
|
rlm@1
|
196 ThrowEndOfData();
|
rlm@1
|
197 for (size_t i = 0; i < size; i++)
|
rlm@1
|
198 data[i] = _buffer[_pos++];
|
rlm@1
|
199 }
|
rlm@1
|
200
|
rlm@1
|
201 void CInByte2::SkeepData(UInt64 size)
|
rlm@1
|
202 {
|
rlm@1
|
203 if (size > _size - _pos)
|
rlm@1
|
204 ThrowEndOfData();
|
rlm@1
|
205 _pos += (size_t)size;
|
rlm@1
|
206 }
|
rlm@1
|
207
|
rlm@1
|
208 void CInByte2::SkeepData()
|
rlm@1
|
209 {
|
rlm@1
|
210 SkeepData(ReadNumber());
|
rlm@1
|
211 }
|
rlm@1
|
212
|
rlm@1
|
213 UInt64 CInByte2::ReadNumber()
|
rlm@1
|
214 {
|
rlm@1
|
215 if (_pos >= _size)
|
rlm@1
|
216 ThrowEndOfData();
|
rlm@1
|
217 Byte firstByte = _buffer[_pos++];
|
rlm@1
|
218 Byte mask = 0x80;
|
rlm@1
|
219 UInt64 value = 0;
|
rlm@1
|
220 for (int i = 0; i < 8; i++)
|
rlm@1
|
221 {
|
rlm@1
|
222 if ((firstByte & mask) == 0)
|
rlm@1
|
223 {
|
rlm@1
|
224 UInt64 highPart = firstByte & (mask - 1);
|
rlm@1
|
225 value += (highPart << (i * 8));
|
rlm@1
|
226 return value;
|
rlm@1
|
227 }
|
rlm@1
|
228 if (_pos >= _size)
|
rlm@1
|
229 ThrowEndOfData();
|
rlm@1
|
230 value |= ((UInt64)_buffer[_pos++] << (8 * i));
|
rlm@1
|
231 mask >>= 1;
|
rlm@1
|
232 }
|
rlm@1
|
233 return value;
|
rlm@1
|
234 }
|
rlm@1
|
235
|
rlm@1
|
236 CNum CInByte2::ReadNum()
|
rlm@1
|
237 {
|
rlm@1
|
238 UInt64 value = ReadNumber();
|
rlm@1
|
239 if (value > kNumMax)
|
rlm@1
|
240 ThrowUnsupported();
|
rlm@1
|
241 return (CNum)value;
|
rlm@1
|
242 }
|
rlm@1
|
243
|
rlm@1
|
244 UInt32 CInByte2::ReadUInt32()
|
rlm@1
|
245 {
|
rlm@1
|
246 if (_pos + 4 > _size)
|
rlm@1
|
247 ThrowEndOfData();
|
rlm@1
|
248 UInt32 res = Get32(_buffer + _pos);
|
rlm@1
|
249 _pos += 4;
|
rlm@1
|
250 return res;
|
rlm@1
|
251 }
|
rlm@1
|
252
|
rlm@1
|
253 UInt64 CInByte2::ReadUInt64()
|
rlm@1
|
254 {
|
rlm@1
|
255 if (_pos + 8 > _size)
|
rlm@1
|
256 ThrowEndOfData();
|
rlm@1
|
257 UInt64 res = Get64(_buffer + _pos);
|
rlm@1
|
258 _pos += 8;
|
rlm@1
|
259 return res;
|
rlm@1
|
260 }
|
rlm@1
|
261
|
rlm@1
|
262 void CInByte2::ReadString(UString &s)
|
rlm@1
|
263 {
|
rlm@1
|
264 const Byte *buf = _buffer + _pos;
|
rlm@1
|
265 size_t rem = (_size - _pos) / 2 * 2;
|
rlm@1
|
266 {
|
rlm@1
|
267 size_t i;
|
rlm@1
|
268 for (i = 0; i < rem; i += 2)
|
rlm@1
|
269 if (buf[i] == 0 && buf[i + 1] == 0)
|
rlm@1
|
270 break;
|
rlm@1
|
271 if (i == rem)
|
rlm@1
|
272 ThrowEndOfData();
|
rlm@1
|
273 rem = i;
|
rlm@1
|
274 }
|
rlm@1
|
275 int len = (int)(rem / 2);
|
rlm@1
|
276 if (len < 0 || (size_t)len * 2 != rem)
|
rlm@1
|
277 ThrowUnsupported();
|
rlm@1
|
278 wchar_t *p = s.GetBuffer(len);
|
rlm@1
|
279 int i;
|
rlm@1
|
280 for (i = 0; i < len; i++, buf += 2)
|
rlm@1
|
281 p[i] = (wchar_t)Get16(buf);
|
rlm@1
|
282 s.ReleaseBuffer(len);
|
rlm@1
|
283 _pos += rem + 2;
|
rlm@1
|
284 }
|
rlm@1
|
285
|
rlm@1
|
286 static inline bool TestSignatureCandidate(const Byte *p)
|
rlm@1
|
287 {
|
rlm@1
|
288 for (int i = 0; i < kSignatureSize; i++)
|
rlm@1
|
289 if (p[i] != kSignature[i])
|
rlm@1
|
290 return false;
|
rlm@1
|
291 return (p[0x1A] == 0 && p[0x1B] == 0);
|
rlm@1
|
292 }
|
rlm@1
|
293
|
rlm@1
|
294 HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
|
rlm@1
|
295 {
|
rlm@1
|
296 RINOK(ReadStream_FALSE(stream, _header, kHeaderSize));
|
rlm@1
|
297
|
rlm@1
|
298 if (TestSignatureCandidate(_header))
|
rlm@1
|
299 return S_OK;
|
rlm@1
|
300
|
rlm@1
|
301 CByteBuffer byteBuffer;
|
rlm@1
|
302 const UInt32 kBufferSize = (1 << 16);
|
rlm@1
|
303 byteBuffer.SetCapacity(kBufferSize);
|
rlm@1
|
304 Byte *buffer = byteBuffer;
|
rlm@1
|
305 UInt32 numPrevBytes = kHeaderSize - 1;
|
rlm@1
|
306 memcpy(buffer, _header + 1, numPrevBytes);
|
rlm@1
|
307 UInt64 curTestPos = _arhiveBeginStreamPosition + 1;
|
rlm@1
|
308 for (;;)
|
rlm@1
|
309 {
|
rlm@1
|
310 if (searchHeaderSizeLimit != NULL)
|
rlm@1
|
311 if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit)
|
rlm@1
|
312 break;
|
rlm@1
|
313 do
|
rlm@1
|
314 {
|
rlm@1
|
315 UInt32 numReadBytes = kBufferSize - numPrevBytes;
|
rlm@1
|
316 UInt32 processedSize;
|
rlm@1
|
317 RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize));
|
rlm@1
|
318 numPrevBytes += processedSize;
|
rlm@1
|
319 if (processedSize == 0)
|
rlm@1
|
320 return S_FALSE;
|
rlm@1
|
321 }
|
rlm@1
|
322 while (numPrevBytes < kHeaderSize);
|
rlm@1
|
323 UInt32 numTests = numPrevBytes - kHeaderSize + 1;
|
rlm@1
|
324 for (UInt32 pos = 0; pos < numTests; pos++)
|
rlm@1
|
325 {
|
rlm@1
|
326 for (; buffer[pos] != '7' && pos < numTests; pos++);
|
rlm@1
|
327 if (pos == numTests)
|
rlm@1
|
328 break;
|
rlm@1
|
329 if (TestSignatureCandidate(buffer + pos))
|
rlm@1
|
330 {
|
rlm@1
|
331 memcpy(_header, buffer + pos, kHeaderSize);
|
rlm@1
|
332 curTestPos += pos;
|
rlm@1
|
333 _arhiveBeginStreamPosition = curTestPos;
|
rlm@1
|
334 return stream->Seek(curTestPos + kHeaderSize, STREAM_SEEK_SET, NULL);
|
rlm@1
|
335 }
|
rlm@1
|
336 }
|
rlm@1
|
337 curTestPos += numTests;
|
rlm@1
|
338 numPrevBytes -= numTests;
|
rlm@1
|
339 memmove(buffer, buffer + numTests, numPrevBytes);
|
rlm@1
|
340 }
|
rlm@1
|
341 return S_FALSE;
|
rlm@1
|
342 }
|
rlm@1
|
343
|
rlm@1
|
344 // S_FALSE means that file is not archive
|
rlm@1
|
345 HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
|
rlm@1
|
346 {
|
rlm@1
|
347 HeadersSize = 0;
|
rlm@1
|
348 Close();
|
rlm@1
|
349 RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition))
|
rlm@1
|
350 RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
|
rlm@1
|
351 _stream = stream;
|
rlm@1
|
352 return S_OK;
|
rlm@1
|
353 }
|
rlm@1
|
354
|
rlm@1
|
355 void CInArchive::Close()
|
rlm@1
|
356 {
|
rlm@1
|
357 _stream.Release();
|
rlm@1
|
358 }
|
rlm@1
|
359
|
rlm@1
|
360 void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
|
rlm@1
|
361 {
|
rlm@1
|
362 for (;;)
|
rlm@1
|
363 {
|
rlm@1
|
364 if (ReadID() == NID::kEnd)
|
rlm@1
|
365 break;
|
rlm@1
|
366 SkeepData();
|
rlm@1
|
367 }
|
rlm@1
|
368 }
|
rlm@1
|
369
|
rlm@1
|
370 void CInArchive::GetNextFolderItem(CFolder &folder)
|
rlm@1
|
371 {
|
rlm@1
|
372 CNum numCoders = ReadNum();
|
rlm@1
|
373
|
rlm@1
|
374 folder.Coders.Clear();
|
rlm@1
|
375 folder.Coders.Reserve((int)numCoders);
|
rlm@1
|
376 CNum numInStreams = 0;
|
rlm@1
|
377 CNum numOutStreams = 0;
|
rlm@1
|
378 CNum i;
|
rlm@1
|
379 for (i = 0; i < numCoders; i++)
|
rlm@1
|
380 {
|
rlm@1
|
381 folder.Coders.Add(CCoderInfo());
|
rlm@1
|
382 CCoderInfo &coder = folder.Coders.Back();
|
rlm@1
|
383
|
rlm@1
|
384 {
|
rlm@1
|
385 Byte mainByte = ReadByte();
|
rlm@1
|
386 int idSize = (mainByte & 0xF);
|
rlm@1
|
387 Byte longID[15];
|
rlm@1
|
388 ReadBytes(longID, idSize);
|
rlm@1
|
389 if (idSize > 8)
|
rlm@1
|
390 ThrowUnsupported();
|
rlm@1
|
391 UInt64 id = 0;
|
rlm@1
|
392 for (int j = 0; j < idSize; j++)
|
rlm@1
|
393 id |= (UInt64)longID[idSize - 1 - j] << (8 * j);
|
rlm@1
|
394 coder.MethodID = id;
|
rlm@1
|
395
|
rlm@1
|
396 if ((mainByte & 0x10) != 0)
|
rlm@1
|
397 {
|
rlm@1
|
398 coder.NumInStreams = ReadNum();
|
rlm@1
|
399 coder.NumOutStreams = ReadNum();
|
rlm@1
|
400 }
|
rlm@1
|
401 else
|
rlm@1
|
402 {
|
rlm@1
|
403 coder.NumInStreams = 1;
|
rlm@1
|
404 coder.NumOutStreams = 1;
|
rlm@1
|
405 }
|
rlm@1
|
406 if ((mainByte & 0x20) != 0)
|
rlm@1
|
407 {
|
rlm@1
|
408 CNum propsSize = ReadNum();
|
rlm@1
|
409 coder.Props.SetCapacity((size_t)propsSize);
|
rlm@1
|
410 ReadBytes((Byte *)coder.Props, (size_t)propsSize);
|
rlm@1
|
411 }
|
rlm@1
|
412 if ((mainByte & 0x80) != 0)
|
rlm@1
|
413 ThrowUnsupported();
|
rlm@1
|
414 }
|
rlm@1
|
415 numInStreams += coder.NumInStreams;
|
rlm@1
|
416 numOutStreams += coder.NumOutStreams;
|
rlm@1
|
417 }
|
rlm@1
|
418
|
rlm@1
|
419 CNum numBindPairs = numOutStreams - 1;
|
rlm@1
|
420 folder.BindPairs.Clear();
|
rlm@1
|
421 folder.BindPairs.Reserve(numBindPairs);
|
rlm@1
|
422 for (i = 0; i < numBindPairs; i++)
|
rlm@1
|
423 {
|
rlm@1
|
424 CBindPair bp;
|
rlm@1
|
425 bp.InIndex = ReadNum();
|
rlm@1
|
426 bp.OutIndex = ReadNum();
|
rlm@1
|
427 folder.BindPairs.Add(bp);
|
rlm@1
|
428 }
|
rlm@1
|
429
|
rlm@1
|
430 if (numInStreams < numBindPairs)
|
rlm@1
|
431 ThrowUnsupported();
|
rlm@1
|
432 CNum numPackStreams = numInStreams - numBindPairs;
|
rlm@1
|
433 folder.PackStreams.Reserve(numPackStreams);
|
rlm@1
|
434 if (numPackStreams == 1)
|
rlm@1
|
435 {
|
rlm@1
|
436 for (i = 0; i < numInStreams; i++)
|
rlm@1
|
437 if (folder.FindBindPairForInStream(i) < 0)
|
rlm@1
|
438 {
|
rlm@1
|
439 folder.PackStreams.Add(i);
|
rlm@1
|
440 break;
|
rlm@1
|
441 }
|
rlm@1
|
442 if (folder.PackStreams.Size() != 1)
|
rlm@1
|
443 ThrowUnsupported();
|
rlm@1
|
444 }
|
rlm@1
|
445 else
|
rlm@1
|
446 for (i = 0; i < numPackStreams; i++)
|
rlm@1
|
447 folder.PackStreams.Add(ReadNum());
|
rlm@1
|
448 }
|
rlm@1
|
449
|
rlm@1
|
450 void CInArchive::WaitAttribute(UInt64 attribute)
|
rlm@1
|
451 {
|
rlm@1
|
452 for (;;)
|
rlm@1
|
453 {
|
rlm@1
|
454 UInt64 type = ReadID();
|
rlm@1
|
455 if (type == attribute)
|
rlm@1
|
456 return;
|
rlm@1
|
457 if (type == NID::kEnd)
|
rlm@1
|
458 ThrowIncorrect();
|
rlm@1
|
459 SkeepData();
|
rlm@1
|
460 }
|
rlm@1
|
461 }
|
rlm@1
|
462
|
rlm@1
|
463 void CInArchive::ReadHashDigests(int numItems,
|
rlm@1
|
464 CBoolVector &digestsDefined,
|
rlm@1
|
465 CRecordVector<UInt32> &digests)
|
rlm@1
|
466 {
|
rlm@1
|
467 ReadBoolVector2(numItems, digestsDefined);
|
rlm@1
|
468 digests.Clear();
|
rlm@1
|
469 digests.Reserve(numItems);
|
rlm@1
|
470 for (int i = 0; i < numItems; i++)
|
rlm@1
|
471 {
|
rlm@1
|
472 UInt32 crc = 0;
|
rlm@1
|
473 if (digestsDefined[i])
|
rlm@1
|
474 crc = ReadUInt32();
|
rlm@1
|
475 digests.Add(crc);
|
rlm@1
|
476 }
|
rlm@1
|
477 }
|
rlm@1
|
478
|
rlm@1
|
479 void CInArchive::ReadPackInfo(
|
rlm@1
|
480 UInt64 &dataOffset,
|
rlm@1
|
481 CRecordVector<UInt64> &packSizes,
|
rlm@1
|
482 CBoolVector &packCRCsDefined,
|
rlm@1
|
483 CRecordVector<UInt32> &packCRCs)
|
rlm@1
|
484 {
|
rlm@1
|
485 dataOffset = ReadNumber();
|
rlm@1
|
486 CNum numPackStreams = ReadNum();
|
rlm@1
|
487
|
rlm@1
|
488 WaitAttribute(NID::kSize);
|
rlm@1
|
489 packSizes.Clear();
|
rlm@1
|
490 packSizes.Reserve(numPackStreams);
|
rlm@1
|
491 for (CNum i = 0; i < numPackStreams; i++)
|
rlm@1
|
492 packSizes.Add(ReadNumber());
|
rlm@1
|
493
|
rlm@1
|
494 UInt64 type;
|
rlm@1
|
495 for (;;)
|
rlm@1
|
496 {
|
rlm@1
|
497 type = ReadID();
|
rlm@1
|
498 if (type == NID::kEnd)
|
rlm@1
|
499 break;
|
rlm@1
|
500 if (type == NID::kCRC)
|
rlm@1
|
501 {
|
rlm@1
|
502 ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs);
|
rlm@1
|
503 continue;
|
rlm@1
|
504 }
|
rlm@1
|
505 SkeepData();
|
rlm@1
|
506 }
|
rlm@1
|
507 if (packCRCsDefined.IsEmpty())
|
rlm@1
|
508 {
|
rlm@1
|
509 BoolVector_Fill_False(packCRCsDefined, numPackStreams);
|
rlm@1
|
510 packCRCs.Reserve(numPackStreams);
|
rlm@1
|
511 packCRCs.Clear();
|
rlm@1
|
512 for (CNum i = 0; i < numPackStreams; i++)
|
rlm@1
|
513 packCRCs.Add(0);
|
rlm@1
|
514 }
|
rlm@1
|
515 }
|
rlm@1
|
516
|
rlm@1
|
517 void CInArchive::ReadUnpackInfo(
|
rlm@1
|
518 const CObjectVector<CByteBuffer> *dataVector,
|
rlm@1
|
519 CObjectVector<CFolder> &folders)
|
rlm@1
|
520 {
|
rlm@1
|
521 WaitAttribute(NID::kFolder);
|
rlm@1
|
522 CNum numFolders = ReadNum();
|
rlm@1
|
523
|
rlm@1
|
524 {
|
rlm@1
|
525 CStreamSwitch streamSwitch;
|
rlm@1
|
526 streamSwitch.Set(this, dataVector);
|
rlm@1
|
527 folders.Clear();
|
rlm@1
|
528 folders.Reserve(numFolders);
|
rlm@1
|
529 for (CNum i = 0; i < numFolders; i++)
|
rlm@1
|
530 {
|
rlm@1
|
531 folders.Add(CFolder());
|
rlm@1
|
532 GetNextFolderItem(folders.Back());
|
rlm@1
|
533 }
|
rlm@1
|
534 }
|
rlm@1
|
535
|
rlm@1
|
536 WaitAttribute(NID::kCodersUnpackSize);
|
rlm@1
|
537
|
rlm@1
|
538 CNum i;
|
rlm@1
|
539 for (i = 0; i < numFolders; i++)
|
rlm@1
|
540 {
|
rlm@1
|
541 CFolder &folder = folders[i];
|
rlm@1
|
542 CNum numOutStreams = folder.GetNumOutStreams();
|
rlm@1
|
543 folder.UnpackSizes.Reserve(numOutStreams);
|
rlm@1
|
544 for (CNum j = 0; j < numOutStreams; j++)
|
rlm@1
|
545 folder.UnpackSizes.Add(ReadNumber());
|
rlm@1
|
546 }
|
rlm@1
|
547
|
rlm@1
|
548 for (;;)
|
rlm@1
|
549 {
|
rlm@1
|
550 UInt64 type = ReadID();
|
rlm@1
|
551 if (type == NID::kEnd)
|
rlm@1
|
552 return;
|
rlm@1
|
553 if (type == NID::kCRC)
|
rlm@1
|
554 {
|
rlm@1
|
555 CBoolVector crcsDefined;
|
rlm@1
|
556 CRecordVector<UInt32> crcs;
|
rlm@1
|
557 ReadHashDigests(numFolders, crcsDefined, crcs);
|
rlm@1
|
558 for (i = 0; i < numFolders; i++)
|
rlm@1
|
559 {
|
rlm@1
|
560 CFolder &folder = folders[i];
|
rlm@1
|
561 folder.UnpackCRCDefined = crcsDefined[i];
|
rlm@1
|
562 folder.UnpackCRC = crcs[i];
|
rlm@1
|
563 }
|
rlm@1
|
564 continue;
|
rlm@1
|
565 }
|
rlm@1
|
566 SkeepData();
|
rlm@1
|
567 }
|
rlm@1
|
568 }
|
rlm@1
|
569
|
rlm@1
|
570 void CInArchive::ReadSubStreamsInfo(
|
rlm@1
|
571 const CObjectVector<CFolder> &folders,
|
rlm@1
|
572 CRecordVector<CNum> &numUnpackStreamsInFolders,
|
rlm@1
|
573 CRecordVector<UInt64> &unpackSizes,
|
rlm@1
|
574 CBoolVector &digestsDefined,
|
rlm@1
|
575 CRecordVector<UInt32> &digests)
|
rlm@1
|
576 {
|
rlm@1
|
577 numUnpackStreamsInFolders.Clear();
|
rlm@1
|
578 numUnpackStreamsInFolders.Reserve(folders.Size());
|
rlm@1
|
579 UInt64 type;
|
rlm@1
|
580 for (;;)
|
rlm@1
|
581 {
|
rlm@1
|
582 type = ReadID();
|
rlm@1
|
583 if (type == NID::kNumUnpackStream)
|
rlm@1
|
584 {
|
rlm@1
|
585 for (int i = 0; i < folders.Size(); i++)
|
rlm@1
|
586 numUnpackStreamsInFolders.Add(ReadNum());
|
rlm@1
|
587 continue;
|
rlm@1
|
588 }
|
rlm@1
|
589 if (type == NID::kCRC || type == NID::kSize)
|
rlm@1
|
590 break;
|
rlm@1
|
591 if (type == NID::kEnd)
|
rlm@1
|
592 break;
|
rlm@1
|
593 SkeepData();
|
rlm@1
|
594 }
|
rlm@1
|
595
|
rlm@1
|
596 if (numUnpackStreamsInFolders.IsEmpty())
|
rlm@1
|
597 for (int i = 0; i < folders.Size(); i++)
|
rlm@1
|
598 numUnpackStreamsInFolders.Add(1);
|
rlm@1
|
599
|
rlm@1
|
600 int i;
|
rlm@1
|
601 for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
|
rlm@1
|
602 {
|
rlm@1
|
603 // v3.13 incorrectly worked with empty folders
|
rlm@1
|
604 // v4.07: we check that folder is empty
|
rlm@1
|
605 CNum numSubstreams = numUnpackStreamsInFolders[i];
|
rlm@1
|
606 if (numSubstreams == 0)
|
rlm@1
|
607 continue;
|
rlm@1
|
608 UInt64 sum = 0;
|
rlm@1
|
609 for (CNum j = 1; j < numSubstreams; j++)
|
rlm@1
|
610 if (type == NID::kSize)
|
rlm@1
|
611 {
|
rlm@1
|
612 UInt64 size = ReadNumber();
|
rlm@1
|
613 unpackSizes.Add(size);
|
rlm@1
|
614 sum += size;
|
rlm@1
|
615 }
|
rlm@1
|
616 unpackSizes.Add(folders[i].GetUnpackSize() - sum);
|
rlm@1
|
617 }
|
rlm@1
|
618 if (type == NID::kSize)
|
rlm@1
|
619 type = ReadID();
|
rlm@1
|
620
|
rlm@1
|
621 int numDigests = 0;
|
rlm@1
|
622 int numDigestsTotal = 0;
|
rlm@1
|
623 for (i = 0; i < folders.Size(); i++)
|
rlm@1
|
624 {
|
rlm@1
|
625 CNum numSubstreams = numUnpackStreamsInFolders[i];
|
rlm@1
|
626 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
|
rlm@1
|
627 numDigests += numSubstreams;
|
rlm@1
|
628 numDigestsTotal += numSubstreams;
|
rlm@1
|
629 }
|
rlm@1
|
630
|
rlm@1
|
631 for (;;)
|
rlm@1
|
632 {
|
rlm@1
|
633 if (type == NID::kCRC)
|
rlm@1
|
634 {
|
rlm@1
|
635 CBoolVector digestsDefined2;
|
rlm@1
|
636 CRecordVector<UInt32> digests2;
|
rlm@1
|
637 ReadHashDigests(numDigests, digestsDefined2, digests2);
|
rlm@1
|
638 int digestIndex = 0;
|
rlm@1
|
639 for (i = 0; i < folders.Size(); i++)
|
rlm@1
|
640 {
|
rlm@1
|
641 CNum numSubstreams = numUnpackStreamsInFolders[i];
|
rlm@1
|
642 const CFolder &folder = folders[i];
|
rlm@1
|
643 if (numSubstreams == 1 && folder.UnpackCRCDefined)
|
rlm@1
|
644 {
|
rlm@1
|
645 digestsDefined.Add(true);
|
rlm@1
|
646 digests.Add(folder.UnpackCRC);
|
rlm@1
|
647 }
|
rlm@1
|
648 else
|
rlm@1
|
649 for (CNum j = 0; j < numSubstreams; j++, digestIndex++)
|
rlm@1
|
650 {
|
rlm@1
|
651 digestsDefined.Add(digestsDefined2[digestIndex]);
|
rlm@1
|
652 digests.Add(digests2[digestIndex]);
|
rlm@1
|
653 }
|
rlm@1
|
654 }
|
rlm@1
|
655 }
|
rlm@1
|
656 else if (type == NID::kEnd)
|
rlm@1
|
657 {
|
rlm@1
|
658 if (digestsDefined.IsEmpty())
|
rlm@1
|
659 {
|
rlm@1
|
660 BoolVector_Fill_False(digestsDefined, numDigestsTotal);
|
rlm@1
|
661 digests.Clear();
|
rlm@1
|
662 for (int i = 0; i < numDigestsTotal; i++)
|
rlm@1
|
663 digests.Add(0);
|
rlm@1
|
664 }
|
rlm@1
|
665 return;
|
rlm@1
|
666 }
|
rlm@1
|
667 else
|
rlm@1
|
668 SkeepData();
|
rlm@1
|
669 type = ReadID();
|
rlm@1
|
670 }
|
rlm@1
|
671 }
|
rlm@1
|
672
|
rlm@1
|
673 void CInArchive::ReadStreamsInfo(
|
rlm@1
|
674 const CObjectVector<CByteBuffer> *dataVector,
|
rlm@1
|
675 UInt64 &dataOffset,
|
rlm@1
|
676 CRecordVector<UInt64> &packSizes,
|
rlm@1
|
677 CBoolVector &packCRCsDefined,
|
rlm@1
|
678 CRecordVector<UInt32> &packCRCs,
|
rlm@1
|
679 CObjectVector<CFolder> &folders,
|
rlm@1
|
680 CRecordVector<CNum> &numUnpackStreamsInFolders,
|
rlm@1
|
681 CRecordVector<UInt64> &unpackSizes,
|
rlm@1
|
682 CBoolVector &digestsDefined,
|
rlm@1
|
683 CRecordVector<UInt32> &digests)
|
rlm@1
|
684 {
|
rlm@1
|
685 for (;;)
|
rlm@1
|
686 {
|
rlm@1
|
687 UInt64 type = ReadID();
|
rlm@1
|
688 if (type > ((UInt32)1 << 30))
|
rlm@1
|
689 ThrowIncorrect();
|
rlm@1
|
690 switch((UInt32)type)
|
rlm@1
|
691 {
|
rlm@1
|
692 case NID::kEnd:
|
rlm@1
|
693 return;
|
rlm@1
|
694 case NID::kPackInfo:
|
rlm@1
|
695 {
|
rlm@1
|
696 ReadPackInfo(dataOffset, packSizes, packCRCsDefined, packCRCs);
|
rlm@1
|
697 break;
|
rlm@1
|
698 }
|
rlm@1
|
699 case NID::kUnpackInfo:
|
rlm@1
|
700 {
|
rlm@1
|
701 ReadUnpackInfo(dataVector, folders);
|
rlm@1
|
702 break;
|
rlm@1
|
703 }
|
rlm@1
|
704 case NID::kSubStreamsInfo:
|
rlm@1
|
705 {
|
rlm@1
|
706 ReadSubStreamsInfo(folders, numUnpackStreamsInFolders,
|
rlm@1
|
707 unpackSizes, digestsDefined, digests);
|
rlm@1
|
708 break;
|
rlm@1
|
709 }
|
rlm@1
|
710 default:
|
rlm@1
|
711 ThrowIncorrect();
|
rlm@1
|
712 }
|
rlm@1
|
713 }
|
rlm@1
|
714 }
|
rlm@1
|
715
|
rlm@1
|
716 void CInArchive::ReadBoolVector(int numItems, CBoolVector &v)
|
rlm@1
|
717 {
|
rlm@1
|
718 v.Clear();
|
rlm@1
|
719 v.Reserve(numItems);
|
rlm@1
|
720 Byte b = 0;
|
rlm@1
|
721 Byte mask = 0;
|
rlm@1
|
722 for (int i = 0; i < numItems; i++)
|
rlm@1
|
723 {
|
rlm@1
|
724 if (mask == 0)
|
rlm@1
|
725 {
|
rlm@1
|
726 b = ReadByte();
|
rlm@1
|
727 mask = 0x80;
|
rlm@1
|
728 }
|
rlm@1
|
729 v.Add((b & mask) != 0);
|
rlm@1
|
730 mask >>= 1;
|
rlm@1
|
731 }
|
rlm@1
|
732 }
|
rlm@1
|
733
|
rlm@1
|
734 void CInArchive::ReadBoolVector2(int numItems, CBoolVector &v)
|
rlm@1
|
735 {
|
rlm@1
|
736 Byte allAreDefined = ReadByte();
|
rlm@1
|
737 if (allAreDefined == 0)
|
rlm@1
|
738 {
|
rlm@1
|
739 ReadBoolVector(numItems, v);
|
rlm@1
|
740 return;
|
rlm@1
|
741 }
|
rlm@1
|
742 v.Clear();
|
rlm@1
|
743 v.Reserve(numItems);
|
rlm@1
|
744 for (int i = 0; i < numItems; i++)
|
rlm@1
|
745 v.Add(true);
|
rlm@1
|
746 }
|
rlm@1
|
747
|
rlm@1
|
748 void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
|
rlm@1
|
749 CUInt64DefVector &v, int numFiles)
|
rlm@1
|
750 {
|
rlm@1
|
751 ReadBoolVector2(numFiles, v.Defined);
|
rlm@1
|
752
|
rlm@1
|
753 CStreamSwitch streamSwitch;
|
rlm@1
|
754 streamSwitch.Set(this, &dataVector);
|
rlm@1
|
755 v.Values.Reserve(numFiles);
|
rlm@1
|
756
|
rlm@1
|
757 for (int i = 0; i < numFiles; i++)
|
rlm@1
|
758 {
|
rlm@1
|
759 UInt64 t = 0;
|
rlm@1
|
760 if (v.Defined[i])
|
rlm@1
|
761 t = ReadUInt64();
|
rlm@1
|
762 v.Values.Add(t);
|
rlm@1
|
763 }
|
rlm@1
|
764 }
|
rlm@1
|
765
|
rlm@1
|
766 HRESULT CInArchive::ReadAndDecodePackedStreams(
|
rlm@1
|
767 DECL_EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
768 UInt64 baseOffset,
|
rlm@1
|
769 UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
|
rlm@1
|
770 #ifndef _NO_CRYPTO
|
rlm@1
|
771 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
|
rlm@1
|
772 #endif
|
rlm@1
|
773 )
|
rlm@1
|
774 {
|
rlm@1
|
775 CRecordVector<UInt64> packSizes;
|
rlm@1
|
776 CBoolVector packCRCsDefined;
|
rlm@1
|
777 CRecordVector<UInt32> packCRCs;
|
rlm@1
|
778 CObjectVector<CFolder> folders;
|
rlm@1
|
779
|
rlm@1
|
780 CRecordVector<CNum> numUnpackStreamsInFolders;
|
rlm@1
|
781 CRecordVector<UInt64> unpackSizes;
|
rlm@1
|
782 CBoolVector digestsDefined;
|
rlm@1
|
783 CRecordVector<UInt32> digests;
|
rlm@1
|
784
|
rlm@1
|
785 ReadStreamsInfo(NULL,
|
rlm@1
|
786 dataOffset,
|
rlm@1
|
787 packSizes,
|
rlm@1
|
788 packCRCsDefined,
|
rlm@1
|
789 packCRCs,
|
rlm@1
|
790 folders,
|
rlm@1
|
791 numUnpackStreamsInFolders,
|
rlm@1
|
792 unpackSizes,
|
rlm@1
|
793 digestsDefined,
|
rlm@1
|
794 digests);
|
rlm@1
|
795
|
rlm@1
|
796 // db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
|
rlm@1
|
797
|
rlm@1
|
798 CNum packIndex = 0;
|
rlm@1
|
799 CDecoder decoder(
|
rlm@1
|
800 #ifdef _ST_MODE
|
rlm@1
|
801 false
|
rlm@1
|
802 #else
|
rlm@1
|
803 true
|
rlm@1
|
804 #endif
|
rlm@1
|
805 );
|
rlm@1
|
806 UInt64 dataStartPos = baseOffset + dataOffset;
|
rlm@1
|
807 for (int i = 0; i < folders.Size(); i++)
|
rlm@1
|
808 {
|
rlm@1
|
809 const CFolder &folder = folders[i];
|
rlm@1
|
810 dataVector.Add(CByteBuffer());
|
rlm@1
|
811 CByteBuffer &data = dataVector.Back();
|
rlm@1
|
812 UInt64 unpackSize64 = folder.GetUnpackSize();
|
rlm@1
|
813 size_t unpackSize = (size_t)unpackSize64;
|
rlm@1
|
814 if (unpackSize != unpackSize64)
|
rlm@1
|
815 ThrowUnsupported();
|
rlm@1
|
816 data.SetCapacity(unpackSize);
|
rlm@1
|
817
|
rlm@1
|
818 CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2;
|
rlm@1
|
819 CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
|
rlm@1
|
820 outStreamSpec->Init(data, unpackSize);
|
rlm@1
|
821
|
rlm@1
|
822 HRESULT result = decoder.Decode(
|
rlm@1
|
823 EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
824 _stream, dataStartPos,
|
rlm@1
|
825 &packSizes[packIndex], folder, outStream, NULL
|
rlm@1
|
826 #ifndef _NO_CRYPTO
|
rlm@1
|
827 , getTextPassword, passwordIsDefined
|
rlm@1
|
828 #endif
|
rlm@1
|
829 #ifdef COMPRESS_MT
|
rlm@1
|
830 , false, 1
|
rlm@1
|
831 #endif
|
rlm@1
|
832 );
|
rlm@1
|
833 RINOK(result);
|
rlm@1
|
834
|
rlm@1
|
835 if (folder.UnpackCRCDefined)
|
rlm@1
|
836 if (CrcCalc(data, unpackSize) != folder.UnpackCRC)
|
rlm@1
|
837 ThrowIncorrect();
|
rlm@1
|
838 for (int j = 0; j < folder.PackStreams.Size(); j++)
|
rlm@1
|
839 {
|
rlm@1
|
840 UInt64 packSize = packSizes[packIndex++];
|
rlm@1
|
841 dataStartPos += packSize;
|
rlm@1
|
842 HeadersSize += packSize;
|
rlm@1
|
843 }
|
rlm@1
|
844 }
|
rlm@1
|
845 return S_OK;
|
rlm@1
|
846 }
|
rlm@1
|
847
|
rlm@1
|
848 HRESULT CInArchive::ReadHeader(
|
rlm@1
|
849 DECL_EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
850 CArchiveDatabaseEx &db
|
rlm@1
|
851 #ifndef _NO_CRYPTO
|
rlm@1
|
852 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
|
rlm@1
|
853 #endif
|
rlm@1
|
854 )
|
rlm@1
|
855 {
|
rlm@1
|
856 UInt64 type = ReadID();
|
rlm@1
|
857
|
rlm@1
|
858 if (type == NID::kArchiveProperties)
|
rlm@1
|
859 {
|
rlm@1
|
860 ReadArchiveProperties(db.ArchiveInfo);
|
rlm@1
|
861 type = ReadID();
|
rlm@1
|
862 }
|
rlm@1
|
863
|
rlm@1
|
864 CObjectVector<CByteBuffer> dataVector;
|
rlm@1
|
865
|
rlm@1
|
866 if (type == NID::kAdditionalStreamsInfo)
|
rlm@1
|
867 {
|
rlm@1
|
868 HRESULT result = ReadAndDecodePackedStreams(
|
rlm@1
|
869 EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
870 db.ArchiveInfo.StartPositionAfterHeader,
|
rlm@1
|
871 db.ArchiveInfo.DataStartPosition2,
|
rlm@1
|
872 dataVector
|
rlm@1
|
873 #ifndef _NO_CRYPTO
|
rlm@1
|
874 , getTextPassword, passwordIsDefined
|
rlm@1
|
875 #endif
|
rlm@1
|
876 );
|
rlm@1
|
877 RINOK(result);
|
rlm@1
|
878 db.ArchiveInfo.DataStartPosition2 += db.ArchiveInfo.StartPositionAfterHeader;
|
rlm@1
|
879 type = ReadID();
|
rlm@1
|
880 }
|
rlm@1
|
881
|
rlm@1
|
882 CRecordVector<UInt64> unpackSizes;
|
rlm@1
|
883 CBoolVector digestsDefined;
|
rlm@1
|
884 CRecordVector<UInt32> digests;
|
rlm@1
|
885
|
rlm@1
|
886 if (type == NID::kMainStreamsInfo)
|
rlm@1
|
887 {
|
rlm@1
|
888 ReadStreamsInfo(&dataVector,
|
rlm@1
|
889 db.ArchiveInfo.DataStartPosition,
|
rlm@1
|
890 db.PackSizes,
|
rlm@1
|
891 db.PackCRCsDefined,
|
rlm@1
|
892 db.PackCRCs,
|
rlm@1
|
893 db.Folders,
|
rlm@1
|
894 db.NumUnpackStreamsVector,
|
rlm@1
|
895 unpackSizes,
|
rlm@1
|
896 digestsDefined,
|
rlm@1
|
897 digests);
|
rlm@1
|
898 db.ArchiveInfo.DataStartPosition += db.ArchiveInfo.StartPositionAfterHeader;
|
rlm@1
|
899 type = ReadID();
|
rlm@1
|
900 }
|
rlm@1
|
901 else
|
rlm@1
|
902 {
|
rlm@1
|
903 for (int i = 0; i < db.Folders.Size(); i++)
|
rlm@1
|
904 {
|
rlm@1
|
905 db.NumUnpackStreamsVector.Add(1);
|
rlm@1
|
906 CFolder &folder = db.Folders[i];
|
rlm@1
|
907 unpackSizes.Add(folder.GetUnpackSize());
|
rlm@1
|
908 digestsDefined.Add(folder.UnpackCRCDefined);
|
rlm@1
|
909 digests.Add(folder.UnpackCRC);
|
rlm@1
|
910 }
|
rlm@1
|
911 }
|
rlm@1
|
912
|
rlm@1
|
913 db.Files.Clear();
|
rlm@1
|
914
|
rlm@1
|
915 if (type == NID::kEnd)
|
rlm@1
|
916 return S_OK;
|
rlm@1
|
917 if (type != NID::kFilesInfo)
|
rlm@1
|
918 ThrowIncorrect();
|
rlm@1
|
919
|
rlm@1
|
920 CNum numFiles = ReadNum();
|
rlm@1
|
921 db.Files.Reserve(numFiles);
|
rlm@1
|
922 CNum i;
|
rlm@1
|
923 for (i = 0; i < numFiles; i++)
|
rlm@1
|
924 db.Files.Add(CFileItem());
|
rlm@1
|
925
|
rlm@1
|
926 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize);
|
rlm@1
|
927 if (!db.PackSizes.IsEmpty())
|
rlm@1
|
928 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo);
|
rlm@1
|
929 if (numFiles > 0 && !digests.IsEmpty())
|
rlm@1
|
930 db.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC);
|
rlm@1
|
931
|
rlm@1
|
932 CBoolVector emptyStreamVector;
|
rlm@1
|
933 BoolVector_Fill_False(emptyStreamVector, (int)numFiles);
|
rlm@1
|
934 CBoolVector emptyFileVector;
|
rlm@1
|
935 CBoolVector antiFileVector;
|
rlm@1
|
936 CNum numEmptyStreams = 0;
|
rlm@1
|
937
|
rlm@1
|
938 for (;;)
|
rlm@1
|
939 {
|
rlm@1
|
940 UInt64 type = ReadID();
|
rlm@1
|
941 if (type == NID::kEnd)
|
rlm@1
|
942 break;
|
rlm@1
|
943 UInt64 size = ReadNumber();
|
rlm@1
|
944 size_t ppp = _inByteBack->_pos;
|
rlm@1
|
945 bool addPropIdToList = true;
|
rlm@1
|
946 bool isKnownType = true;
|
rlm@1
|
947 if (type > ((UInt32)1 << 30))
|
rlm@1
|
948 isKnownType = false;
|
rlm@1
|
949 else switch((UInt32)type)
|
rlm@1
|
950 {
|
rlm@1
|
951 case NID::kName:
|
rlm@1
|
952 {
|
rlm@1
|
953 CStreamSwitch streamSwitch;
|
rlm@1
|
954 streamSwitch.Set(this, &dataVector);
|
rlm@1
|
955 for (int i = 0; i < db.Files.Size(); i++)
|
rlm@1
|
956 _inByteBack->ReadString(db.Files[i].Name);
|
rlm@1
|
957 break;
|
rlm@1
|
958 }
|
rlm@1
|
959 case NID::kWinAttributes:
|
rlm@1
|
960 {
|
rlm@1
|
961 CBoolVector boolVector;
|
rlm@1
|
962 ReadBoolVector2(db.Files.Size(), boolVector);
|
rlm@1
|
963 CStreamSwitch streamSwitch;
|
rlm@1
|
964 streamSwitch.Set(this, &dataVector);
|
rlm@1
|
965 for (i = 0; i < numFiles; i++)
|
rlm@1
|
966 {
|
rlm@1
|
967 CFileItem &file = db.Files[i];
|
rlm@1
|
968 file.AttribDefined = boolVector[i];
|
rlm@1
|
969 if (file.AttribDefined)
|
rlm@1
|
970 file.Attrib = ReadUInt32();
|
rlm@1
|
971 }
|
rlm@1
|
972 break;
|
rlm@1
|
973 }
|
rlm@1
|
974 case NID::kEmptyStream:
|
rlm@1
|
975 {
|
rlm@1
|
976 ReadBoolVector(numFiles, emptyStreamVector);
|
rlm@1
|
977 for (i = 0; i < (CNum)emptyStreamVector.Size(); i++)
|
rlm@1
|
978 if (emptyStreamVector[i])
|
rlm@1
|
979 numEmptyStreams++;
|
rlm@1
|
980
|
rlm@1
|
981 BoolVector_Fill_False(emptyFileVector, numEmptyStreams);
|
rlm@1
|
982 BoolVector_Fill_False(antiFileVector, numEmptyStreams);
|
rlm@1
|
983
|
rlm@1
|
984 break;
|
rlm@1
|
985 }
|
rlm@1
|
986 case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
|
rlm@1
|
987 case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
|
rlm@1
|
988 case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (int)numFiles); break;
|
rlm@1
|
989 case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (int)numFiles); break;
|
rlm@1
|
990 case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (int)numFiles); break;
|
rlm@1
|
991 case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (int)numFiles); break;
|
rlm@1
|
992 case NID::kDummy:
|
rlm@1
|
993 {
|
rlm@1
|
994 for (UInt64 j = 0; j < size; j++)
|
rlm@1
|
995 if (ReadByte() != 0)
|
rlm@1
|
996 ThrowIncorrect();
|
rlm@1
|
997 addPropIdToList = false;
|
rlm@1
|
998 break;
|
rlm@1
|
999 }
|
rlm@1
|
1000 default:
|
rlm@1
|
1001 addPropIdToList = isKnownType = false;
|
rlm@1
|
1002 }
|
rlm@1
|
1003 if (isKnownType)
|
rlm@1
|
1004 {
|
rlm@1
|
1005 if(addPropIdToList)
|
rlm@1
|
1006 db.ArchiveInfo.FileInfoPopIDs.Add(type);
|
rlm@1
|
1007 }
|
rlm@1
|
1008 else
|
rlm@1
|
1009 SkeepData(size);
|
rlm@1
|
1010 bool checkRecordsSize = (db.ArchiveInfo.Version.Major > 0 ||
|
rlm@1
|
1011 db.ArchiveInfo.Version.Minor > 2);
|
rlm@1
|
1012 if (checkRecordsSize && _inByteBack->_pos - ppp != size)
|
rlm@1
|
1013 ThrowIncorrect();
|
rlm@1
|
1014 }
|
rlm@1
|
1015
|
rlm@1
|
1016 CNum emptyFileIndex = 0;
|
rlm@1
|
1017 CNum sizeIndex = 0;
|
rlm@1
|
1018
|
rlm@1
|
1019 CNum numAntiItems = 0;
|
rlm@1
|
1020 for (i = 0; i < numEmptyStreams; i++)
|
rlm@1
|
1021 if (antiFileVector[i])
|
rlm@1
|
1022 numAntiItems++;
|
rlm@1
|
1023
|
rlm@1
|
1024 for (i = 0; i < numFiles; i++)
|
rlm@1
|
1025 {
|
rlm@1
|
1026 CFileItem &file = db.Files[i];
|
rlm@1
|
1027 bool isAnti;
|
rlm@1
|
1028 file.HasStream = !emptyStreamVector[i];
|
rlm@1
|
1029 if (file.HasStream)
|
rlm@1
|
1030 {
|
rlm@1
|
1031 file.IsDir = false;
|
rlm@1
|
1032 isAnti = false;
|
rlm@1
|
1033 file.Size = unpackSizes[sizeIndex];
|
rlm@1
|
1034 file.Crc = digests[sizeIndex];
|
rlm@1
|
1035 file.CrcDefined = digestsDefined[sizeIndex];
|
rlm@1
|
1036 sizeIndex++;
|
rlm@1
|
1037 }
|
rlm@1
|
1038 else
|
rlm@1
|
1039 {
|
rlm@1
|
1040 file.IsDir = !emptyFileVector[emptyFileIndex];
|
rlm@1
|
1041 isAnti = antiFileVector[emptyFileIndex];
|
rlm@1
|
1042 emptyFileIndex++;
|
rlm@1
|
1043 file.Size = 0;
|
rlm@1
|
1044 file.CrcDefined = false;
|
rlm@1
|
1045 }
|
rlm@1
|
1046 if (numAntiItems != 0)
|
rlm@1
|
1047 db.IsAnti.Add(isAnti);
|
rlm@1
|
1048 }
|
rlm@1
|
1049 return S_OK;
|
rlm@1
|
1050 }
|
rlm@1
|
1051
|
rlm@1
|
1052
|
rlm@1
|
1053 void CArchiveDatabaseEx::FillFolderStartPackStream()
|
rlm@1
|
1054 {
|
rlm@1
|
1055 FolderStartPackStreamIndex.Clear();
|
rlm@1
|
1056 FolderStartPackStreamIndex.Reserve(Folders.Size());
|
rlm@1
|
1057 CNum startPos = 0;
|
rlm@1
|
1058 for (int i = 0; i < Folders.Size(); i++)
|
rlm@1
|
1059 {
|
rlm@1
|
1060 FolderStartPackStreamIndex.Add(startPos);
|
rlm@1
|
1061 startPos += (CNum)Folders[i].PackStreams.Size();
|
rlm@1
|
1062 }
|
rlm@1
|
1063 }
|
rlm@1
|
1064
|
rlm@1
|
1065 void CArchiveDatabaseEx::FillStartPos()
|
rlm@1
|
1066 {
|
rlm@1
|
1067 PackStreamStartPositions.Clear();
|
rlm@1
|
1068 PackStreamStartPositions.Reserve(PackSizes.Size());
|
rlm@1
|
1069 UInt64 startPos = 0;
|
rlm@1
|
1070 for (int i = 0; i < PackSizes.Size(); i++)
|
rlm@1
|
1071 {
|
rlm@1
|
1072 PackStreamStartPositions.Add(startPos);
|
rlm@1
|
1073 startPos += PackSizes[i];
|
rlm@1
|
1074 }
|
rlm@1
|
1075 }
|
rlm@1
|
1076
|
rlm@1
|
1077 void CArchiveDatabaseEx::FillFolderStartFileIndex()
|
rlm@1
|
1078 {
|
rlm@1
|
1079 FolderStartFileIndex.Clear();
|
rlm@1
|
1080 FolderStartFileIndex.Reserve(Folders.Size());
|
rlm@1
|
1081 FileIndexToFolderIndexMap.Clear();
|
rlm@1
|
1082 FileIndexToFolderIndexMap.Reserve(Files.Size());
|
rlm@1
|
1083
|
rlm@1
|
1084 int folderIndex = 0;
|
rlm@1
|
1085 CNum indexInFolder = 0;
|
rlm@1
|
1086 for (int i = 0; i < Files.Size(); i++)
|
rlm@1
|
1087 {
|
rlm@1
|
1088 const CFileItem &file = Files[i];
|
rlm@1
|
1089 bool emptyStream = !file.HasStream;
|
rlm@1
|
1090 if (emptyStream && indexInFolder == 0)
|
rlm@1
|
1091 {
|
rlm@1
|
1092 FileIndexToFolderIndexMap.Add(kNumNoIndex);
|
rlm@1
|
1093 continue;
|
rlm@1
|
1094 }
|
rlm@1
|
1095 if (indexInFolder == 0)
|
rlm@1
|
1096 {
|
rlm@1
|
1097 // v3.13 incorrectly worked with empty folders
|
rlm@1
|
1098 // v4.07: Loop for skipping empty folders
|
rlm@1
|
1099 for (;;)
|
rlm@1
|
1100 {
|
rlm@1
|
1101 if (folderIndex >= Folders.Size())
|
rlm@1
|
1102 ThrowIncorrect();
|
rlm@1
|
1103 FolderStartFileIndex.Add(i); // check it
|
rlm@1
|
1104 if (NumUnpackStreamsVector[folderIndex] != 0)
|
rlm@1
|
1105 break;
|
rlm@1
|
1106 folderIndex++;
|
rlm@1
|
1107 }
|
rlm@1
|
1108 }
|
rlm@1
|
1109 FileIndexToFolderIndexMap.Add(folderIndex);
|
rlm@1
|
1110 if (emptyStream)
|
rlm@1
|
1111 continue;
|
rlm@1
|
1112 indexInFolder++;
|
rlm@1
|
1113 if (indexInFolder >= NumUnpackStreamsVector[folderIndex])
|
rlm@1
|
1114 {
|
rlm@1
|
1115 folderIndex++;
|
rlm@1
|
1116 indexInFolder = 0;
|
rlm@1
|
1117 }
|
rlm@1
|
1118 }
|
rlm@1
|
1119 }
|
rlm@1
|
1120
|
rlm@1
|
1121 HRESULT CInArchive::ReadDatabase2(
|
rlm@1
|
1122 DECL_EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
1123 CArchiveDatabaseEx &db
|
rlm@1
|
1124 #ifndef _NO_CRYPTO
|
rlm@1
|
1125 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
|
rlm@1
|
1126 #endif
|
rlm@1
|
1127 )
|
rlm@1
|
1128 {
|
rlm@1
|
1129 db.Clear();
|
rlm@1
|
1130 db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
|
rlm@1
|
1131
|
rlm@1
|
1132 db.ArchiveInfo.Version.Major = _header[6];
|
rlm@1
|
1133 db.ArchiveInfo.Version.Minor = _header[7];
|
rlm@1
|
1134
|
rlm@1
|
1135 if (db.ArchiveInfo.Version.Major != kMajorVersion)
|
rlm@1
|
1136 ThrowUnsupportedVersion();
|
rlm@1
|
1137
|
rlm@1
|
1138 UInt32 crcFromArchive = Get32(_header + 8);
|
rlm@1
|
1139 UInt64 nextHeaderOffset = Get64(_header + 0xC);
|
rlm@1
|
1140 UInt64 nextHeaderSize = Get64(_header + 0x14);
|
rlm@1
|
1141 UInt32 nextHeaderCRC = Get32(_header + 0x1C);
|
rlm@1
|
1142 UInt32 crc = CrcCalc(_header + 0xC, 20);
|
rlm@1
|
1143
|
rlm@1
|
1144 #ifdef FORMAT_7Z_RECOVERY
|
rlm@1
|
1145 if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
|
rlm@1
|
1146 {
|
rlm@1
|
1147 UInt64 cur, cur2;
|
rlm@1
|
1148 RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
|
rlm@1
|
1149 const int kCheckSize = 500;
|
rlm@1
|
1150 Byte buf[kCheckSize];
|
rlm@1
|
1151 RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
|
rlm@1
|
1152 int checkSize = kCheckSize;
|
rlm@1
|
1153 if (cur2 - cur < kCheckSize)
|
rlm@1
|
1154 checkSize = (int)(cur2 - cur);
|
rlm@1
|
1155 RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));
|
rlm@1
|
1156
|
rlm@1
|
1157 RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));
|
rlm@1
|
1158
|
rlm@1
|
1159 int i;
|
rlm@1
|
1160 for (i = (int)checkSize - 2; i >= 0; i--)
|
rlm@1
|
1161 if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
|
rlm@1
|
1162 break;
|
rlm@1
|
1163 if (i < 0)
|
rlm@1
|
1164 return S_FALSE;
|
rlm@1
|
1165 nextHeaderSize = checkSize - i;
|
rlm@1
|
1166 nextHeaderOffset = cur2 - cur + i;
|
rlm@1
|
1167 nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
|
rlm@1
|
1168 RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
|
rlm@1
|
1169 }
|
rlm@1
|
1170 #endif
|
rlm@1
|
1171
|
rlm@1
|
1172 #ifdef FORMAT_7Z_RECOVERY
|
rlm@1
|
1173 crcFromArchive = crc;
|
rlm@1
|
1174 #endif
|
rlm@1
|
1175
|
rlm@1
|
1176 db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
|
rlm@1
|
1177
|
rlm@1
|
1178 if (crc != crcFromArchive)
|
rlm@1
|
1179 ThrowIncorrect();
|
rlm@1
|
1180
|
rlm@1
|
1181 if (nextHeaderSize == 0)
|
rlm@1
|
1182 return S_OK;
|
rlm@1
|
1183
|
rlm@1
|
1184 if (nextHeaderSize > (UInt64)0xFFFFFFFF)
|
rlm@1
|
1185 return S_FALSE;
|
rlm@1
|
1186
|
rlm@1
|
1187 RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
|
rlm@1
|
1188
|
rlm@1
|
1189 CByteBuffer buffer2;
|
rlm@1
|
1190 buffer2.SetCapacity((size_t)nextHeaderSize);
|
rlm@1
|
1191
|
rlm@1
|
1192 RINOK(ReadStream_FALSE(_stream, buffer2, (size_t)nextHeaderSize));
|
rlm@1
|
1193 HeadersSize += kHeaderSize + nextHeaderSize;
|
rlm@1
|
1194 db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
|
rlm@1
|
1195
|
rlm@1
|
1196 if (CrcCalc(buffer2, (UInt32)nextHeaderSize) != nextHeaderCRC)
|
rlm@1
|
1197 ThrowIncorrect();
|
rlm@1
|
1198
|
rlm@1
|
1199 CStreamSwitch streamSwitch;
|
rlm@1
|
1200 streamSwitch.Set(this, buffer2);
|
rlm@1
|
1201
|
rlm@1
|
1202 CObjectVector<CByteBuffer> dataVector;
|
rlm@1
|
1203
|
rlm@1
|
1204 UInt64 type = ReadID();
|
rlm@1
|
1205 if (type != NID::kHeader)
|
rlm@1
|
1206 {
|
rlm@1
|
1207 if (type != NID::kEncodedHeader)
|
rlm@1
|
1208 ThrowIncorrect();
|
rlm@1
|
1209 HRESULT result = ReadAndDecodePackedStreams(
|
rlm@1
|
1210 EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
1211 db.ArchiveInfo.StartPositionAfterHeader,
|
rlm@1
|
1212 db.ArchiveInfo.DataStartPosition2,
|
rlm@1
|
1213 dataVector
|
rlm@1
|
1214 #ifndef _NO_CRYPTO
|
rlm@1
|
1215 , getTextPassword, passwordIsDefined
|
rlm@1
|
1216 #endif
|
rlm@1
|
1217 );
|
rlm@1
|
1218 RINOK(result);
|
rlm@1
|
1219 if (dataVector.Size() == 0)
|
rlm@1
|
1220 return S_OK;
|
rlm@1
|
1221 if (dataVector.Size() > 1)
|
rlm@1
|
1222 ThrowIncorrect();
|
rlm@1
|
1223 streamSwitch.Remove();
|
rlm@1
|
1224 streamSwitch.Set(this, dataVector.Front());
|
rlm@1
|
1225 if (ReadID() != NID::kHeader)
|
rlm@1
|
1226 ThrowIncorrect();
|
rlm@1
|
1227 }
|
rlm@1
|
1228
|
rlm@1
|
1229 db.HeadersSize = HeadersSize;
|
rlm@1
|
1230
|
rlm@1
|
1231 return ReadHeader(
|
rlm@1
|
1232 EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
1233 db
|
rlm@1
|
1234 #ifndef _NO_CRYPTO
|
rlm@1
|
1235 , getTextPassword, passwordIsDefined
|
rlm@1
|
1236 #endif
|
rlm@1
|
1237 );
|
rlm@1
|
1238 }
|
rlm@1
|
1239
|
rlm@1
|
1240 HRESULT CInArchive::ReadDatabase(
|
rlm@1
|
1241 DECL_EXTERNAL_CODECS_LOC_VARS
|
rlm@1
|
1242 CArchiveDatabaseEx &db
|
rlm@1
|
1243 #ifndef _NO_CRYPTO
|
rlm@1
|
1244 , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
|
rlm@1
|
1245 #endif
|
rlm@1
|
1246 )
|
rlm@1
|
1247 {
|
rlm@1
|
1248 try
|
rlm@1
|
1249 {
|
rlm@1
|
1250 return ReadDatabase2(
|
rlm@1
|
1251 EXTERNAL_CODECS_LOC_VARS db
|
rlm@1
|
1252 #ifndef _NO_CRYPTO
|
rlm@1
|
1253 , getTextPassword, passwordIsDefined
|
rlm@1
|
1254 #endif
|
rlm@1
|
1255 );
|
rlm@1
|
1256 }
|
rlm@1
|
1257 catch(CInArchiveException &) { return S_FALSE; }
|
rlm@1
|
1258 }
|
rlm@1
|
1259
|
rlm@1
|
1260 }}
|