9 #include "../../../Windows/PropVariant.h"
11 #include "../../../Common/ComTry.h"
12 #include "../../../Common/StringToInt.h"
13 #include "../../IPassword.h"
14 #include "../../ICoder.h"
16 #include "../Common/ItemNameUtils.h"
17 #include "../Common/ParseProperties.h"
19 using namespace NWindows;
24 static const wchar_t *kLZMAMethodName = L"LZMA";
25 static const wchar_t *kCopyMethod = L"Copy";
26 static const wchar_t *kDefaultMethodName = kLZMAMethodName;
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;
34 static inline bool IsCopyMethod(const UString &methodName)
35 { return (methodName.CompareNoCase(kCopyMethod) == 0); }
37 STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
39 *type = NFileTimeType::kWindows;
43 HRESULT CHandler::SetPassword(CCompressionMethodMode &methodMode,
44 IArchiveUpdateCallback *updateCallback)
46 CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
49 CMyComPtr<IArchiveUpdateCallback> udateCallback2(updateCallback);
50 udateCallback2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
56 Int32 passwordIsDefined;
57 RINOK(getTextPassword->CryptoGetTextPassword2(
58 &passwordIsDefined, &password));
59 methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
60 if (methodMode.PasswordIsDefined)
61 methodMode.Password = password;
64 methodMode.PasswordIsDefined = false;
68 HRESULT CHandler::SetCompressionMethod(
69 CCompressionMethodMode &methodMode,
70 CCompressionMethodMode &headerMethod)
72 HRESULT res = SetCompressionMethod(methodMode, _methods
78 methodMode.Binds = _binds;
82 // headerMethod.Methods.Add(methodMode.Methods.Back());
84 CObjectVector<COneMethodInfo> headerMethodInfoVector;
85 COneMethodInfo oneMethodInfo;
86 oneMethodInfo.MethodName = kLZMAMethodName;
89 property.Id = NCoderPropID::kMatchFinder;
90 property.Value = kLzmaMatchFinderForHeaders;
91 oneMethodInfo.Properties.Add(property);
95 property.Id = NCoderPropID::kAlgorithm;
96 property.Value = kAlgorithmForHeaders;
97 oneMethodInfo.Properties.Add(property);
101 property.Id = NCoderPropID::kNumFastBytes;
102 property.Value = UInt32(kNumFastBytesForHeaders);
103 oneMethodInfo.Properties.Add(property);
107 property.Id = NCoderPropID::kDictionarySize;
108 property.Value = UInt32(kDictionaryForHeaders);
109 oneMethodInfo.Properties.Add(property);
111 headerMethodInfoVector.Add(oneMethodInfo);
112 HRESULT res = SetCompressionMethod(headerMethod, headerMethodInfoVector
122 HRESULT CHandler::SetCompressionMethod(
123 CCompressionMethodMode &methodMode,
124 CObjectVector<COneMethodInfo> &methodsInfo
130 UInt32 level = _level;
132 if (methodsInfo.IsEmpty())
134 COneMethodInfo oneMethodInfo;
135 oneMethodInfo.MethodName = ((level == 0) ? kCopyMethod : kDefaultMethodName);
136 methodsInfo.Add(oneMethodInfo);
139 bool needSolid = false;
140 for(int i = 0; i < methodsInfo.Size(); i++)
142 COneMethodInfo &oneMethodInfo = methodsInfo[i];
143 SetCompressionMethod2(oneMethodInfo
149 if (!IsCopyMethod(oneMethodInfo.MethodName))
152 CMethodFull methodFull;
156 oneMethodInfo.MethodName, methodFull.Id, methodFull.NumInStreams, methodFull.NumOutStreams))
158 methodFull.Properties = oneMethodInfo.Properties;
159 methodMode.Methods.Add(methodFull);
161 if (!_numSolidBytesDefined)
163 for (int j = 0; j < methodFull.Properties.Size(); j++)
165 const CProp &prop = methodFull.Properties[j];
166 if ((prop.Id == NCoderPropID::kDictionarySize ||
167 prop.Id == NCoderPropID::kUsedMemorySize) && prop.Value.vt == VT_UI4)
169 _numSolidBytes = ((UInt64)prop.Value.ulVal) << 7;
170 const UInt64 kMinSize = (1 << 24);
171 if (_numSolidBytes < kMinSize)
172 _numSolidBytes = kMinSize;
173 _numSolidBytesDefined = true;
180 if (!needSolid && !_numSolidBytesDefined)
182 _numSolidBytesDefined = true;
188 static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, CArchiveFileTime &filetime, bool &filetimeIsDefined)
190 filetimeIsDefined = false;
191 NCOM::CPropVariant propVariant;
192 RINOK(updateCallback->GetProperty(index, propID, &propVariant));
193 if (propVariant.vt == VT_FILETIME)
195 filetime = propVariant.filetime;
196 filetimeIsDefined = true;
198 else if (propVariant.vt != VT_EMPTY)
203 STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
204 IArchiveUpdateCallback *updateCallback)
208 const CArchiveDatabaseEx *database = 0;
210 if(_volumes.Size() > 1)
212 const CVolume *volume = 0;
213 if (_volumes.Size() == 1)
215 volume = &_volumes.Front();
216 database = &volume->Database;
220 database = &_database;
223 // CRecordVector<bool> compressStatuses;
224 CObjectVector<CUpdateItem> updateItems;
225 // CRecordVector<UInt32> copyIndices;
227 // CMyComPtr<IUpdateCallback2> updateCallback2;
228 // updateCallback->QueryInterface(&updateCallback2);
230 for(UInt32 i = 0; i < numItems; i++)
234 UInt32 indexInArchive;
237 RINOK(updateCallback->GetUpdateItemInfo(i,
238 &newData, &newProperties, &indexInArchive));
239 CUpdateItem updateItem;
240 updateItem.NewProperties = IntToBool(newProperties);
241 updateItem.NewData = IntToBool(newData);
242 updateItem.IndexInArchive = indexInArchive;
243 updateItem.IndexInClient = i;
244 updateItem.IsAnti = false;
247 if (updateItem.IndexInArchive != -1)
249 const CFileItem &fileItem = database->Files[updateItem.IndexInArchive];
250 updateItem.Name = fileItem.Name;
251 updateItem.IsDirectory = fileItem.IsDirectory;
252 updateItem.Size = fileItem.UnPackSize;
253 updateItem.IsAnti = fileItem.IsAnti;
255 updateItem.CreationTime = fileItem.CreationTime;
256 updateItem.IsCreationTimeDefined = fileItem.IsCreationTimeDefined;
257 updateItem.LastWriteTime = fileItem.LastWriteTime;
258 updateItem.IsLastWriteTimeDefined = fileItem.IsLastWriteTimeDefined;
259 updateItem.LastAccessTime = fileItem.LastAccessTime;
260 updateItem.IsLastAccessTimeDefined = fileItem.IsLastAccessTimeDefined;
263 if (updateItem.NewProperties)
266 bool folderStatusIsDefined;
268 NCOM::CPropVariant propVariant;
269 RINOK(updateCallback->GetProperty(i, kpidAttributes, &propVariant));
270 if (propVariant.vt == VT_EMPTY)
271 updateItem.AttributesAreDefined = false;
272 else if (propVariant.vt != VT_UI4)
276 updateItem.Attributes = propVariant.ulVal;
277 updateItem.AttributesAreDefined = true;
281 RINOK(GetTime(updateCallback, i, kpidCreationTime, updateItem.CreationTime, updateItem.IsCreationTimeDefined));
282 RINOK(GetTime(updateCallback, i, kpidLastWriteTime, updateItem.LastWriteTime , updateItem.IsLastWriteTimeDefined));
283 RINOK(GetTime(updateCallback, i, kpidLastAccessTime, updateItem.LastAccessTime, updateItem.IsLastAccessTimeDefined));
286 NCOM::CPropVariant propVariant;
287 RINOK(updateCallback->GetProperty(i, kpidPath, &propVariant));
288 if (propVariant.vt == VT_EMPTY)
289 nameIsDefined = false;
290 else if (propVariant.vt != VT_BSTR)
294 updateItem.Name = NItemName::MakeLegalName(propVariant.bstrVal);
295 nameIsDefined = true;
299 NCOM::CPropVariant propVariant;
300 RINOK(updateCallback->GetProperty(i, kpidIsFolder, &propVariant));
301 if (propVariant.vt == VT_EMPTY)
302 folderStatusIsDefined = false;
303 else if (propVariant.vt != VT_BOOL)
307 updateItem.IsDirectory = (propVariant.boolVal != VARIANT_FALSE);
308 folderStatusIsDefined = true;
313 NCOM::CPropVariant propVariant;
314 RINOK(updateCallback->GetProperty(i, kpidIsAnti, &propVariant));
315 if (propVariant.vt == VT_EMPTY)
316 updateItem.IsAnti = false;
317 else if (propVariant.vt != VT_BOOL)
320 updateItem.IsAnti = (propVariant.boolVal != VARIANT_FALSE);
323 if (updateItem.IsAnti)
325 updateItem.AttributesAreDefined = false;
327 updateItem.IsCreationTimeDefined = false;
328 updateItem.IsLastWriteTimeDefined = false;
329 updateItem.IsLastAccessTimeDefined = false;
334 if (!folderStatusIsDefined && updateItem.AttributesAreDefined)
335 updateItem.SetDirectoryStatusFromAttributes();
338 if (updateItem.NewData)
340 NCOM::CPropVariant propVariant;
341 RINOK(updateCallback->GetProperty(i, kpidSize, &propVariant));
342 if (propVariant.vt != VT_UI8)
344 updateItem.Size = (UInt64)propVariant.uhVal.QuadPart;
345 if (updateItem.Size != 0 && updateItem.IsAnti)
348 updateItems.Add(updateItem);
351 CCompressionMethodMode methodMode, headerMethod;
352 RINOK(SetCompressionMethod(methodMode, headerMethod));
354 methodMode.NumThreads = _numThreads;
355 headerMethod.NumThreads = 1;
358 RINOK(SetPassword(methodMode, updateCallback));
360 bool compressMainHeader = _compressHeaders; // check it
362 if (methodMode.PasswordIsDefined)
364 compressMainHeader = true;
366 RINOK(SetPassword(headerMethod, updateCallback));
370 compressMainHeader = false;
372 CUpdateOptions options;
373 options.Method = &methodMode;
374 options.HeaderMethod = (_compressHeaders ||
375 (methodMode.PasswordIsDefined && _encryptHeaders)) ?
377 options.UseFilters = _level != 0 && _autoFilter;
378 options.MaxFilter = _level >= 8;
380 options.HeaderOptions.CompressMainHeader = compressMainHeader;
381 options.HeaderOptions.WriteModified = WriteModified;
382 options.HeaderOptions.WriteCreated = WriteCreated;
383 options.HeaderOptions.WriteAccessed = WriteAccessed;
385 options.NumSolidFiles = _numSolidFiles;
386 options.NumSolidBytes = _numSolidBytes;
387 options.SolidExtension = _solidExtension;
388 options.RemoveSfxBlock = _removeSfxBlock;
389 options.VolumeMode = _volumeMode;
393 volume ? volume->Stream: 0,
394 volume ? database: 0,
399 updateItems, outStream, updateCallback, options);
403 static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
406 int index = ParseStringToUInt32(srcString, coder);
409 srcString.Delete(0, index);
410 if (srcString[0] == 'S')
413 int index = ParseStringToUInt32(srcString, stream);
416 srcString.Delete(0, index);
421 static HRESULT GetBindInfo(UString &srcString, CBind &bind)
423 RINOK(GetBindInfoPart(srcString, bind.OutCoder, bind.OutStream));
424 if (srcString[0] != ':')
427 RINOK(GetBindInfoPart(srcString, bind.InCoder, bind.InStream));
428 if (!srcString.IsEmpty())
433 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties)
439 for (int i = 0; i < numProperties; i++)
441 UString name = names[i];
446 const PROPVARIANT &value = values[i];
452 RINOK(GetBindInfo(name, bind));
457 RINOK(SetProperty(name, value));