7zHandlerOut.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. // 7zHandlerOut.cpp
  2. #include "StdAfx.h"
  3. #include "7zHandler.h"
  4. #include "7zOut.h"
  5. #include "7zUpdate.h"
  6. #include "../../../Windows/PropVariant.h"
  7. #include "../../../Common/ComTry.h"
  8. #include "../../../Common/StringToInt.h"
  9. #include "../../IPassword.h"
  10. #include "../../ICoder.h"
  11. #include "../Common/ItemNameUtils.h"
  12. #include "../Common/ParseProperties.h"
  13. using namespace NWindows;
  14. namespace NArchive {
  15. namespace N7z {
  16. static const wchar_t *kLZMAMethodName = L"LZMA";
  17. static const wchar_t *kCopyMethod = L"Copy";
  18. static const wchar_t *kDefaultMethodName = kLZMAMethodName;
  19. static const UInt32 kLzmaAlgorithmX5 = 1;
  20. static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
  21. static const UInt32 kDictionaryForHeaders = 1 << 20;
  22. static const UInt32 kNumFastBytesForHeaders = 273;
  23. static const UInt32 kAlgorithmForHeaders = kLzmaAlgorithmX5;
  24. static inline bool IsCopyMethod(const UString &methodName)
  25. { return (methodName.CompareNoCase(kCopyMethod) == 0); }
  26. STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
  27. {
  28. *type = NFileTimeType::kWindows;
  29. return S_OK;
  30. }
  31. HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode,
  32. IArchiveUpdateCallback *updateCallback)
  33. {
  34. CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
  35. if (!getTextPassword)
  36. {
  37. CMyComPtr<IArchiveUpdateCallback> udateCallback2(updateCallback);
  38. udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
  39. }
  40. if (getTextPassword)
  41. {
  42. CMyComBSTR password;
  43. Int32 passwordIsDefined;
  44. RINOK(getTextPassword->CryptoGetTextPassword2(
  45. &passwordIsDefined, &password));
  46. methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
  47. if (methodMode.PasswordIsDefined)
  48. methodMode.Password = password;
  49. }
  50. else
  51. methodMode.PasswordIsDefined = false;
  52. return S_OK;
  53. }
  54. HRESULT CHandler::SetCompressionMethod(
  55. CCompressionMethodMode &methodMode,
  56. CCompressionMethodMode &headerMethod)
  57. {
  58. HRESULT res = SetCompressionMethod(methodMode, _methods
  59. #ifdef COMPRESS_MT
  60. , _numThreads
  61. #endif
  62. );
  63. RINOK(res);
  64. methodMode.Binds = _binds;
  65. if (_compressHeaders)
  66. {
  67. // headerMethod.Methods.Add(methodMode.Methods.Back());
  68. CObjectVector<COneMethodInfo> headerMethodInfoVector;
  69. COneMethodInfo oneMethodInfo;
  70. oneMethodInfo.MethodName = kLZMAMethodName;
  71. {
  72. CProp property;
  73. property.Id = NCoderPropID::kMatchFinder;
  74. property.Value = kLzmaMatchFinderForHeaders;
  75. oneMethodInfo.Properties.Add(property);
  76. }
  77. {
  78. CProp property;
  79. property.Id = NCoderPropID::kAlgorithm;
  80. property.Value = kAlgorithmForHeaders;
  81. oneMethodInfo.Properties.Add(property);
  82. }
  83. {
  84. CProp property;
  85. property.Id = NCoderPropID::kNumFastBytes;
  86. property.Value = UInt32(kNumFastBytesForHeaders);
  87. oneMethodInfo.Properties.Add(property);
  88. }
  89. {
  90. CProp property;
  91. property.Id = NCoderPropID::kDictionarySize;
  92. property.Value = UInt32(kDictionaryForHeaders);
  93. oneMethodInfo.Properties.Add(property);
  94. }
  95. headerMethodInfoVector.Add(oneMethodInfo);
  96. HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
  97. #ifdef COMPRESS_MT
  98. ,1
  99. #endif
  100. );
  101. RINOK(res);
  102. }
  103. return S_OK;
  104. }
  105. HRESULT CHandler::SetCompressionMethod(
  106. CCompressionMethodMode &methodMode,
  107. CObjectVector<COneMethodInfo> &methodsInfo
  108. #ifdef COMPRESS_MT
  109. , UInt32 numThreads
  110. #endif
  111. )
  112. {
  113. UInt32 level = _level;
  114. if (methodsInfo.IsEmpty())
  115. {
  116. COneMethodInfo oneMethodInfo;
  117. oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
  118. methodsInfo.Add(oneMethodInfo);
  119. }
  120. bool needSolid = false;
  121. for(int i = 0; i < methodsInfo.Size(); i++)
  122. {
  123. COneMethodInfo &oneMethodInfo = methodsInfo[i];
  124. SetCompressionMethod2(oneMethodInfo
  125. #ifdef COMPRESS_MT
  126. , numThreads
  127. #endif
  128. );
  129. if (!IsCopyMethod(oneMethodInfo.MethodName))
  130. needSolid = true;
  131. CMethodFull methodFull;
  132. if (!FindMethod(
  133. EXTERNAL_CODECS_VARS
  134. oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams))
  135. return E_INVALIDARG;
  136. methodFull.Properties = oneMethodInfo.Properties;
  137. methodMode.Methods.Add(methodFull);
  138. if (!_numSolidBytesDefined)
  139. {
  140. for (int j = 0; j < methodFull.Properties.Size(); j++)
  141. {
  142. const CProp &prop = methodFull.Properties[j];
  143. if ((prop.Id == NCoderPropID::kDictionarySize ||
  144. prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4)
  145. {
  146. _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7;
  147. const UInt64 kMinSize = (1 << 24);
  148. if (_numSolidBytes < kMinSize)
  149. _numSolidBytes = kMinSize;
  150. _numSolidBytesDefined = true;
  151. break;
  152. }
  153. }
  154. }
  155. }
  156. if (!needSolid && !_numSolidBytesDefined)
  157. {
  158. _numSolidBytesDefined = true;
  159. _numSolidBytes = 0;
  160. }
  161. return S_OK;
  162. }
  163. static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, CArchiveFileTime &filetime, bool &filetimeIsDefined)
  164. {
  165. filetimeIsDefined = false;
  166. NCOM::CPropVariant propVariant;
  167. RINOK(updateCallback->GetProperty(index, propID, &propVariant));
  168. if (propVariant.vt == VT_FILETIME)
  169. {
  170. filetime = propVariant.filetime;
  171. filetimeIsDefined = true;
  172. }
  173. else if (propVariant.vt != VT_EMPTY)
  174. return E_INVALIDARG;
  175. return S_OK;
  176. }
  177. STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
  178. IArchiveUpdateCallback *updateCallback)
  179. {
  180. COM_TRY_BEGIN
  181. const CArchiveDatabaseEx *database = 0;
  182. #ifdef _7Z_VOL
  183. if(_volumes.Size() > 1)
  184. return E_FAIL;
  185. const CVolume *volume = 0;
  186. if (_volumes.Size() == 1)
  187. {
  188. volume = &_volumes.Front();
  189. database = &volume->Database;
  190. }
  191. #else
  192. if (_inStream != 0)
  193. database = &_database;
  194. #endif
  195. // CRecordVector<bool> compressStatuses;
  196. CObjectVector<CUpdateItem> updateItems;
  197. // CRecordVector<UInt32> copyIndices;
  198. // CMyComPtr<IUpdateCallback2> updateCallback2;
  199. // updateCallback->QueryInterface(&updateCallback2);
  200. for(UInt32 i = 0; i < numItems; i++)
  201. {
  202. Int32 newData;
  203. Int32 newProperties;
  204. UInt32 indexInArchive;
  205. if (!updateCallback)
  206. return E_FAIL;
  207. RINOK(updateCallback->GetUpdateItemInfo(i,
  208. &newData, &newProperties, &indexInArchive));
  209. CUpdateItem updateItem;
  210. updateItem.NewProperties = IntToBool(newProperties);
  211. updateItem.NewData = IntToBool(newData);
  212. updateItem.IndexInArchive = indexInArchive;
  213. updateItem.IndexInClient = i;
  214. updateItem.IsAnti = false;
  215. updateItem.Size = 0;
  216. if (updateItem.IndexInArchive != -1)
  217. {
  218. const CFileItem &fileItem = database->Files[updateItem.IndexInArchive];
  219. updateItem.Name = fileItem.Name;
  220. updateItem.IsDirectory = fileItem.IsDirectory;
  221. updateItem.Size = fileItem.UnPackSize;
  222. updateItem.IsAnti = fileItem.IsAnti;
  223. updateItem.CreationTime = fileItem.CreationTime;
  224. updateItem.IsCreationTimeDefined = fileItem.IsCreationTimeDefined;
  225. updateItem.LastWriteTime = fileItem.LastWriteTime;
  226. updateItem.IsLastWriteTimeDefined = fileItem.IsLastWriteTimeDefined;
  227. updateItem.LastAccessTime = fileItem.LastAccessTime;
  228. updateItem.IsLastAccessTimeDefined = fileItem.IsLastAccessTimeDefined;
  229. }
  230. if (updateItem.NewProperties)
  231. {
  232. bool nameIsDefined;
  233. bool folderStatusIsDefined;
  234. {
  235. NCOM::CPropVariant propVariant;
  236. RINOK(updateCallback->GetProperty(i, kpidAttributes, &propVariant));
  237. if (propVariant.vt == VT_EMPTY)
  238. updateItem.AttributesAreDefined = false;
  239. else if (propVariant.vt != VT_UI4)
  240. return E_INVALIDARG;
  241. else
  242. {
  243. updateItem.Attributes = propVariant.ulVal;
  244. updateItem.AttributesAreDefined = true;
  245. }
  246. }
  247. RINOK(GetTime(updateCallback, i, kpidCreationTime, updateItem.CreationTime, updateItem.IsCreationTimeDefined));
  248. RINOK(GetTime(updateCallback, i, kpidLastWriteTime, updateItem.LastWriteTime , updateItem.IsLastWriteTimeDefined));
  249. RINOK(GetTime(updateCallback, i, kpidLastAccessTime, updateItem.LastAccessTime, updateItem.IsLastAccessTimeDefined));
  250. {
  251. NCOM::CPropVariant propVariant;
  252. RINOK(updateCallback->GetProperty(i, kpidPath, &propVariant));
  253. if (propVariant.vt == VT_EMPTY)
  254. nameIsDefined = false;
  255. else if (propVariant.vt != VT_BSTR)
  256. return E_INVALIDARG;
  257. else
  258. {
  259. updateItem.Name = NItemName::MakeLegalName(propVariant.bstrVal);
  260. nameIsDefined = true;
  261. }
  262. }
  263. {
  264. NCOM::CPropVariant propVariant;
  265. RINOK(updateCallback->GetProperty(i, kpidIsFolder, &propVariant));
  266. if (propVariant.vt == VT_EMPTY)
  267. folderStatusIsDefined = false;
  268. else if (propVariant.vt != VT_BOOL)
  269. return E_INVALIDARG;
  270. else
  271. {
  272. updateItem.IsDirectory = (propVariant.boolVal != VARIANT_FALSE);
  273. folderStatusIsDefined = true;
  274. }
  275. }
  276. {
  277. NCOM::CPropVariant propVariant;
  278. RINOK(updateCallback->GetProperty(i, kpidIsAnti, &propVariant));
  279. if (propVariant.vt == VT_EMPTY)
  280. updateItem.IsAnti = false;
  281. else if (propVariant.vt != VT_BOOL)
  282. return E_INVALIDARG;
  283. else
  284. updateItem.IsAnti = (propVariant.boolVal != VARIANT_FALSE);
  285. }
  286. if (updateItem.IsAnti)
  287. {
  288. updateItem.AttributesAreDefined = false;
  289. updateItem.IsCreationTimeDefined = false;
  290. updateItem.IsLastWriteTimeDefined = false;
  291. updateItem.IsLastAccessTimeDefined = false;
  292. updateItem.Size = 0;
  293. }
  294. if (!folderStatusIsDefined && updateItem.AttributesAreDefined)
  295. updateItem.SetDirectoryStatusFromAttributes();
  296. }
  297. if (updateItem.NewData)
  298. {
  299. NCOM::CPropVariant propVariant;
  300. RINOK(updateCallback->GetProperty(i, kpidSize, &propVariant));
  301. if (propVariant.vt != VT_UI8)
  302. return E_INVALIDARG;
  303. updateItem.Size = (UInt64)propVariant.uhVal.QuadPart;
  304. if (updateItem.Size != 0 && updateItem.IsAnti)
  305. return E_INVALIDARG;
  306. }
  307. updateItems.Add(updateItem);
  308. }
  309. CCompressionMethodMode methodMode, headerMethod;
  310. RINOK(SetCompressionMethod(methodMode, headerMethod));
  311. #ifdef COMPRESS_MT
  312. methodMode.NumThreads = _numThreads;
  313. headerMethod.NumThreads = 1;
  314. #endif
  315. RINOK(SetPassword(methodMode, updateCallback));
  316. bool compressMainHeader = _compressHeaders; // check it
  317. if (methodMode.PasswordIsDefined)
  318. {
  319. compressMainHeader = true;
  320. if(_encryptHeaders)
  321. RINOK(SetPassword(headerMethod, updateCallback));
  322. }
  323. if (numItems < 2)
  324. compressMainHeader = false;
  325. CUpdateOptions options;
  326. options.Method = &methodMode;
  327. options.HeaderMethod = (_compressHeaders ||
  328. (methodMode.PasswordIsDefined && _encryptHeaders)) ?
  329. &headerMethod : 0;
  330. options.UseFilters = _level != 0 && _autoFilter;
  331. options.MaxFilter = _level >= 8;
  332. options.HeaderOptions.CompressMainHeader = compressMainHeader;
  333. options.HeaderOptions.WriteModified = WriteModified;
  334. options.HeaderOptions.WriteCreated = WriteCreated;
  335. options.HeaderOptions.WriteAccessed = WriteAccessed;
  336. options.NumSolidFiles = _numSolidFiles;
  337. options.NumSolidBytes = _numSolidBytes;
  338. options.SolidExtension = _solidExtension;
  339. options.RemoveSfxBlock = _removeSfxBlock;
  340. options.VolumeMode = _volumeMode;
  341. return Update(
  342. EXTERNAL_CODECS_VARS
  343. #ifdef _7Z_VOL
  344. volume ? volume->Stream: 0,
  345. volume ? database: 0,
  346. #else
  347. _inStream,
  348. database,
  349. #endif
  350. updateItems, outStream, updateCallback, options);
  351. COM_TRY_END
  352. }
  353. static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
  354. {
  355. stream = 0;
  356. int index = ParseStringToUInt32(srcString, coder);
  357. if (index == 0)
  358. return E_INVALIDARG;
  359. srcString.Delete(0, index);
  360. if (srcString[0] == 'S')
  361. {
  362. srcString.Delete(0);
  363. int index = ParseStringToUInt32(srcString, stream);
  364. if (index == 0)
  365. return E_INVALIDARG;
  366. srcString.Delete(0, index);
  367. }
  368. return S_OK;
  369. }
  370. static HRESULT GetBindInfo(UString &srcString, CBind &bind)
  371. {
  372. RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream));
  373. if (srcString[0] != ':')
  374. return E_INVALIDARG;
  375. srcString.Delete(0);
  376. RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream));
  377. if (!srcString.IsEmpty())
  378. return E_INVALIDARG;
  379. return S_OK;
  380. }
  381. STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
  382. {
  383. COM_TRY_BEGIN
  384. _binds.Clear();
  385. BeforeSetProperty();
  386. for (int i = 0; i < numProperties; i++)
  387. {
  388. UString name = names[i];
  389. name.MakeUpper();
  390. if (name.IsEmpty())
  391. return E_INVALIDARG;
  392. const PROPVARIANT &value = values[i];
  393. if (name[0] == 'B')
  394. {
  395. name.Delete(0);
  396. CBind bind;
  397. RINOK(GetBindInfo(name, bind));
  398. _binds.Add(bind);
  399. continue;
  400. }
  401. RINOK(SetProperty(name, value));
  402. }
  403. return S_OK;
  404. COM_TRY_END
  405. }
  406. }}