HandlerOut.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. // HandlerOutCommon.cpp
  2. #include "StdAfx.h"
  3. #include "HandlerOut.h"
  4. #include "../../../Windows/PropVariant.h"
  5. #include "../../../Common/StringToInt.h"
  6. #include "../../ICoder.h"
  7. #include "../Common/ParseProperties.h"
  8. #ifdef COMPRESS_MT
  9. #include "../../../Windows/System.h"
  10. #endif
  11. using namespace NWindows;
  12. namespace NArchive {
  13. static const wchar_t *kCopyMethod = L"Copy";
  14. static const wchar_t *kLZMAMethodName = L"LZMA";
  15. static const wchar_t *kLZMA2MethodName = L"LZMA2";
  16. static const wchar_t *kBZip2MethodName = L"BZip2";
  17. static const wchar_t *kPpmdMethodName = L"PPMd";
  18. static const wchar_t *kDeflateMethodName = L"Deflate";
  19. static const wchar_t *kDeflate64MethodName = L"Deflate64";
  20. static const wchar_t *kLzmaMatchFinderX1 = L"HC4";
  21. static const wchar_t *kLzmaMatchFinderX5 = L"BT4";
  22. static const UInt32 kLzmaAlgoX1 = 0;
  23. static const UInt32 kLzmaAlgoX5 = 1;
  24. static const UInt32 kLzmaDicSizeX1 = 1 << 16;
  25. static const UInt32 kLzmaDicSizeX3 = 1 << 20;
  26. static const UInt32 kLzmaDicSizeX5 = 1 << 24;
  27. static const UInt32 kLzmaDicSizeX7 = 1 << 25;
  28. static const UInt32 kLzmaDicSizeX9 = 1 << 26;
  29. static const UInt32 kLzmaFastBytesX1 = 32;
  30. static const UInt32 kLzmaFastBytesX7 = 64;
  31. static const UInt32 kPpmdMemSizeX1 = (1 << 22);
  32. static const UInt32 kPpmdMemSizeX5 = (1 << 24);
  33. static const UInt32 kPpmdMemSizeX7 = (1 << 26);
  34. static const UInt32 kPpmdMemSizeX9 = (192 << 20);
  35. static const UInt32 kPpmdOrderX1 = 4;
  36. static const UInt32 kPpmdOrderX5 = 6;
  37. static const UInt32 kPpmdOrderX7 = 16;
  38. static const UInt32 kPpmdOrderX9 = 32;
  39. static const UInt32 kDeflateAlgoX1 = 0;
  40. static const UInt32 kDeflateAlgoX5 = 1;
  41. static const UInt32 kDeflateFastBytesX1 = 32;
  42. static const UInt32 kDeflateFastBytesX7 = 64;
  43. static const UInt32 kDeflateFastBytesX9 = 128;
  44. static const UInt32 kDeflatePassesX1 = 1;
  45. static const UInt32 kDeflatePassesX7 = 3;
  46. static const UInt32 kDeflatePassesX9 = 10;
  47. static const UInt32 kBZip2NumPassesX1 = 1;
  48. static const UInt32 kBZip2NumPassesX7 = 2;
  49. static const UInt32 kBZip2NumPassesX9 = 7;
  50. static const UInt32 kBZip2DicSizeX1 = 100000;
  51. static const UInt32 kBZip2DicSizeX3 = 500000;
  52. static const UInt32 kBZip2DicSizeX5 = 900000;
  53. static const wchar_t *kDefaultMethodName = kLZMAMethodName;
  54. static const wchar_t *kLzmaMatchFinderForHeaders = L"BT2";
  55. static const UInt32 kDictionaryForHeaders = 1 << 20;
  56. static const UInt32 kNumFastBytesForHeaders = 273;
  57. static const UInt32 kAlgorithmForHeaders = kLzmaAlgoX5;
  58. static bool AreEqual(const UString &methodName, const wchar_t *s)
  59. { return (methodName.CompareNoCase(s) == 0); }
  60. static inline bool IsLZMAMethod(const UString &methodName)
  61. {
  62. return
  63. AreEqual(methodName, kLZMAMethodName) ||
  64. AreEqual(methodName, kLZMA2MethodName);
  65. }
  66. static inline bool IsBZip2Method(const UString &methodName)
  67. { return AreEqual(methodName, kBZip2MethodName); }
  68. static inline bool IsPpmdMethod(const UString &methodName)
  69. { return AreEqual(methodName, kPpmdMethodName); }
  70. static inline bool IsDeflateMethod(const UString &methodName)
  71. {
  72. return
  73. AreEqual(methodName, kDeflateMethodName) ||
  74. AreEqual(methodName, kDeflate64MethodName);
  75. }
  76. struct CNameToPropID
  77. {
  78. PROPID PropID;
  79. VARTYPE VarType;
  80. const wchar_t *Name;
  81. };
  82. CNameToPropID g_NameToPropID[] =
  83. {
  84. { NCoderPropID::kOrder, VT_UI4, L"O" },
  85. { NCoderPropID::kPosStateBits, VT_UI4, L"PB" },
  86. { NCoderPropID::kLitContextBits, VT_UI4, L"LC" },
  87. { NCoderPropID::kLitPosBits, VT_UI4, L"LP" },
  88. { NCoderPropID::kEndMarker, VT_BOOL, L"eos" },
  89. { NCoderPropID::kNumPasses, VT_UI4, L"Pass" },
  90. { NCoderPropID::kNumFastBytes, VT_UI4, L"fb" },
  91. { NCoderPropID::kMatchFinderCycles, VT_UI4, L"mc" },
  92. { NCoderPropID::kAlgorithm, VT_UI4, L"a" },
  93. { NCoderPropID::kMatchFinder, VT_BSTR, L"mf" },
  94. { NCoderPropID::kNumThreads, VT_UI4, L"mt" }
  95. };
  96. static bool ConvertProperty(PROPVARIANT srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
  97. {
  98. if (varType == srcProp.vt)
  99. {
  100. destProp = srcProp;
  101. return true;
  102. }
  103. if (varType == VT_UI1)
  104. {
  105. if (srcProp.vt == VT_UI4)
  106. {
  107. UInt32 value = srcProp.ulVal;
  108. if (value > 0xFF)
  109. return false;
  110. destProp = (Byte)value;
  111. return true;
  112. }
  113. }
  114. else if (varType == VT_BOOL)
  115. {
  116. bool res;
  117. if (SetBoolProperty(res, srcProp) != S_OK)
  118. return false;
  119. destProp = res;
  120. return true;
  121. }
  122. return false;
  123. }
  124. static int FindPropIdFromStringName(const UString &name)
  125. {
  126. for (int i = 0; i < sizeof(g_NameToPropID) / sizeof(g_NameToPropID[0]); i++)
  127. if (name.CompareNoCase(g_NameToPropID[i].Name) == 0)
  128. return i;
  129. return -1;
  130. }
  131. static void SetOneMethodProp(COneMethodInfo &oneMethodInfo, PROPID propID,
  132. const NWindows::NCOM::CPropVariant &value)
  133. {
  134. for (int j = 0; j < oneMethodInfo.Properties.Size(); j++)
  135. if (oneMethodInfo.Properties[j].Id == propID)
  136. return;
  137. CProp property;
  138. property.Id = propID;
  139. property.Value = value;
  140. oneMethodInfo.Properties.Add(property);
  141. }
  142. void COutHandler::SetCompressionMethod2(COneMethodInfo &oneMethodInfo
  143. #ifdef COMPRESS_MT
  144. , UInt32 numThreads
  145. #endif
  146. )
  147. {
  148. UInt32 level = _level;
  149. if (oneMethodInfo.MethodName.IsEmpty())
  150. oneMethodInfo.MethodName = kDefaultMethodName;
  151. if (IsLZMAMethod(oneMethodInfo.MethodName))
  152. {
  153. UInt32 dicSize =
  154. (level >= 9 ? kLzmaDicSizeX9 :
  155. (level >= 7 ? kLzmaDicSizeX7 :
  156. (level >= 5 ? kLzmaDicSizeX5 :
  157. (level >= 3 ? kLzmaDicSizeX3 :
  158. kLzmaDicSizeX1))));
  159. UInt32 algo =
  160. (level >= 5 ? kLzmaAlgoX5 :
  161. kLzmaAlgoX1);
  162. UInt32 fastBytes =
  163. (level >= 7 ? kLzmaFastBytesX7 :
  164. kLzmaFastBytesX1);
  165. const wchar_t *matchFinder =
  166. (level >= 5 ? kLzmaMatchFinderX5 :
  167. kLzmaMatchFinderX1);
  168. SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
  169. SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
  170. SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
  171. SetOneMethodProp(oneMethodInfo, NCoderPropID::kMatchFinder, matchFinder);
  172. #ifdef COMPRESS_MT
  173. SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
  174. #endif
  175. }
  176. else if (IsDeflateMethod(oneMethodInfo.MethodName))
  177. {
  178. UInt32 fastBytes =
  179. (level >= 9 ? kDeflateFastBytesX9 :
  180. (level >= 7 ? kDeflateFastBytesX7 :
  181. kDeflateFastBytesX1));
  182. UInt32 numPasses =
  183. (level >= 9 ? kDeflatePassesX9 :
  184. (level >= 7 ? kDeflatePassesX7 :
  185. kDeflatePassesX1));
  186. UInt32 algo =
  187. (level >= 5 ? kDeflateAlgoX5 :
  188. kDeflateAlgoX1);
  189. SetOneMethodProp(oneMethodInfo, NCoderPropID::kAlgorithm, algo);
  190. SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumFastBytes, fastBytes);
  191. SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
  192. }
  193. else if (IsBZip2Method(oneMethodInfo.MethodName))
  194. {
  195. UInt32 numPasses =
  196. (level >= 9 ? kBZip2NumPassesX9 :
  197. (level >= 7 ? kBZip2NumPassesX7 :
  198. kBZip2NumPassesX1));
  199. UInt32 dicSize =
  200. (level >= 5 ? kBZip2DicSizeX5 :
  201. (level >= 3 ? kBZip2DicSizeX3 :
  202. kBZip2DicSizeX1));
  203. SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumPasses, numPasses);
  204. SetOneMethodProp(oneMethodInfo, NCoderPropID::kDictionarySize, dicSize);
  205. #ifdef COMPRESS_MT
  206. SetOneMethodProp(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
  207. #endif
  208. }
  209. else if (IsPpmdMethod(oneMethodInfo.MethodName))
  210. {
  211. UInt32 useMemSize =
  212. (level >= 9 ? kPpmdMemSizeX9 :
  213. (level >= 7 ? kPpmdMemSizeX7 :
  214. (level >= 5 ? kPpmdMemSizeX5 :
  215. kPpmdMemSizeX1)));
  216. UInt32 order =
  217. (level >= 9 ? kPpmdOrderX9 :
  218. (level >= 7 ? kPpmdOrderX7 :
  219. (level >= 5 ? kPpmdOrderX5 :
  220. kPpmdOrderX1)));
  221. SetOneMethodProp(oneMethodInfo, NCoderPropID::kUsedMemorySize, useMemSize);
  222. SetOneMethodProp(oneMethodInfo, NCoderPropID::kOrder, order);
  223. }
  224. }
  225. static void SplitParams(const UString &srcString, UStringVector &subStrings)
  226. {
  227. subStrings.Clear();
  228. UString name;
  229. int len = srcString.Length();
  230. if (len == 0)
  231. return;
  232. for (int i = 0; i < len; i++)
  233. {
  234. wchar_t c = srcString[i];
  235. if (c == L':')
  236. {
  237. subStrings.Add(name);
  238. name.Empty();
  239. }
  240. else
  241. name += c;
  242. }
  243. subStrings.Add(name);
  244. }
  245. static void SplitParam(const UString &param, UString &name, UString &value)
  246. {
  247. int eqPos = param.Find(L'=');
  248. if (eqPos >= 0)
  249. {
  250. name = param.Left(eqPos);
  251. value = param.Mid(eqPos + 1);
  252. return;
  253. }
  254. for(int i = 0; i < param.Length(); i++)
  255. {
  256. wchar_t c = param[i];
  257. if (c >= L'0' && c <= L'9')
  258. {
  259. name = param.Left(i);
  260. value = param.Mid(i);
  261. return;
  262. }
  263. }
  264. name = param;
  265. }
  266. HRESULT COutHandler::SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value)
  267. {
  268. CProp property;
  269. if (
  270. name.CompareNoCase(L"D") == 0 ||
  271. name.CompareNoCase(L"MEM") == 0)
  272. {
  273. UInt32 dicSize;
  274. RINOK(ParsePropDictionaryValue(value, dicSize));
  275. if (name.CompareNoCase(L"D") == 0)
  276. property.Id = NCoderPropID::kDictionarySize;
  277. else
  278. property.Id = NCoderPropID::kUsedMemorySize;
  279. property.Value = dicSize;
  280. oneMethodInfo.Properties.Add(property);
  281. }
  282. else
  283. {
  284. int index = FindPropIdFromStringName(name);
  285. if (index < 0)
  286. return E_INVALIDARG;
  287. const CNameToPropID &nameToPropID = g_NameToPropID[index];
  288. property.Id = nameToPropID.PropID;
  289. NCOM::CPropVariant propValue;
  290. if (nameToPropID.VarType == VT_BSTR)
  291. propValue = value;
  292. else if (nameToPropID.VarType == VT_BOOL)
  293. {
  294. bool res;
  295. if (!StringToBool(value, res))
  296. return E_INVALIDARG;
  297. propValue = res;
  298. }
  299. else
  300. {
  301. UInt32 number;
  302. if (ParseStringToUInt32(value, number) == value.Length())
  303. propValue = number;
  304. else
  305. propValue = value;
  306. }
  307. if (!ConvertProperty(propValue, nameToPropID.VarType, property.Value))
  308. return E_INVALIDARG;
  309. oneMethodInfo.Properties.Add(property);
  310. }
  311. return S_OK;
  312. }
  313. HRESULT COutHandler::SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString)
  314. {
  315. UStringVector params;
  316. SplitParams(srcString, params);
  317. if (params.Size() > 0)
  318. oneMethodInfo.MethodName = params[0];
  319. for (int i = 1; i < params.Size(); i++)
  320. {
  321. const UString &param = params[i];
  322. UString name, value;
  323. SplitParam(param, name, value);
  324. RINOK(SetParam(oneMethodInfo, name, value));
  325. }
  326. return S_OK;
  327. }
  328. HRESULT COutHandler::SetSolidSettings(const UString &s)
  329. {
  330. bool res;
  331. if (StringToBool(s, res))
  332. {
  333. if (res)
  334. InitSolid();
  335. else
  336. _numSolidFiles = 1;
  337. return S_OK;
  338. }
  339. UString s2 = s;
  340. s2.MakeUpper();
  341. for (int i = 0; i < s2.Length();)
  342. {
  343. const wchar_t *start = ((const wchar_t *)s2) + i;
  344. const wchar_t *end;
  345. UInt64 v = ConvertStringToUInt64(start, &end);
  346. if (start == end)
  347. {
  348. if (s2[i++] != 'E')
  349. return E_INVALIDARG;
  350. _solidExtension = true;
  351. continue;
  352. }
  353. i += (int)(end - start);
  354. if (i == s2.Length())
  355. return E_INVALIDARG;
  356. wchar_t c = s2[i++];
  357. switch(c)
  358. {
  359. case 'F':
  360. if (v < 1)
  361. v = 1;
  362. _numSolidFiles = v;
  363. break;
  364. case 'B':
  365. _numSolidBytes = v;
  366. _numSolidBytesDefined = true;
  367. break;
  368. case 'K':
  369. _numSolidBytes = (v << 10);
  370. _numSolidBytesDefined = true;
  371. break;
  372. case 'M':
  373. _numSolidBytes = (v << 20);
  374. _numSolidBytesDefined = true;
  375. break;
  376. case 'G':
  377. _numSolidBytes = (v << 30);
  378. _numSolidBytesDefined = true;
  379. break;
  380. default:
  381. return E_INVALIDARG;
  382. }
  383. }
  384. return S_OK;
  385. }
  386. HRESULT COutHandler::SetSolidSettings(const PROPVARIANT &value)
  387. {
  388. switch(value.vt)
  389. {
  390. case VT_EMPTY:
  391. InitSolid();
  392. return S_OK;
  393. case VT_BSTR:
  394. return SetSolidSettings(value.bstrVal);
  395. default:
  396. return E_INVALIDARG;
  397. }
  398. }
  399. void COutHandler::Init()
  400. {
  401. _removeSfxBlock = false;
  402. _compressHeaders = true;
  403. _encryptHeaders = false;
  404. WriteModified = true;
  405. WriteCreated = false;
  406. WriteAccessed = false;
  407. #ifdef COMPRESS_MT
  408. _numThreads = NWindows::NSystem::GetNumberOfProcessors();
  409. #endif
  410. _level = 5;
  411. _autoFilter = true;
  412. _volumeMode = false;
  413. _crcSize = 4;
  414. InitSolid();
  415. }
  416. void COutHandler::BeforeSetProperty()
  417. {
  418. Init();
  419. #ifdef COMPRESS_MT
  420. numProcessors = NSystem::GetNumberOfProcessors();
  421. #endif
  422. mainDicSize = 0xFFFFFFFF;
  423. mainDicMethodIndex = 0xFFFFFFFF;
  424. minNumber = 0;
  425. _crcSize = 4;
  426. }
  427. HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
  428. {
  429. UString name = nameSpec;
  430. name.MakeUpper();
  431. if (name.IsEmpty())
  432. return E_INVALIDARG;
  433. if (name[0] == 'X')
  434. {
  435. name.Delete(0);
  436. _level = 9;
  437. return ParsePropValue(name, value, _level);
  438. }
  439. if (name[0] == L'S')
  440. {
  441. name.Delete(0);
  442. if (name.IsEmpty())
  443. return SetSolidSettings(value);
  444. if (value.vt != VT_EMPTY)
  445. return E_INVALIDARG;
  446. return SetSolidSettings(name);
  447. }
  448. if (name == L"CRC")
  449. {
  450. _crcSize = 4;
  451. name.Delete(0, 3);
  452. return ParsePropValue(name, value, _crcSize);
  453. }
  454. UInt32 number;
  455. int index = ParseStringToUInt32(name, number);
  456. UString realName = name.Mid(index);
  457. if (index == 0)
  458. {
  459. if(name.Left(2).CompareNoCase(L"MT") == 0)
  460. {
  461. #ifdef COMPRESS_MT
  462. RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads));
  463. #endif
  464. return S_OK;
  465. }
  466. if (name.CompareNoCase(L"RSFX") == 0)
  467. return SetBoolProperty(_removeSfxBlock, value);
  468. if (name.CompareNoCase(L"F") == 0)
  469. return SetBoolProperty(_autoFilter, value);
  470. if (name.CompareNoCase(L"HC") == 0)
  471. return SetBoolProperty(_compressHeaders, value);
  472. if (name.CompareNoCase(L"HCF") == 0)
  473. {
  474. bool compressHeadersFull = true;
  475. RINOK(SetBoolProperty(compressHeadersFull, value));
  476. if (!compressHeadersFull)
  477. return E_INVALIDARG;
  478. return S_OK;
  479. }
  480. if (name.CompareNoCase(L"HE") == 0)
  481. return SetBoolProperty(_encryptHeaders, value);
  482. if (name.CompareNoCase(L"TM") == 0)
  483. return SetBoolProperty(WriteModified, value);
  484. if (name.CompareNoCase(L"TC") == 0)
  485. return SetBoolProperty(WriteCreated, value);
  486. if (name.CompareNoCase(L"TA") == 0)
  487. return SetBoolProperty(WriteAccessed, value);
  488. if (name.CompareNoCase(L"V") == 0)
  489. return SetBoolProperty(_volumeMode, value);
  490. number = 0;
  491. }
  492. if (number > 10000)
  493. return E_FAIL;
  494. if (number < minNumber)
  495. return E_INVALIDARG;
  496. number -= minNumber;
  497. for(int j = _methods.Size(); j <= (int)number; j++)
  498. {
  499. COneMethodInfo oneMethodInfo;
  500. _methods.Add(oneMethodInfo);
  501. }
  502. COneMethodInfo &oneMethodInfo = _methods[number];
  503. if (realName.Length() == 0)
  504. {
  505. if (value.vt != VT_BSTR)
  506. return E_INVALIDARG;
  507. RINOK(SetParams(oneMethodInfo, value.bstrVal));
  508. }
  509. else
  510. {
  511. CProp property;
  512. if (realName.Left(1).CompareNoCase(L"D") == 0)
  513. {
  514. UInt32 dicSize;
  515. RINOK(ParsePropDictionaryValue(realName.Mid(1), value, dicSize));
  516. property.Id = NCoderPropID::kDictionarySize;
  517. property.Value = dicSize;
  518. oneMethodInfo.Properties.Add(property);
  519. if (number <= mainDicMethodIndex)
  520. mainDicSize = dicSize;
  521. }
  522. else if (realName.Left(3).CompareNoCase(L"MEM") == 0)
  523. {
  524. UInt32 dicSize;
  525. RINOK(ParsePropDictionaryValue(realName.Mid(3), value, dicSize));
  526. property.Id = NCoderPropID::kUsedMemorySize;
  527. property.Value = dicSize;
  528. oneMethodInfo.Properties.Add(property);
  529. if (number <= mainDicMethodIndex)
  530. mainDicSize = dicSize;
  531. }
  532. else
  533. {
  534. int index = FindPropIdFromStringName(realName);
  535. if (index < 0)
  536. return E_INVALIDARG;
  537. const CNameToPropID &nameToPropID = g_NameToPropID[index];
  538. property.Id = nameToPropID.PropID;
  539. if (!ConvertProperty(value, nameToPropID.VarType, property.Value))
  540. return E_INVALIDARG;
  541. oneMethodInfo.Properties.Add(property);
  542. }
  543. }
  544. return S_OK;
  545. }
  546. }