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