ArchiveDatabase.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using SharpCompress.Compressors.LZMA;
  5. using SharpCompress.Compressors.LZMA.Utilites;
  6. namespace SharpCompress.Common.SevenZip
  7. {
  8. internal class ArchiveDatabase
  9. {
  10. internal byte _majorVersion;
  11. internal byte _minorVersion;
  12. internal long _startPositionAfterHeader;
  13. internal long _dataStartPosition;
  14. internal List<long> _packSizes = new List<long>();
  15. internal List<uint?> _packCrCs = new List<uint?>();
  16. internal List<CFolder> _folders = new List<CFolder>();
  17. internal List<int> _numUnpackStreamsVector;
  18. internal List<CFileItem> _files = new List<CFileItem>();
  19. internal List<long> _packStreamStartPositions = new List<long>();
  20. internal List<int> _folderStartFileIndex = new List<int>();
  21. internal List<int> _fileIndexToFolderIndexMap = new List<int>();
  22. internal IPasswordProvider PasswordProvider { get; }
  23. public ArchiveDatabase(IPasswordProvider passwordProvider)
  24. {
  25. PasswordProvider = passwordProvider;
  26. }
  27. internal void Clear()
  28. {
  29. _packSizes.Clear();
  30. _packCrCs.Clear();
  31. _folders.Clear();
  32. _numUnpackStreamsVector = null;
  33. _files.Clear();
  34. _packStreamStartPositions.Clear();
  35. _folderStartFileIndex.Clear();
  36. _fileIndexToFolderIndexMap.Clear();
  37. }
  38. internal bool IsEmpty()
  39. {
  40. return _packSizes.Count == 0
  41. && _packCrCs.Count == 0
  42. && _folders.Count == 0
  43. && _numUnpackStreamsVector.Count == 0
  44. && _files.Count == 0;
  45. }
  46. private void FillStartPos()
  47. {
  48. _packStreamStartPositions.Clear();
  49. long startPos = 0;
  50. for (int i = 0; i < _packSizes.Count; i++)
  51. {
  52. _packStreamStartPositions.Add(startPos);
  53. startPos += _packSizes[i];
  54. }
  55. }
  56. private void FillFolderStartFileIndex()
  57. {
  58. _folderStartFileIndex.Clear();
  59. _fileIndexToFolderIndexMap.Clear();
  60. int folderIndex = 0;
  61. int indexInFolder = 0;
  62. for (int i = 0; i < _files.Count; i++)
  63. {
  64. CFileItem file = _files[i];
  65. bool emptyStream = !file.HasStream;
  66. if (emptyStream && indexInFolder == 0)
  67. {
  68. _fileIndexToFolderIndexMap.Add(-1);
  69. continue;
  70. }
  71. if (indexInFolder == 0)
  72. {
  73. // v3.13 incorrectly worked with empty folders
  74. // v4.07: Loop for skipping empty folders
  75. for (;;)
  76. {
  77. if (folderIndex >= _folders.Count)
  78. {
  79. throw new InvalidOperationException();
  80. }
  81. _folderStartFileIndex.Add(i); // check it
  82. if (_numUnpackStreamsVector[folderIndex] != 0)
  83. {
  84. break;
  85. }
  86. folderIndex++;
  87. }
  88. }
  89. _fileIndexToFolderIndexMap.Add(folderIndex);
  90. if (emptyStream)
  91. {
  92. continue;
  93. }
  94. indexInFolder++;
  95. if (indexInFolder >= _numUnpackStreamsVector[folderIndex])
  96. {
  97. folderIndex++;
  98. indexInFolder = 0;
  99. }
  100. }
  101. }
  102. public void Fill()
  103. {
  104. FillStartPos();
  105. FillFolderStartFileIndex();
  106. }
  107. internal long GetFolderStreamPos(CFolder folder, int indexInFolder)
  108. {
  109. int index = folder._firstPackStreamId + indexInFolder;
  110. return _dataStartPosition + _packStreamStartPositions[index];
  111. }
  112. internal long GetFolderFullPackSize(int folderIndex)
  113. {
  114. int packStreamIndex = _folders[folderIndex]._firstPackStreamId;
  115. CFolder folder = _folders[folderIndex];
  116. long size = 0;
  117. for (int i = 0; i < folder._packStreams.Count; i++)
  118. {
  119. size += _packSizes[packStreamIndex + i];
  120. }
  121. return size;
  122. }
  123. internal Stream GetFolderStream(Stream stream, CFolder folder, IPasswordProvider pw)
  124. {
  125. int packStreamIndex = folder._firstPackStreamId;
  126. long folderStartPackPos = GetFolderStreamPos(folder, 0);
  127. List<long> packSizes = new List<long>();
  128. for (int j = 0; j < folder._packStreams.Count; j++)
  129. {
  130. packSizes.Add(_packSizes[packStreamIndex + j]);
  131. }
  132. return DecoderStreamHelper.CreateDecoderStream(stream, folderStartPackPos, packSizes.ToArray(), folder, pw);
  133. }
  134. private long GetFolderPackStreamSize(int folderIndex, int streamIndex)
  135. {
  136. return _packSizes[_folders[folderIndex]._firstPackStreamId + streamIndex];
  137. }
  138. private long GetFilePackSize(int fileIndex)
  139. {
  140. int folderIndex = _fileIndexToFolderIndexMap[fileIndex];
  141. if (folderIndex != -1)
  142. {
  143. if (_folderStartFileIndex[folderIndex] == fileIndex)
  144. {
  145. return GetFolderFullPackSize(folderIndex);
  146. }
  147. }
  148. return 0;
  149. }
  150. }
  151. }