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