7zIn.cpp 30 KB

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