7zExtract.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // 7zExtract.cpp
  2. #include "StdAfx.h"
  3. #include "7zHandler.h"
  4. #include "7zFolderOutStream.h"
  5. #include "7zDecode.h"
  6. // #include "7z1Decode.h"
  7. #include "../../../Common/ComTry.h"
  8. #include "../../Common/StreamObjects.h"
  9. #include "../../Common/ProgressUtils.h"
  10. #include "../../Common/LimitedStreams.h"
  11. namespace NArchive {
  12. namespace N7z {
  13. struct CExtractFolderInfo
  14. {
  15. #ifdef _7Z_VOL
  16. int VolumeIndex;
  17. #endif
  18. CNum FileIndex;
  19. CNum FolderIndex;
  20. CBoolVector ExtractStatuses;
  21. UInt64 UnPackSize;
  22. CExtractFolderInfo(
  23. #ifdef _7Z_VOL
  24. int volumeIndex,
  25. #endif
  26. CNum fileIndex, CNum folderIndex):
  27. #ifdef _7Z_VOL
  28. VolumeIndex(volumeIndex),
  29. #endif
  30. FileIndex(fileIndex),
  31. FolderIndex(folderIndex),
  32. UnPackSize(0)
  33. {
  34. if (fileIndex != kNumNoIndex)
  35. {
  36. ExtractStatuses.Reserve(1);
  37. ExtractStatuses.Add(true);
  38. }
  39. };
  40. };
  41. STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
  42. Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
  43. {
  44. COM_TRY_BEGIN
  45. bool testMode = (testModeSpec != 0);
  46. CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
  47. UInt64 importantTotalUnPacked = 0;
  48. bool allFilesMode = (numItems == UInt32(-1));
  49. if (allFilesMode)
  50. numItems =
  51. #ifdef _7Z_VOL
  52. _refs.Size();
  53. #else
  54. _database.Files.Size();
  55. #endif
  56. if(numItems == 0)
  57. return S_OK;
  58. /*
  59. if(_volumes.Size() != 1)
  60. return E_FAIL;
  61. const CVolume &volume = _volumes.Front();
  62. const CArchiveDatabaseEx &_database = volume.Database;
  63. IInStream *_inStream = volume.Stream;
  64. */
  65. CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
  66. for(UInt32 ii = 0; ii < numItems; ii++)
  67. {
  68. // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
  69. UInt32 ref2Index = allFilesMode ? ii : indices[ii];
  70. // const CRef2 &ref2 = _refs[ref2Index];
  71. // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
  72. {
  73. #ifdef _7Z_VOL
  74. // const CRef &ref = ref2.Refs[ri];
  75. const CRef &ref = _refs[ref2Index];
  76. int volumeIndex = ref.VolumeIndex;
  77. const CVolume &volume = _volumes[volumeIndex];
  78. const CArchiveDatabaseEx &database = volume.Database;
  79. UInt32 fileIndex = ref.ItemIndex;
  80. #else
  81. const CArchiveDatabaseEx &database = _database;
  82. UInt32 fileIndex = ref2Index;
  83. #endif
  84. CNum folderIndex = database.FileIndexToFolderIndexMap[fileIndex];
  85. if (folderIndex == kNumNoIndex)
  86. {
  87. extractFolderInfoVector.Add(CExtractFolderInfo(
  88. #ifdef _7Z_VOL
  89. volumeIndex,
  90. #endif
  91. fileIndex, kNumNoIndex));
  92. continue;
  93. }
  94. if (extractFolderInfoVector.IsEmpty() ||
  95. folderIndex != extractFolderInfoVector.Back().FolderIndex
  96. #ifdef _7Z_VOL
  97. || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
  98. #endif
  99. )
  100. {
  101. extractFolderInfoVector.Add(CExtractFolderInfo(
  102. #ifdef _7Z_VOL
  103. volumeIndex,
  104. #endif
  105. kNumNoIndex, folderIndex));
  106. const CFolder &folderInfo = database.Folders[folderIndex];
  107. UInt64 unPackSize = folderInfo.GetUnPackSize();
  108. importantTotalUnPacked += unPackSize;
  109. extractFolderInfoVector.Back().UnPackSize = unPackSize;
  110. }
  111. CExtractFolderInfo &efi = extractFolderInfoVector.Back();
  112. // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
  113. CNum startIndex = database.FolderStartFileIndex[folderIndex];
  114. for (CNum index = efi.ExtractStatuses.Size();
  115. index <= fileIndex - startIndex; index++)
  116. {
  117. // UInt64 unPackSize = _database.Files[startIndex + index].UnPackSize;
  118. // Count partial_folder_size
  119. // efi.UnPackSize += unPackSize;
  120. // importantTotalUnPacked += unPackSize;
  121. efi.ExtractStatuses.Add(index == fileIndex - startIndex);
  122. }
  123. }
  124. }
  125. extractCallback->SetTotal(importantTotalUnPacked);
  126. CDecoder decoder(
  127. #ifdef _ST_MODE
  128. false
  129. #else
  130. true
  131. #endif
  132. );
  133. // CDecoder1 decoder;
  134. UInt64 currentTotalPacked = 0;
  135. UInt64 currentTotalUnPacked = 0;
  136. UInt64 totalFolderUnPacked;
  137. UInt64 totalFolderPacked;
  138. CLocalProgress *lps = new CLocalProgress;
  139. CMyComPtr<ICompressProgressInfo> progress = lps;
  140. lps->Init(extractCallback, false);
  141. for(int i = 0; i < extractFolderInfoVector.Size(); i++,
  142. currentTotalUnPacked += totalFolderUnPacked,
  143. currentTotalPacked += totalFolderPacked)
  144. {
  145. lps->OutSize = currentTotalUnPacked;
  146. lps->InSize = currentTotalPacked;
  147. RINOK(lps->SetCur());
  148. const CExtractFolderInfo &efi = extractFolderInfoVector[i];
  149. totalFolderUnPacked = efi.UnPackSize;
  150. totalFolderPacked = 0;
  151. CFolderOutStream *folderOutStream = new CFolderOutStream;
  152. CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
  153. #ifdef _7Z_VOL
  154. const CVolume &volume = _volumes[efi.VolumeIndex];
  155. const CArchiveDatabaseEx &database = volume.Database;
  156. #else
  157. const CArchiveDatabaseEx &database = _database;
  158. #endif
  159. CNum startIndex;
  160. if (efi.FileIndex != kNumNoIndex)
  161. startIndex = efi.FileIndex;
  162. else
  163. startIndex = database.FolderStartFileIndex[efi.FolderIndex];
  164. HRESULT result = folderOutStream->Init(&database,
  165. #ifdef _7Z_VOL
  166. volume.StartRef2Index,
  167. #else
  168. 0,
  169. #endif
  170. startIndex,
  171. &efi.ExtractStatuses, extractCallback, testMode, _crcSize != 0);
  172. RINOK(result);
  173. if (efi.FileIndex != kNumNoIndex)
  174. continue;
  175. CNum folderIndex = efi.FolderIndex;
  176. const CFolder &folderInfo = database.Folders[folderIndex];
  177. totalFolderPacked = _database.GetFolderFullPackSize(folderIndex);
  178. CNum packStreamIndex = database.FolderStartPackStreamIndex[folderIndex];
  179. UInt64 folderStartPackPos = database.GetFolderStreamPos(folderIndex, 0);
  180. #ifndef _NO_CRYPTO
  181. CMyComPtr<ICryptoGetTextPassword> getTextPassword;
  182. if (extractCallback)
  183. extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
  184. #endif
  185. try
  186. {
  187. HRESULT result = decoder.Decode(
  188. EXTERNAL_CODECS_VARS
  189. #ifdef _7Z_VOL
  190. volume.Stream,
  191. #else
  192. _inStream,
  193. #endif
  194. folderStartPackPos,
  195. &database.PackSizes[packStreamIndex],
  196. folderInfo,
  197. outStream,
  198. progress
  199. #ifndef _NO_CRYPTO
  200. , getTextPassword
  201. #endif
  202. #ifdef COMPRESS_MT
  203. , true, _numThreads
  204. #endif
  205. );
  206. if (result == S_FALSE)
  207. {
  208. RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
  209. continue;
  210. }
  211. if (result == E_NOTIMPL)
  212. {
  213. RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
  214. continue;
  215. }
  216. if (result != S_OK)
  217. return result;
  218. if (folderOutStream->WasWritingFinished() != S_OK)
  219. {
  220. RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
  221. continue;
  222. }
  223. }
  224. catch(...)
  225. {
  226. RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
  227. continue;
  228. }
  229. }
  230. return S_OK;
  231. COM_TRY_END
  232. }
  233. }}