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