ArchiveReader.cs 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Linq;
  6. using SharpCompress.Compressors.LZMA;
  7. using SharpCompress.Compressors.LZMA.Utilites;
  8. using SharpCompress.IO;
  9. namespace SharpCompress.Common.SevenZip
  10. {
  11. internal class ArchiveReader
  12. {
  13. internal Stream _stream;
  14. internal Stack<DataReader> _readerStack = new Stack<DataReader>();
  15. internal DataReader _currentReader;
  16. internal long _streamOrigin;
  17. internal long _streamEnding;
  18. internal byte[] _header;
  19. private readonly Dictionary<int, Stream> _cachedStreams = new Dictionary<int, Stream>();
  20. internal void AddByteStream(byte[] buffer, int offset, int length)
  21. {
  22. _readerStack.Push(_currentReader);
  23. _currentReader = new DataReader(buffer, offset, length);
  24. }
  25. internal void DeleteByteStream()
  26. {
  27. _currentReader = _readerStack.Pop();
  28. }
  29. #region Private Methods - Data Reader
  30. internal Byte ReadByte()
  31. {
  32. return _currentReader.ReadByte();
  33. }
  34. private void ReadBytes(byte[] buffer, int offset, int length)
  35. {
  36. _currentReader.ReadBytes(buffer, offset, length);
  37. }
  38. private ulong ReadNumber()
  39. {
  40. return _currentReader.ReadNumber();
  41. }
  42. internal int ReadNum()
  43. {
  44. return _currentReader.ReadNum();
  45. }
  46. private uint ReadUInt32()
  47. {
  48. return _currentReader.ReadUInt32();
  49. }
  50. private ulong ReadUInt64()
  51. {
  52. return _currentReader.ReadUInt64();
  53. }
  54. private BlockType? ReadId()
  55. {
  56. ulong id = _currentReader.ReadNumber();
  57. if (id > 25)
  58. {
  59. return null;
  60. }
  61. #if DEBUG
  62. Log.WriteLine("ReadId: {0}", (BlockType)id);
  63. #endif
  64. return (BlockType)id;
  65. }
  66. private void SkipData(long size)
  67. {
  68. _currentReader.SkipData(size);
  69. }
  70. private void SkipData()
  71. {
  72. _currentReader.SkipData();
  73. }
  74. private void WaitAttribute(BlockType attribute)
  75. {
  76. for (;;)
  77. {
  78. BlockType? type = ReadId();
  79. if (type == attribute)
  80. {
  81. return;
  82. }
  83. if (type == BlockType.End)
  84. {
  85. throw new InvalidOperationException();
  86. }
  87. SkipData();
  88. }
  89. }
  90. private void ReadArchiveProperties()
  91. {
  92. while (ReadId() != BlockType.End)
  93. {
  94. SkipData();
  95. }
  96. }
  97. #endregion
  98. #region Private Methods - Reader Utilities
  99. private BitVector ReadBitVector(int length)
  100. {
  101. var bits = new BitVector(length);
  102. byte data = 0;
  103. byte mask = 0;
  104. for (int i = 0; i < length; i++)
  105. {
  106. if (mask == 0)
  107. {
  108. data = ReadByte();
  109. mask = 0x80;
  110. }
  111. if ((data & mask) != 0)
  112. {
  113. bits.SetBit(i);
  114. }
  115. mask >>= 1;
  116. }
  117. return bits;
  118. }
  119. private BitVector ReadOptionalBitVector(int length)
  120. {
  121. byte allTrue = ReadByte();
  122. if (allTrue != 0)
  123. {
  124. return new BitVector(length, true);
  125. }
  126. return ReadBitVector(length);
  127. }
  128. private void ReadNumberVector(List<byte[]> dataVector, int numFiles, Action<int, long?> action)
  129. {
  130. var defined = ReadOptionalBitVector(numFiles);
  131. using (CStreamSwitch streamSwitch = new CStreamSwitch())
  132. {
  133. streamSwitch.Set(this, dataVector);
  134. for (int i = 0; i < numFiles; i++)
  135. {
  136. if (defined[i])
  137. {
  138. action(i, checked((long)ReadUInt64()));
  139. }
  140. else
  141. {
  142. action(i, null);
  143. }
  144. }
  145. }
  146. }
  147. private DateTime TranslateTime(long time)
  148. {
  149. // FILETIME = 100-nanosecond intervals since January 1, 1601 (UTC)
  150. return DateTime.FromFileTimeUtc(time).ToLocalTime();
  151. }
  152. private DateTime? TranslateTime(long? time)
  153. {
  154. if (time.HasValue && time.Value >= 0 && time.Value <= 2650467743999999999) //maximum Windows file time 31.12.9999
  155. {
  156. return TranslateTime(time.Value);
  157. }
  158. return null;
  159. }
  160. private void ReadDateTimeVector(List<byte[]> dataVector, int numFiles, Action<int, DateTime?> action)
  161. {
  162. ReadNumberVector(dataVector, numFiles, (index, value) => action(index, TranslateTime(value)));
  163. }
  164. private void ReadAttributeVector(List<byte[]> dataVector, int numFiles, Action<int, uint?> action)
  165. {
  166. BitVector boolVector = ReadOptionalBitVector(numFiles);
  167. using (var streamSwitch = new CStreamSwitch())
  168. {
  169. streamSwitch.Set(this, dataVector);
  170. for (int i = 0; i < numFiles; i++)
  171. {
  172. if (boolVector[i])
  173. {
  174. action(i, ReadUInt32());
  175. }
  176. else
  177. {
  178. action(i, null);
  179. }
  180. }
  181. }
  182. }
  183. #endregion
  184. #region Private Methods
  185. private void GetNextFolderItem(CFolder folder)
  186. {
  187. #if DEBUG
  188. Log.WriteLine("-- GetNextFolderItem --");
  189. Log.PushIndent();
  190. #endif
  191. try
  192. {
  193. int numCoders = ReadNum();
  194. #if DEBUG
  195. Log.WriteLine("NumCoders: " + numCoders);
  196. #endif
  197. folder._coders = new List<CCoderInfo>(numCoders);
  198. int numInStreams = 0;
  199. int numOutStreams = 0;
  200. for (int i = 0; i < numCoders; i++)
  201. {
  202. #if DEBUG
  203. Log.WriteLine("-- Coder --");
  204. Log.PushIndent();
  205. #endif
  206. try
  207. {
  208. CCoderInfo coder = new CCoderInfo();
  209. folder._coders.Add(coder);
  210. byte mainByte = ReadByte();
  211. int idSize = (mainByte & 0xF);
  212. byte[] longId = new byte[idSize];
  213. ReadBytes(longId, 0, idSize);
  214. #if DEBUG
  215. Log.WriteLine("MethodId: " + String.Join("", Enumerable.Range(0, idSize).Select(x => longId[x].ToString("x2")).ToArray()));
  216. #endif
  217. if (idSize > 8)
  218. {
  219. throw new NotSupportedException();
  220. }
  221. ulong id = 0;
  222. for (int j = 0; j < idSize; j++)
  223. {
  224. id |= (ulong)longId[idSize - 1 - j] << (8 * j);
  225. }
  226. coder._methodId = new CMethodId(id);
  227. if ((mainByte & 0x10) != 0)
  228. {
  229. coder._numInStreams = ReadNum();
  230. coder._numOutStreams = ReadNum();
  231. #if DEBUG
  232. Log.WriteLine("Complex Stream (In: " + coder._numInStreams + " - Out: " + coder._numOutStreams + ")");
  233. #endif
  234. }
  235. else
  236. {
  237. #if DEBUG
  238. Log.WriteLine("Simple Stream (In: 1 - Out: 1)");
  239. #endif
  240. coder._numInStreams = 1;
  241. coder._numOutStreams = 1;
  242. }
  243. if ((mainByte & 0x20) != 0)
  244. {
  245. int propsSize = ReadNum();
  246. coder._props = new byte[propsSize];
  247. ReadBytes(coder._props, 0, propsSize);
  248. #if DEBUG
  249. Log.WriteLine("Settings: " + String.Join("", coder._props.Select(bt => bt.ToString("x2")).ToArray()));
  250. #endif
  251. }
  252. if ((mainByte & 0x80) != 0)
  253. {
  254. throw new NotSupportedException();
  255. }
  256. numInStreams += coder._numInStreams;
  257. numOutStreams += coder._numOutStreams;
  258. }
  259. finally
  260. {
  261. #if DEBUG
  262. Log.PopIndent();
  263. #endif
  264. }
  265. }
  266. int numBindPairs = numOutStreams - 1;
  267. folder._bindPairs = new List<CBindPair>(numBindPairs);
  268. #if DEBUG
  269. Log.WriteLine("BindPairs: " + numBindPairs);
  270. Log.PushIndent();
  271. #endif
  272. for (int i = 0; i < numBindPairs; i++)
  273. {
  274. CBindPair bp = new CBindPair();
  275. bp._inIndex = ReadNum();
  276. bp._outIndex = ReadNum();
  277. folder._bindPairs.Add(bp);
  278. #if DEBUG
  279. Log.WriteLine("#" + i + " - In: " + bp._inIndex + " - Out: " + bp._outIndex);
  280. #endif
  281. }
  282. #if DEBUG
  283. Log.PopIndent();
  284. #endif
  285. if (numInStreams < numBindPairs)
  286. {
  287. throw new NotSupportedException();
  288. }
  289. int numPackStreams = numInStreams - numBindPairs;
  290. //folder.PackStreams.Reserve(numPackStreams);
  291. if (numPackStreams == 1)
  292. {
  293. for (int i = 0; i < numInStreams; i++)
  294. {
  295. if (folder.FindBindPairForInStream(i) < 0)
  296. {
  297. #if DEBUG
  298. Log.WriteLine("Single PackStream: #" + i);
  299. #endif
  300. folder._packStreams.Add(i);
  301. break;
  302. }
  303. }
  304. if (folder._packStreams.Count != 1)
  305. {
  306. throw new NotSupportedException();
  307. }
  308. }
  309. else
  310. {
  311. #if DEBUG
  312. Log.WriteLine("Multiple PackStreams ...");
  313. Log.PushIndent();
  314. #endif
  315. for (int i = 0; i < numPackStreams; i++)
  316. {
  317. var num = ReadNum();
  318. #if DEBUG
  319. Log.WriteLine("#" + i + " - " + num);
  320. #endif
  321. folder._packStreams.Add(num);
  322. }
  323. #if DEBUG
  324. Log.PopIndent();
  325. #endif
  326. }
  327. }
  328. finally
  329. {
  330. #if DEBUG
  331. Log.PopIndent();
  332. #endif
  333. }
  334. }
  335. private List<uint?> ReadHashDigests(int count)
  336. {
  337. #if DEBUG
  338. Log.Write("ReadHashDigests:");
  339. #endif
  340. var defined = ReadOptionalBitVector(count);
  341. var digests = new List<uint?>(count);
  342. for (int i = 0; i < count; i++)
  343. {
  344. if (defined[i])
  345. {
  346. uint crc = ReadUInt32();
  347. #if DEBUG
  348. Log.Write(" " + crc.ToString("x8"));
  349. #endif
  350. digests.Add(crc);
  351. }
  352. else
  353. {
  354. #if DEBUG
  355. Log.Write(" ########");
  356. #endif
  357. digests.Add(null);
  358. }
  359. }
  360. #if DEBUG
  361. Log.WriteLine();
  362. #endif
  363. return digests;
  364. }
  365. private void ReadPackInfo(out long dataOffset, out List<long> packSizes, out List<uint?> packCrCs)
  366. {
  367. #if DEBUG
  368. Log.WriteLine("-- ReadPackInfo --");
  369. Log.PushIndent();
  370. #endif
  371. try
  372. {
  373. packCrCs = null;
  374. dataOffset = checked((long)ReadNumber());
  375. #if DEBUG
  376. Log.WriteLine("DataOffset: " + dataOffset);
  377. #endif
  378. int numPackStreams = ReadNum();
  379. #if DEBUG
  380. Log.WriteLine("NumPackStreams: " + numPackStreams);
  381. #endif
  382. WaitAttribute(BlockType.Size);
  383. packSizes = new List<long>(numPackStreams);
  384. #if DEBUG
  385. Log.Write("Sizes:");
  386. #endif
  387. for (int i = 0; i < numPackStreams; i++)
  388. {
  389. var size = checked((long)ReadNumber());
  390. #if DEBUG
  391. Log.Write(" " + size);
  392. #endif
  393. packSizes.Add(size);
  394. }
  395. #if DEBUG
  396. Log.WriteLine();
  397. #endif
  398. BlockType? type;
  399. for (;;)
  400. {
  401. type = ReadId();
  402. if (type == BlockType.End)
  403. {
  404. break;
  405. }
  406. if (type == BlockType.Crc)
  407. {
  408. packCrCs = ReadHashDigests(numPackStreams);
  409. continue;
  410. }
  411. SkipData();
  412. }
  413. if (packCrCs == null)
  414. {
  415. packCrCs = new List<uint?>(numPackStreams);
  416. for (int i = 0; i < numPackStreams; i++)
  417. {
  418. packCrCs.Add(null);
  419. }
  420. }
  421. }
  422. finally
  423. {
  424. #if DEBUG
  425. Log.PopIndent();
  426. #endif
  427. }
  428. }
  429. private void ReadUnpackInfo(List<byte[]> dataVector, out List<CFolder> folders)
  430. {
  431. #if DEBUG
  432. Log.WriteLine("-- ReadUnpackInfo --");
  433. Log.PushIndent();
  434. #endif
  435. try
  436. {
  437. WaitAttribute(BlockType.Folder);
  438. int numFolders = ReadNum();
  439. #if DEBUG
  440. Log.WriteLine("NumFolders: {0}", numFolders);
  441. #endif
  442. using (CStreamSwitch streamSwitch = new CStreamSwitch())
  443. {
  444. streamSwitch.Set(this, dataVector);
  445. //folders.Clear();
  446. //folders.Reserve(numFolders);
  447. folders = new List<CFolder>(numFolders);
  448. int index = 0;
  449. for (int i = 0; i < numFolders; i++)
  450. {
  451. var f = new CFolder {_firstPackStreamId = index};
  452. folders.Add(f);
  453. GetNextFolderItem(f);
  454. index += f._packStreams.Count;
  455. }
  456. }
  457. WaitAttribute(BlockType.CodersUnpackSize);
  458. #if DEBUG
  459. Log.WriteLine("UnpackSizes:");
  460. #endif
  461. for (int i = 0; i < numFolders; i++)
  462. {
  463. CFolder folder = folders[i];
  464. #if DEBUG
  465. Log.Write(" #" + i + ":");
  466. #endif
  467. int numOutStreams = folder.GetNumOutStreams();
  468. for (int j = 0; j < numOutStreams; j++)
  469. {
  470. long size = checked((long)ReadNumber());
  471. #if DEBUG
  472. Log.Write(" " + size);
  473. #endif
  474. folder._unpackSizes.Add(size);
  475. }
  476. #if DEBUG
  477. Log.WriteLine();
  478. #endif
  479. }
  480. for (;;)
  481. {
  482. BlockType? type = ReadId();
  483. if (type == BlockType.End)
  484. {
  485. return;
  486. }
  487. if (type == BlockType.Crc)
  488. {
  489. List<uint?> crcs = ReadHashDigests(numFolders);
  490. for (int i = 0; i < numFolders; i++)
  491. {
  492. folders[i]._unpackCrc = crcs[i];
  493. }
  494. continue;
  495. }
  496. SkipData();
  497. }
  498. }
  499. finally
  500. {
  501. #if DEBUG
  502. Log.PopIndent();
  503. #endif
  504. }
  505. }
  506. private void ReadSubStreamsInfo(List<CFolder> folders, out List<int> numUnpackStreamsInFolders,
  507. out List<long> unpackSizes, out List<uint?> digests)
  508. {
  509. #if DEBUG
  510. Log.WriteLine("-- ReadSubStreamsInfo --");
  511. Log.PushIndent();
  512. #endif
  513. try
  514. {
  515. numUnpackStreamsInFolders = null;
  516. BlockType? type;
  517. for (;;)
  518. {
  519. type = ReadId();
  520. if (type == BlockType.NumUnpackStream)
  521. {
  522. numUnpackStreamsInFolders = new List<int>(folders.Count);
  523. #if DEBUG
  524. Log.Write("NumUnpackStreams:");
  525. #endif
  526. for (int i = 0; i < folders.Count; i++)
  527. {
  528. var num = ReadNum();
  529. #if DEBUG
  530. Log.Write(" " + num);
  531. #endif
  532. numUnpackStreamsInFolders.Add(num);
  533. }
  534. #if DEBUG
  535. Log.WriteLine();
  536. #endif
  537. continue;
  538. }
  539. if (type == BlockType.Crc || type == BlockType.Size)
  540. {
  541. break;
  542. }
  543. if (type == BlockType.End)
  544. {
  545. break;
  546. }
  547. SkipData();
  548. }
  549. if (numUnpackStreamsInFolders == null)
  550. {
  551. numUnpackStreamsInFolders = new List<int>(folders.Count);
  552. for (int i = 0; i < folders.Count; i++)
  553. {
  554. numUnpackStreamsInFolders.Add(1);
  555. }
  556. }
  557. unpackSizes = new List<long>(folders.Count);
  558. for (int i = 0; i < numUnpackStreamsInFolders.Count; i++)
  559. {
  560. // v3.13 incorrectly worked with empty folders
  561. // v4.07: we check that folder is empty
  562. int numSubstreams = numUnpackStreamsInFolders[i];
  563. if (numSubstreams == 0)
  564. {
  565. continue;
  566. }
  567. #if DEBUG
  568. Log.Write("#{0} StreamSizes:", i);
  569. #endif
  570. long sum = 0;
  571. for (int j = 1; j < numSubstreams; j++)
  572. {
  573. if (type == BlockType.Size)
  574. {
  575. long size = checked((long)ReadNumber());
  576. #if DEBUG
  577. Log.Write(" " + size);
  578. #endif
  579. unpackSizes.Add(size);
  580. sum += size;
  581. }
  582. }
  583. unpackSizes.Add(folders[i].GetUnpackSize() - sum);
  584. #if DEBUG
  585. Log.WriteLine(" - rest: " + unpackSizes.Last());
  586. #endif
  587. }
  588. if (type == BlockType.Size)
  589. {
  590. type = ReadId();
  591. }
  592. int numDigests = 0;
  593. int numDigestsTotal = 0;
  594. for (int i = 0; i < folders.Count; i++)
  595. {
  596. int numSubstreams = numUnpackStreamsInFolders[i];
  597. if (numSubstreams != 1 || !folders[i].UnpackCrcDefined)
  598. {
  599. numDigests += numSubstreams;
  600. }
  601. numDigestsTotal += numSubstreams;
  602. }
  603. digests = null;
  604. for (;;)
  605. {
  606. if (type == BlockType.Crc)
  607. {
  608. digests = new List<uint?>(numDigestsTotal);
  609. List<uint?> digests2 = ReadHashDigests(numDigests);
  610. int digestIndex = 0;
  611. for (int i = 0; i < folders.Count; i++)
  612. {
  613. int numSubstreams = numUnpackStreamsInFolders[i];
  614. CFolder folder = folders[i];
  615. if (numSubstreams == 1 && folder.UnpackCrcDefined)
  616. {
  617. digests.Add(folder._unpackCrc.Value);
  618. }
  619. else
  620. {
  621. for (int j = 0; j < numSubstreams; j++, digestIndex++)
  622. {
  623. digests.Add(digests2[digestIndex]);
  624. }
  625. }
  626. }
  627. if (digestIndex != numDigests || numDigestsTotal != digests.Count)
  628. {
  629. Debugger.Break();
  630. }
  631. }
  632. else if (type == BlockType.End)
  633. {
  634. if (digests == null)
  635. {
  636. digests = new List<uint?>(numDigestsTotal);
  637. for (int i = 0; i < numDigestsTotal; i++)
  638. {
  639. digests.Add(null);
  640. }
  641. }
  642. return;
  643. }
  644. else
  645. {
  646. SkipData();
  647. }
  648. type = ReadId();
  649. }
  650. }
  651. finally
  652. {
  653. #if DEBUG
  654. Log.PopIndent();
  655. #endif
  656. }
  657. }
  658. private void ReadStreamsInfo(
  659. List<byte[]> dataVector,
  660. out long dataOffset,
  661. out List<long> packSizes,
  662. out List<uint?> packCrCs,
  663. out List<CFolder> folders,
  664. out List<int> numUnpackStreamsInFolders,
  665. out List<long> unpackSizes,
  666. out List<uint?> digests)
  667. {
  668. #if DEBUG
  669. Log.WriteLine("-- ReadStreamsInfo --");
  670. Log.PushIndent();
  671. #endif
  672. try
  673. {
  674. dataOffset = long.MinValue;
  675. packSizes = null;
  676. packCrCs = null;
  677. folders = null;
  678. numUnpackStreamsInFolders = null;
  679. unpackSizes = null;
  680. digests = null;
  681. for (;;)
  682. {
  683. switch (ReadId())
  684. {
  685. case BlockType.End:
  686. return;
  687. case BlockType.PackInfo:
  688. ReadPackInfo(out dataOffset, out packSizes, out packCrCs);
  689. break;
  690. case BlockType.UnpackInfo:
  691. ReadUnpackInfo(dataVector, out folders);
  692. break;
  693. case BlockType.SubStreamsInfo:
  694. ReadSubStreamsInfo(folders, out numUnpackStreamsInFolders, out unpackSizes, out digests);
  695. break;
  696. default:
  697. throw new InvalidOperationException();
  698. }
  699. }
  700. }
  701. finally
  702. {
  703. #if DEBUG
  704. Log.PopIndent();
  705. #endif
  706. }
  707. }
  708. private List<byte[]> ReadAndDecodePackedStreams(long baseOffset, IPasswordProvider pass)
  709. {
  710. #if DEBUG
  711. Log.WriteLine("-- ReadAndDecodePackedStreams --");
  712. Log.PushIndent();
  713. #endif
  714. try
  715. {
  716. long dataStartPos;
  717. List<long> packSizes;
  718. List<uint?> packCrCs;
  719. List<CFolder> folders;
  720. List<int> numUnpackStreamsInFolders;
  721. List<long> unpackSizes;
  722. List<uint?> digests;
  723. ReadStreamsInfo(null,
  724. out dataStartPos,
  725. out packSizes,
  726. out packCrCs,
  727. out folders,
  728. out numUnpackStreamsInFolders,
  729. out unpackSizes,
  730. out digests);
  731. dataStartPos += baseOffset;
  732. var dataVector = new List<byte[]>(folders.Count);
  733. int packIndex = 0;
  734. foreach (var folder in folders)
  735. {
  736. long oldDataStartPos = dataStartPos;
  737. long[] myPackSizes = new long[folder._packStreams.Count];
  738. for (int i = 0; i < myPackSizes.Length; i++)
  739. {
  740. long packSize = packSizes[packIndex + i];
  741. myPackSizes[i] = packSize;
  742. dataStartPos += packSize;
  743. }
  744. var outStream = DecoderStreamHelper.CreateDecoderStream(_stream, oldDataStartPos, myPackSizes,
  745. folder, pass);
  746. int unpackSize = checked((int)folder.GetUnpackSize());
  747. byte[] data = new byte[unpackSize];
  748. outStream.ReadExact(data, 0, data.Length);
  749. if (outStream.ReadByte() >= 0)
  750. {
  751. throw new InvalidOperationException("Decoded stream is longer than expected.");
  752. }
  753. dataVector.Add(data);
  754. if (folder.UnpackCrcDefined)
  755. {
  756. if (Crc.Finish(Crc.Update(Crc.INIT_CRC, data, 0, unpackSize)) != folder._unpackCrc)
  757. {
  758. throw new InvalidOperationException("Decoded stream does not match expected CRC.");
  759. }
  760. }
  761. }
  762. return dataVector;
  763. }
  764. finally
  765. {
  766. #if DEBUG
  767. Log.PopIndent();
  768. #endif
  769. }
  770. }
  771. private void ReadHeader(ArchiveDatabase db, IPasswordProvider getTextPassword)
  772. {
  773. #if DEBUG
  774. Log.WriteLine("-- ReadHeader --");
  775. Log.PushIndent();
  776. #endif
  777. try
  778. {
  779. BlockType? type = ReadId();
  780. if (type == BlockType.ArchiveProperties)
  781. {
  782. ReadArchiveProperties();
  783. type = ReadId();
  784. }
  785. List<byte[]> dataVector = null;
  786. if (type == BlockType.AdditionalStreamsInfo)
  787. {
  788. dataVector = ReadAndDecodePackedStreams(db._startPositionAfterHeader, getTextPassword);
  789. type = ReadId();
  790. }
  791. List<long> unpackSizes;
  792. List<uint?> digests;
  793. if (type == BlockType.MainStreamsInfo)
  794. {
  795. ReadStreamsInfo(dataVector,
  796. out db._dataStartPosition,
  797. out db._packSizes,
  798. out db._packCrCs,
  799. out db._folders,
  800. out db._numUnpackStreamsVector,
  801. out unpackSizes,
  802. out digests);
  803. db._dataStartPosition += db._startPositionAfterHeader;
  804. type = ReadId();
  805. }
  806. else
  807. {
  808. unpackSizes = new List<long>(db._folders.Count);
  809. digests = new List<uint?>(db._folders.Count);
  810. db._numUnpackStreamsVector = new List<int>(db._folders.Count);
  811. for (int i = 0; i < db._folders.Count; i++)
  812. {
  813. var folder = db._folders[i];
  814. unpackSizes.Add(folder.GetUnpackSize());
  815. digests.Add(folder._unpackCrc);
  816. db._numUnpackStreamsVector.Add(1);
  817. }
  818. }
  819. db._files.Clear();
  820. if (type == BlockType.End)
  821. {
  822. return;
  823. }
  824. if (type != BlockType.FilesInfo)
  825. {
  826. throw new InvalidOperationException();
  827. }
  828. int numFiles = ReadNum();
  829. #if DEBUG
  830. Log.WriteLine("NumFiles: " + numFiles);
  831. #endif
  832. db._files = new List<CFileItem>(numFiles);
  833. for (int i = 0; i < numFiles; i++)
  834. {
  835. db._files.Add(new CFileItem());
  836. }
  837. BitVector emptyStreamVector = new BitVector(numFiles);
  838. BitVector emptyFileVector = null;
  839. BitVector antiFileVector = null;
  840. int numEmptyStreams = 0;
  841. for (;;)
  842. {
  843. type = ReadId();
  844. if (type == BlockType.End)
  845. {
  846. break;
  847. }
  848. long size = checked((long)ReadNumber()); // TODO: throw invalid data on negative
  849. int oldPos = _currentReader.Offset;
  850. switch (type)
  851. {
  852. case BlockType.Name:
  853. using (var streamSwitch = new CStreamSwitch())
  854. {
  855. streamSwitch.Set(this, dataVector);
  856. #if DEBUG
  857. Log.Write("FileNames:");
  858. #endif
  859. for (int i = 0; i < db._files.Count; i++)
  860. {
  861. db._files[i].Name = _currentReader.ReadString();
  862. #if DEBUG
  863. Log.Write(" " + db._files[i].Name);
  864. #endif
  865. }
  866. #if DEBUG
  867. Log.WriteLine();
  868. #endif
  869. }
  870. break;
  871. case BlockType.WinAttributes:
  872. #if DEBUG
  873. Log.Write("WinAttributes:");
  874. #endif
  875. ReadAttributeVector(dataVector, numFiles, delegate(int i, uint? attr)
  876. {
  877. // Some third party implementations established an unofficial extension
  878. // of the 7z archive format by placing posix file attributes in the high
  879. // bits of the windows file attributes. This makes use of the fact that
  880. // the official implementation does not perform checks on this value.
  881. //
  882. // Newer versions of the official 7z GUI client will try to parse this
  883. // extension, thus acknowledging the unofficial use of these bits.
  884. //
  885. // For us it is safe to just discard the upper bits if they are set and
  886. // keep the windows attributes from the lower bits (which should be set
  887. // properly even if posix file attributes are present, in order to be
  888. // compatible with older 7z archive readers)
  889. //
  890. // Note that the 15th bit is used by some implementations to indicate
  891. // presence of the extension, but not all implementations do that so
  892. // we can't trust that bit and must ignore it.
  893. //
  894. if (attr.HasValue && (attr.Value >> 16) != 0)
  895. {
  896. attr = attr.Value & 0x7FFFu;
  897. }
  898. db._files[i].Attrib = attr;
  899. #if DEBUG
  900. Log.Write(" " + (attr.HasValue ? attr.Value.ToString("x8") : "n/a"));
  901. #endif
  902. });
  903. #if DEBUG
  904. Log.WriteLine();
  905. #endif
  906. break;
  907. case BlockType.EmptyStream:
  908. emptyStreamVector = ReadBitVector(numFiles);
  909. #if DEBUG
  910. Log.Write("EmptyStream: ");
  911. #endif
  912. for (int i = 0; i < emptyStreamVector.Length; i++)
  913. {
  914. if (emptyStreamVector[i])
  915. {
  916. #if DEBUG
  917. Log.Write("x");
  918. #endif
  919. numEmptyStreams++;
  920. }
  921. else
  922. {
  923. #if DEBUG
  924. Log.Write(".");
  925. #endif
  926. }
  927. }
  928. #if DEBUG
  929. Log.WriteLine();
  930. #endif
  931. emptyFileVector = new BitVector(numEmptyStreams);
  932. antiFileVector = new BitVector(numEmptyStreams);
  933. break;
  934. case BlockType.EmptyFile:
  935. emptyFileVector = ReadBitVector(numEmptyStreams);
  936. #if DEBUG
  937. Log.Write("EmptyFile: ");
  938. for (int i = 0; i < numEmptyStreams; i++)
  939. {
  940. Log.Write(emptyFileVector[i] ? "x" : ".");
  941. }
  942. Log.WriteLine();
  943. #endif
  944. break;
  945. case BlockType.Anti:
  946. antiFileVector = ReadBitVector(numEmptyStreams);
  947. #if DEBUG
  948. Log.Write("Anti: ");
  949. for (int i = 0; i < numEmptyStreams; i++)
  950. {
  951. Log.Write(antiFileVector[i] ? "x" : ".");
  952. }
  953. Log.WriteLine();
  954. #endif
  955. break;
  956. case BlockType.StartPos:
  957. #if DEBUG
  958. Log.Write("StartPos:");
  959. #endif
  960. ReadNumberVector(dataVector, numFiles, delegate(int i, long? startPos)
  961. {
  962. db._files[i].StartPos = startPos;
  963. #if DEBUG
  964. Log.Write(" " + (startPos.HasValue ? startPos.Value.ToString() : "n/a"));
  965. #endif
  966. });
  967. #if DEBUG
  968. Log.WriteLine();
  969. #endif
  970. break;
  971. case BlockType.CTime:
  972. #if DEBUG
  973. Log.Write("CTime:");
  974. #endif
  975. ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
  976. {
  977. db._files[i].CTime = time;
  978. #if DEBUG
  979. Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
  980. #endif
  981. });
  982. #if DEBUG
  983. Log.WriteLine();
  984. #endif
  985. break;
  986. case BlockType.ATime:
  987. #if DEBUG
  988. Log.Write("ATime:");
  989. #endif
  990. ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
  991. {
  992. db._files[i].ATime = time;
  993. #if DEBUG
  994. Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
  995. #endif
  996. });
  997. #if DEBUG
  998. Log.WriteLine();
  999. #endif
  1000. break;
  1001. case BlockType.MTime:
  1002. #if DEBUG
  1003. Log.Write("MTime:");
  1004. #endif
  1005. ReadDateTimeVector(dataVector, numFiles, delegate(int i, DateTime? time)
  1006. {
  1007. db._files[i].MTime = time;
  1008. #if DEBUG
  1009. Log.Write(" " + (time.HasValue ? time.Value.ToString() : "n/a"));
  1010. #endif
  1011. });
  1012. #if DEBUG
  1013. Log.WriteLine();
  1014. #endif
  1015. break;
  1016. case BlockType.Dummy:
  1017. #if DEBUG
  1018. Log.Write("Dummy: " + size);
  1019. #endif
  1020. for (long j = 0; j < size; j++)
  1021. {
  1022. if (ReadByte() != 0)
  1023. {
  1024. throw new InvalidOperationException();
  1025. }
  1026. }
  1027. break;
  1028. default:
  1029. SkipData(size);
  1030. break;
  1031. }
  1032. // since 0.3 record sizes must be correct
  1033. bool checkRecordsSize = (db._majorVersion > 0 || db._minorVersion > 2);
  1034. if (checkRecordsSize && _currentReader.Offset - oldPos != size)
  1035. {
  1036. throw new InvalidOperationException();
  1037. }
  1038. }
  1039. int emptyFileIndex = 0;
  1040. int sizeIndex = 0;
  1041. for (int i = 0; i < numFiles; i++)
  1042. {
  1043. CFileItem file = db._files[i];
  1044. file.HasStream = !emptyStreamVector[i];
  1045. if (file.HasStream)
  1046. {
  1047. file.IsDir = false;
  1048. file.IsAnti = false;
  1049. file.Size = unpackSizes[sizeIndex];
  1050. file.Crc = digests[sizeIndex];
  1051. sizeIndex++;
  1052. }
  1053. else
  1054. {
  1055. file.IsDir = !emptyFileVector[emptyFileIndex];
  1056. file.IsAnti = antiFileVector[emptyFileIndex];
  1057. emptyFileIndex++;
  1058. file.Size = 0;
  1059. file.Crc = null;
  1060. }
  1061. }
  1062. }
  1063. finally
  1064. {
  1065. #if DEBUG
  1066. Log.PopIndent();
  1067. #endif
  1068. }
  1069. }
  1070. #endregion
  1071. #region Public Methods
  1072. public void Open(Stream stream)
  1073. {
  1074. Close();
  1075. _streamOrigin = stream.Position;
  1076. _streamEnding = stream.Length;
  1077. // TODO: Check Signature!
  1078. _header = new byte[0x20];
  1079. for (int offset = 0; offset < 0x20;)
  1080. {
  1081. int delta = stream.Read(_header, offset, 0x20 - offset);
  1082. if (delta == 0)
  1083. {
  1084. throw new EndOfStreamException();
  1085. }
  1086. offset += delta;
  1087. }
  1088. _stream = stream;
  1089. }
  1090. public void Close()
  1091. {
  1092. if (_stream != null)
  1093. {
  1094. _stream.Dispose();
  1095. }
  1096. foreach (var stream in _cachedStreams.Values)
  1097. {
  1098. stream.Dispose();
  1099. }
  1100. _cachedStreams.Clear();
  1101. }
  1102. public ArchiveDatabase ReadDatabase(IPasswordProvider pass)
  1103. {
  1104. var db = new ArchiveDatabase(pass);
  1105. db.Clear();
  1106. db._majorVersion = _header[6];
  1107. db._minorVersion = _header[7];
  1108. if (db._majorVersion != 0)
  1109. {
  1110. throw new InvalidOperationException();
  1111. }
  1112. uint crcFromArchive = DataReader.Get32(_header, 8);
  1113. long nextHeaderOffset = (long)DataReader.Get64(_header, 0xC);
  1114. long nextHeaderSize = (long)DataReader.Get64(_header, 0x14);
  1115. uint nextHeaderCrc = DataReader.Get32(_header, 0x1C);
  1116. uint crc = Crc.INIT_CRC;
  1117. crc = Crc.Update(crc, nextHeaderOffset);
  1118. crc = Crc.Update(crc, nextHeaderSize);
  1119. crc = Crc.Update(crc, nextHeaderCrc);
  1120. crc = Crc.Finish(crc);
  1121. if (crc != crcFromArchive)
  1122. {
  1123. throw new InvalidOperationException();
  1124. }
  1125. db._startPositionAfterHeader = _streamOrigin + 0x20;
  1126. // empty header is ok
  1127. if (nextHeaderSize == 0)
  1128. {
  1129. db.Fill();
  1130. return db;
  1131. }
  1132. if (nextHeaderOffset < 0 || nextHeaderSize < 0 || nextHeaderSize > Int32.MaxValue)
  1133. {
  1134. throw new InvalidOperationException();
  1135. }
  1136. if (nextHeaderOffset > _streamEnding - db._startPositionAfterHeader)
  1137. {
  1138. throw new IndexOutOfRangeException();
  1139. }
  1140. _stream.Seek(nextHeaderOffset, SeekOrigin.Current);
  1141. byte[] header = new byte[nextHeaderSize];
  1142. _stream.ReadExact(header, 0, header.Length);
  1143. if (Crc.Finish(Crc.Update(Crc.INIT_CRC, header, 0, header.Length)) != nextHeaderCrc)
  1144. {
  1145. throw new InvalidOperationException();
  1146. }
  1147. using (CStreamSwitch streamSwitch = new CStreamSwitch())
  1148. {
  1149. streamSwitch.Set(this, header);
  1150. BlockType? type = ReadId();
  1151. if (type != BlockType.Header)
  1152. {
  1153. if (type != BlockType.EncodedHeader)
  1154. {
  1155. throw new InvalidOperationException();
  1156. }
  1157. var dataVector = ReadAndDecodePackedStreams(db._startPositionAfterHeader, db.PasswordProvider);
  1158. // compressed header without content is odd but ok
  1159. if (dataVector.Count == 0)
  1160. {
  1161. db.Fill();
  1162. return db;
  1163. }
  1164. if (dataVector.Count != 1)
  1165. {
  1166. throw new InvalidOperationException();
  1167. }
  1168. streamSwitch.Set(this, dataVector[0]);
  1169. if (ReadId() != BlockType.Header)
  1170. {
  1171. throw new InvalidOperationException();
  1172. }
  1173. }
  1174. ReadHeader(db, db.PasswordProvider);
  1175. }
  1176. db.Fill();
  1177. return db;
  1178. }
  1179. internal class CExtractFolderInfo
  1180. {
  1181. internal int _fileIndex;
  1182. internal int _folderIndex;
  1183. internal List<bool> _extractStatuses = new List<bool>();
  1184. internal CExtractFolderInfo(int fileIndex, int folderIndex)
  1185. {
  1186. _fileIndex = fileIndex;
  1187. _folderIndex = folderIndex;
  1188. if (fileIndex != -1)
  1189. {
  1190. _extractStatuses.Add(true);
  1191. }
  1192. }
  1193. }
  1194. private class FolderUnpackStream : Stream
  1195. {
  1196. private readonly ArchiveDatabase _db;
  1197. private readonly int _startIndex;
  1198. private readonly List<bool> _extractStatuses;
  1199. public FolderUnpackStream(ArchiveDatabase db, int p, int startIndex, List<bool> list)
  1200. {
  1201. _db = db;
  1202. _startIndex = startIndex;
  1203. _extractStatuses = list;
  1204. }
  1205. #region Stream
  1206. public override bool CanRead => true;
  1207. public override bool CanSeek => false;
  1208. public override bool CanWrite => false;
  1209. public override void Flush()
  1210. {
  1211. throw new NotSupportedException();
  1212. }
  1213. public override long Length => throw new NotSupportedException();
  1214. public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
  1215. public override int Read(byte[] buffer, int offset, int count)
  1216. {
  1217. throw new NotSupportedException();
  1218. }
  1219. public override long Seek(long offset, SeekOrigin origin)
  1220. {
  1221. throw new NotSupportedException();
  1222. }
  1223. public override void SetLength(long value)
  1224. {
  1225. throw new NotSupportedException();
  1226. }
  1227. private Stream _stream;
  1228. private long _rem;
  1229. private int _currentIndex;
  1230. private void ProcessEmptyFiles()
  1231. {
  1232. while (_currentIndex < _extractStatuses.Count && _db._files[_startIndex + _currentIndex].Size == 0)
  1233. {
  1234. OpenFile();
  1235. _stream.Dispose();
  1236. _stream = null;
  1237. _currentIndex++;
  1238. }
  1239. }
  1240. private void OpenFile()
  1241. {
  1242. int index = _startIndex + _currentIndex;
  1243. #if DEBUG
  1244. Log.WriteLine(_db._files[index].Name);
  1245. #endif
  1246. if (_db._files[index].CrcDefined)
  1247. {
  1248. _stream = new CrcCheckStream(_db._files[index].Crc.Value);
  1249. }
  1250. else
  1251. {
  1252. _stream = new MemoryStream();
  1253. }
  1254. _rem = _db._files[index].Size;
  1255. }
  1256. public override void Write(byte[] buffer, int offset, int count)
  1257. {
  1258. while (count != 0)
  1259. {
  1260. if (_stream != null)
  1261. {
  1262. int write = count;
  1263. if (write > _rem)
  1264. {
  1265. write = (int)_rem;
  1266. }
  1267. _stream.Write(buffer, offset, write);
  1268. count -= write;
  1269. _rem -= write;
  1270. offset += write;
  1271. if (_rem == 0)
  1272. {
  1273. _stream.Dispose();
  1274. _stream = null;
  1275. _currentIndex++;
  1276. ProcessEmptyFiles();
  1277. }
  1278. }
  1279. else
  1280. {
  1281. ProcessEmptyFiles();
  1282. if (_currentIndex == _extractStatuses.Count)
  1283. {
  1284. // we support partial extracting
  1285. Debugger.Break();
  1286. throw new NotSupportedException();
  1287. }
  1288. OpenFile();
  1289. }
  1290. }
  1291. }
  1292. #endregion
  1293. }
  1294. private Stream GetCachedDecoderStream(ArchiveDatabase db, int folderIndex)
  1295. {
  1296. Stream s;
  1297. if (!_cachedStreams.TryGetValue(folderIndex, out s))
  1298. {
  1299. CFolder folderInfo = db._folders[folderIndex];
  1300. int packStreamIndex = db._folders[folderIndex]._firstPackStreamId;
  1301. long folderStartPackPos = db.GetFolderStreamPos(folderInfo, 0);
  1302. List<long> packSizes = new List<long>();
  1303. for (int j = 0; j < folderInfo._packStreams.Count; j++)
  1304. {
  1305. packSizes.Add(db._packSizes[packStreamIndex + j]);
  1306. }
  1307. s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(), folderInfo,
  1308. db.PasswordProvider);
  1309. _cachedStreams.Add(folderIndex, s);
  1310. }
  1311. return s;
  1312. }
  1313. public Stream OpenStream(ArchiveDatabase db, int fileIndex)
  1314. {
  1315. int folderIndex = db._fileIndexToFolderIndexMap[fileIndex];
  1316. int numFilesInFolder = db._numUnpackStreamsVector[folderIndex];
  1317. int firstFileIndex = db._folderStartFileIndex[folderIndex];
  1318. if (firstFileIndex > fileIndex || fileIndex - firstFileIndex >= numFilesInFolder)
  1319. {
  1320. throw new InvalidOperationException();
  1321. }
  1322. int skipCount = fileIndex - firstFileIndex;
  1323. long skipSize = 0;
  1324. for (int i = 0; i < skipCount; i++)
  1325. {
  1326. skipSize += db._files[firstFileIndex + i].Size;
  1327. }
  1328. Stream s = GetCachedDecoderStream(db, folderIndex);
  1329. s.Position = skipSize;
  1330. return new ReadOnlySubStream(s, db._files[fileIndex].Size);
  1331. }
  1332. public void Extract(ArchiveDatabase db, int[] indices)
  1333. {
  1334. int numItems;
  1335. bool allFilesMode = (indices == null);
  1336. if (allFilesMode)
  1337. {
  1338. numItems = db._files.Count;
  1339. }
  1340. else
  1341. {
  1342. numItems = indices.Length;
  1343. }
  1344. if (numItems == 0)
  1345. {
  1346. return;
  1347. }
  1348. List<CExtractFolderInfo> extractFolderInfoVector = new List<CExtractFolderInfo>();
  1349. for (int i = 0; i < numItems; i++)
  1350. {
  1351. int fileIndex = allFilesMode ? i : indices[i];
  1352. int folderIndex = db._fileIndexToFolderIndexMap[fileIndex];
  1353. if (folderIndex == -1)
  1354. {
  1355. extractFolderInfoVector.Add(new CExtractFolderInfo(fileIndex, -1));
  1356. continue;
  1357. }
  1358. if (extractFolderInfoVector.Count == 0 || folderIndex != extractFolderInfoVector.Last()._folderIndex)
  1359. {
  1360. extractFolderInfoVector.Add(new CExtractFolderInfo(-1, folderIndex));
  1361. }
  1362. CExtractFolderInfo efi = extractFolderInfoVector.Last();
  1363. int startIndex = db._folderStartFileIndex[folderIndex];
  1364. for (int index = efi._extractStatuses.Count; index <= fileIndex - startIndex; index++)
  1365. {
  1366. efi._extractStatuses.Add(index == fileIndex - startIndex);
  1367. }
  1368. }
  1369. foreach (CExtractFolderInfo efi in extractFolderInfoVector)
  1370. {
  1371. int startIndex;
  1372. if (efi._fileIndex != -1)
  1373. {
  1374. startIndex = efi._fileIndex;
  1375. }
  1376. else
  1377. {
  1378. startIndex = db._folderStartFileIndex[efi._folderIndex];
  1379. }
  1380. var outStream = new FolderUnpackStream(db, 0, startIndex, efi._extractStatuses);
  1381. if (efi._fileIndex != -1)
  1382. {
  1383. continue;
  1384. }
  1385. int folderIndex = efi._folderIndex;
  1386. CFolder folderInfo = db._folders[folderIndex];
  1387. int packStreamIndex = db._folders[folderIndex]._firstPackStreamId;
  1388. long folderStartPackPos = db.GetFolderStreamPos(folderInfo, 0);
  1389. List<long> packSizes = new List<long>();
  1390. for (int j = 0; j < folderInfo._packStreams.Count; j++)
  1391. {
  1392. packSizes.Add(db._packSizes[packStreamIndex + j]);
  1393. }
  1394. // TODO: If the decoding fails the last file may be extracted incompletely. Delete it?
  1395. Stream s = DecoderStreamHelper.CreateDecoderStream(_stream, folderStartPackPos, packSizes.ToArray(),
  1396. folderInfo, db.PasswordProvider);
  1397. byte[] buffer = new byte[4 << 10];
  1398. for (;;)
  1399. {
  1400. int processed = s.Read(buffer, 0, buffer.Length);
  1401. if (processed == 0)
  1402. {
  1403. break;
  1404. }
  1405. outStream.Write(buffer, 0, processed);
  1406. }
  1407. }
  1408. }
  1409. public IEnumerable<CFileItem> GetFiles(ArchiveDatabase db)
  1410. {
  1411. return db._files;
  1412. }
  1413. public int GetFileIndex(ArchiveDatabase db, CFileItem item)
  1414. {
  1415. return db._files.IndexOf(item);
  1416. }
  1417. #endregion
  1418. }
  1419. }