1 // 7zHandlerOut.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/ComTry.h"
6 #include "../../../Common/StringToInt.h"
7 #include "../../../Common/Wildcard.h"
8
9 #include "../Common/ItemNameUtils.h"
10 #include "../Common/ParseProperties.h"
11
12 #include "7zHandler.h"
13 #include "7zOut.h"
14 #include "7zUpdate.h"
15
16 using namespace NWindows;
17
18 namespace NArchive {
19 namespace N7z {
20
21 static const wchar_t *k_LZMA_Name = L"LZMA";
22 static const wchar_t *kDefaultMethodName = L"LZMA2";
23 static const wchar_t *k_Copy_Name = L"Copy";
24
25 static const wchar_t *k_MatchFinder_ForHeaders = L"BT2";
26 static const UInt32 k_NumFastBytes_ForHeaders = 273;
27 static const UInt32 k_Level_ForHeaders = 5;
28 static const UInt32 k_Dictionary_ForHeaders =
29 #ifdef UNDER_CE
30 1 << 18;
31 #else
32 1 << 20;
33 #endif
34
GetFileTimeType(UInt32 * type)35 STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
36 {
37 *type = NFileTimeType::kWindows;
38 return S_OK;
39 }
40
PropsMethod_To_FullMethod(CMethodFull & dest,const COneMethodInfo & m)41 HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
42 {
43 if (!FindMethod(
44 EXTERNAL_CODECS_VARS
45 m.MethodName, dest.Id, dest.NumInStreams, dest.NumOutStreams))
46 return E_INVALIDARG;
47 (CProps &)dest = (CProps &)m;
48 return S_OK;
49 }
50
SetHeaderMethod(CCompressionMethodMode & headerMethod)51 HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
52 {
53 if (!_compressHeaders)
54 return S_OK;
55 COneMethodInfo m;
56 m.MethodName = k_LZMA_Name;
57 m.AddPropString(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
58 m.AddProp32(NCoderPropID::kLevel, k_Level_ForHeaders);
59 m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
60 m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
61 m.AddNumThreadsProp(1);
62
63 CMethodFull methodFull;
64 RINOK(PropsMethod_To_FullMethod(methodFull, m));
65 headerMethod.Methods.Add(methodFull);
66 return S_OK;
67 }
68
AddDefaultMethod()69 void CHandler::AddDefaultMethod()
70 {
71 FOR_VECTOR (i, _methods)
72 {
73 UString &methodName = _methods[i].MethodName;
74 if (methodName.IsEmpty())
75 methodName = kDefaultMethodName;
76 }
77 if (_methods.IsEmpty())
78 {
79 COneMethodInfo m;
80 m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
81 _methods.Add(m);
82 }
83 }
84
SetMainMethod(CCompressionMethodMode & methodMode,CObjectVector<COneMethodInfo> & methods,UInt32 numThreads)85 HRESULT CHandler::SetMainMethod(
86 CCompressionMethodMode &methodMode,
87 CObjectVector<COneMethodInfo> &methods
88 #ifndef _7ZIP_ST
89 , UInt32 numThreads
90 #endif
91 )
92 {
93 AddDefaultMethod();
94
95 const UInt64 kSolidBytes_Min = (1 << 24);
96 const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1;
97
98 bool needSolid = false;
99 FOR_VECTOR (i, methods)
100 {
101 COneMethodInfo &oneMethodInfo = methods[i];
102 SetGlobalLevelAndThreads(oneMethodInfo
103 #ifndef _7ZIP_ST
104 , numThreads
105 #endif
106 );
107
108 CMethodFull methodFull;
109 RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));
110 methodMode.Methods.Add(methodFull);
111
112 if (methodFull.Id != k_Copy)
113 needSolid = true;
114
115 if (_numSolidBytesDefined)
116 continue;
117
118 UInt32 dicSize;
119 switch (methodFull.Id)
120 {
121 case k_LZMA:
122 case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
123 case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
124 case k_Deflate: dicSize = (UInt32)1 << 15; break;
125 case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
126 default: continue;
127 }
128 _numSolidBytes = (UInt64)dicSize << 7;
129 if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min;
130 if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max;
131 _numSolidBytesDefined = true;
132 }
133
134 if (!_numSolidBytesDefined)
135 if (needSolid)
136 _numSolidBytes = kSolidBytes_Max;
137 else
138 _numSolidBytes = 0;
139 _numSolidBytesDefined = true;
140 return S_OK;
141 }
142
GetTime(IArchiveUpdateCallback * updateCallback,int index,PROPID propID,UInt64 & ft,bool & ftDefined)143 static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined)
144 {
145 // ft = 0;
146 // ftDefined = false;
147 NCOM::CPropVariant prop;
148 RINOK(updateCallback->GetProperty(index, propID, &prop));
149 if (prop.vt == VT_FILETIME)
150 {
151 ft = prop.filetime.dwLowDateTime | ((UInt64)prop.filetime.dwHighDateTime << 32);
152 ftDefined = true;
153 }
154 else if (prop.vt != VT_EMPTY)
155 return E_INVALIDARG;
156 else
157 {
158 ft = 0;
159 ftDefined = false;
160 }
161 return S_OK;
162 }
163
164 /*
165
166 #ifdef _WIN32
167 static const wchar_t kDirDelimiter1 = L'\\';
168 #endif
169 static const wchar_t kDirDelimiter2 = L'/';
170
171 static inline bool IsCharDirLimiter(wchar_t c)
172 {
173 return (
174 #ifdef _WIN32
175 c == kDirDelimiter1 ||
176 #endif
177 c == kDirDelimiter2);
178 }
179
180 static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
181 {
182 CTreeFolder &tf = treeFolders[cur];
183 tf.SortIndex = curSortIndex++;
184 for (int i = 0; i < tf.SubFolders.Size(); i++)
185 curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
186 tf.SortIndexEnd = curSortIndex;
187 return curSortIndex;
188 }
189
190 static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
191 {
192 const CIntVector &subFolders = treeFolders[cur].SubFolders;
193 int left = 0, right = subFolders.Size();
194 insertPos = -1;
195 for (;;)
196 {
197 if (left == right)
198 {
199 insertPos = left;
200 return -1;
201 }
202 int mid = (left + right) / 2;
203 int midFolder = subFolders[mid];
204 int compare = CompareFileNames(name, treeFolders[midFolder].Name);
205 if (compare == 0)
206 return midFolder;
207 if (compare < 0)
208 right = mid;
209 else
210 left = mid + 1;
211 }
212 }
213
214 static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
215 {
216 int insertPos;
217 int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
218 if (folderIndex < 0)
219 {
220 folderIndex = treeFolders.Size();
221 CTreeFolder &newFolder = treeFolders.AddNew();
222 newFolder.Parent = cur;
223 newFolder.Name = name;
224 treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
225 }
226 // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
227 return folderIndex;
228 }
229 */
230
UpdateItems(ISequentialOutStream * outStream,UInt32 numItems,IArchiveUpdateCallback * updateCallback)231 STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
232 IArchiveUpdateCallback *updateCallback)
233 {
234 COM_TRY_BEGIN
235
236 const CDbEx *db = 0;
237 #ifdef _7Z_VOL
238 if (_volumes.Size() > 1)
239 return E_FAIL;
240 const CVolume *volume = 0;
241 if (_volumes.Size() == 1)
242 {
243 volume = &_volumes.Front();
244 db = &volume->Database;
245 }
246 #else
247 if (_inStream != 0)
248 db = &_db;
249 #endif
250
251 /*
252 CMyComPtr<IArchiveGetRawProps> getRawProps;
253 updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
254
255 CUniqBlocks secureBlocks;
256 secureBlocks.AddUniq(NULL, 0);
257
258 CObjectVector<CTreeFolder> treeFolders;
259 {
260 CTreeFolder folder;
261 folder.Parent = -1;
262 treeFolders.Add(folder);
263 }
264 */
265
266 CObjectVector<CUpdateItem> updateItems;
267
268 bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
269 bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
270 bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);
271 if (db)
272 {
273 if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
274 if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
275 if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
276 }
277
278 UString s;
279
280 for (UInt32 i = 0; i < numItems; i++)
281 {
282 Int32 newData, newProps;
283 UInt32 indexInArchive;
284 if (!updateCallback)
285 return E_FAIL;
286 RINOK(updateCallback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));
287 CUpdateItem ui;
288 ui.NewProps = IntToBool(newProps);
289 ui.NewData = IntToBool(newData);
290 ui.IndexInArchive = indexInArchive;
291 ui.IndexInClient = i;
292 ui.IsAnti = false;
293 ui.Size = 0;
294
295 UString name;
296 // bool isAltStream = false;
297 if (ui.IndexInArchive != -1)
298 {
299 if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size())
300 return E_INVALIDARG;
301 const CFileItem &fi = db->Files[ui.IndexInArchive];
302 if (!ui.NewProps)
303 {
304 _db.GetPath(ui.IndexInArchive, name);
305 }
306 ui.IsDir = fi.IsDir;
307 ui.Size = fi.Size;
308 // isAltStream = fi.IsAltStream;
309 ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
310
311 if (!ui.NewProps)
312 {
313 ui.CTimeDefined = db->CTime.GetItem(ui.IndexInArchive, ui.CTime);
314 ui.ATimeDefined = db->ATime.GetItem(ui.IndexInArchive, ui.ATime);
315 ui.MTimeDefined = db->MTime.GetItem(ui.IndexInArchive, ui.MTime);
316 }
317 }
318
319 if (ui.NewProps)
320 {
321 bool folderStatusIsDefined;
322 {
323 NCOM::CPropVariant prop;
324 RINOK(updateCallback->GetProperty(i, kpidAttrib, &prop));
325 if (prop.vt == VT_EMPTY)
326 ui.AttribDefined = false;
327 else if (prop.vt != VT_UI4)
328 return E_INVALIDARG;
329 else
330 {
331 ui.Attrib = prop.ulVal;
332 ui.AttribDefined = true;
333 }
334 }
335
336 // we need MTime to sort files.
337 if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined));
338 if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined));
339 if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined));
340
341 /*
342 if (getRawProps)
343 {
344 const void *data;
345 UInt32 dataSize;
346 UInt32 propType;
347
348 getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
349 if (dataSize != 0 && propType != NPropDataType::kRaw)
350 return E_FAIL;
351 ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
352 }
353 */
354
355 {
356 NCOM::CPropVariant prop;
357 RINOK(updateCallback->GetProperty(i, kpidPath, &prop));
358 if (prop.vt == VT_EMPTY)
359 {
360 }
361 else if (prop.vt != VT_BSTR)
362 return E_INVALIDARG;
363 else
364 {
365 name = NItemName::MakeLegalName(prop.bstrVal);
366 }
367 }
368 {
369 NCOM::CPropVariant prop;
370 RINOK(updateCallback->GetProperty(i, kpidIsDir, &prop));
371 if (prop.vt == VT_EMPTY)
372 folderStatusIsDefined = false;
373 else if (prop.vt != VT_BOOL)
374 return E_INVALIDARG;
375 else
376 {
377 ui.IsDir = (prop.boolVal != VARIANT_FALSE);
378 folderStatusIsDefined = true;
379 }
380 }
381
382 {
383 NCOM::CPropVariant prop;
384 RINOK(updateCallback->GetProperty(i, kpidIsAnti, &prop));
385 if (prop.vt == VT_EMPTY)
386 ui.IsAnti = false;
387 else if (prop.vt != VT_BOOL)
388 return E_INVALIDARG;
389 else
390 ui.IsAnti = (prop.boolVal != VARIANT_FALSE);
391 }
392
393 /*
394 {
395 NCOM::CPropVariant prop;
396 RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
397 if (prop.vt == VT_EMPTY)
398 isAltStream = false;
399 else if (prop.vt != VT_BOOL)
400 return E_INVALIDARG;
401 else
402 isAltStream = (prop.boolVal != VARIANT_FALSE);
403 }
404 */
405
406 if (ui.IsAnti)
407 {
408 ui.AttribDefined = false;
409
410 ui.CTimeDefined = false;
411 ui.ATimeDefined = false;
412 ui.MTimeDefined = false;
413
414 ui.Size = 0;
415 }
416
417 if (!folderStatusIsDefined && ui.AttribDefined)
418 ui.SetDirStatusFromAttrib();
419 }
420 else
421 {
422 /*
423 if (_db.SecureIDs.IsEmpty())
424 ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
425 else
426 {
427 int id = _db.SecureIDs[ui.IndexInArchive];
428 size_t offs = _db.SecureOffsets[id];
429 size_t size = _db.SecureOffsets[id + 1] - offs;
430 ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
431 }
432 */
433 }
434
435 /*
436 {
437 int folderIndex = 0;
438 if (_useParents)
439 {
440 int j;
441 s.Empty();
442 for (j = 0; j < name.Len(); j++)
443 {
444 wchar_t c = name[j];
445 if (IsCharDirLimiter(c))
446 {
447 folderIndex = AddFolder(treeFolders, folderIndex, s);
448 s.Empty();
449 continue;
450 }
451 s += c;
452 }
453 if (isAltStream)
454 {
455 int colonPos = s.Find(':');
456 if (colonPos < 0)
457 {
458 // isAltStream = false;
459 return E_INVALIDARG;
460 }
461 UString mainName = s.Left(colonPos);
462 int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
463 if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
464 {
465 for (int j = updateItems.Size() - 1; j >= 0; j--)
466 {
467 CUpdateItem &ui2 = updateItems[j];
468 if (ui2.ParentFolderIndex == folderIndex
469 && ui2.Name == mainName)
470 {
471 ui2.TreeFolderIndex = newFolderIndex;
472 treeFolders[newFolderIndex].UpdateItemIndex = j;
473 }
474 }
475 }
476 folderIndex = newFolderIndex;
477 s.Delete(0, colonPos + 1);
478 }
479 ui.Name = s;
480 }
481 else
482 ui.Name = name;
483 ui.IsAltStream = isAltStream;
484 ui.ParentFolderIndex = folderIndex;
485 ui.TreeFolderIndex = -1;
486 if (ui.IsDir && !s.IsEmpty())
487 {
488 ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
489 treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
490 }
491 }
492 */
493 ui.Name = name;
494
495 if (ui.NewData)
496 {
497 NCOM::CPropVariant prop;
498 RINOK(updateCallback->GetProperty(i, kpidSize, &prop));
499 if (prop.vt != VT_UI8)
500 return E_INVALIDARG;
501 ui.Size = (UInt64)prop.uhVal.QuadPart;
502 if (ui.Size != 0 && ui.IsAnti)
503 return E_INVALIDARG;
504 }
505 updateItems.Add(ui);
506 }
507
508 /*
509 FillSortIndex(treeFolders, 0, 0);
510 for (i = 0; i < (UInt32)updateItems.Size(); i++)
511 {
512 CUpdateItem &ui = updateItems[i];
513 ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
514 ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
515 }
516 */
517
518 CCompressionMethodMode methodMode, headerMethod;
519
520 HRESULT res = SetMainMethod(methodMode, _methods
521 #ifndef _7ZIP_ST
522 , _numThreads
523 #endif
524 );
525 RINOK(res);
526 methodMode.Binds = _binds;
527
528 RINOK(SetHeaderMethod(headerMethod));
529 #ifndef _7ZIP_ST
530 methodMode.NumThreads = _numThreads;
531 headerMethod.NumThreads = 1;
532 #endif
533
534 CMyComPtr<ICryptoGetTextPassword2> getPassword2;
535 updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
536
537 methodMode.PasswordIsDefined = false;
538 methodMode.Password.Empty();
539 if (getPassword2)
540 {
541 CMyComBSTR password;
542 Int32 passwordIsDefined;
543 RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
544 methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
545 if (methodMode.PasswordIsDefined && (BSTR)password)
546 methodMode.Password = password;
547 }
548
549 bool compressMainHeader = _compressHeaders; // check it
550
551 bool encryptHeaders = false;
552
553 if (methodMode.PasswordIsDefined)
554 {
555 if (_encryptHeadersSpecified)
556 encryptHeaders = _encryptHeaders;
557 #ifndef _NO_CRYPTO
558 else
559 encryptHeaders = _passwordIsDefined;
560 #endif
561 compressMainHeader = true;
562 if (encryptHeaders)
563 {
564 headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
565 headerMethod.Password = methodMode.Password;
566 }
567 }
568
569 if (numItems < 2)
570 compressMainHeader = false;
571
572 CUpdateOptions options;
573 options.Method = &methodMode;
574 options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : 0;
575 int level = GetLevel();
576 options.UseFilters = level != 0 && _autoFilter;
577 options.MaxFilter = level >= 8;
578
579 options.HeaderOptions.CompressMainHeader = compressMainHeader;
580 /*
581 options.HeaderOptions.WriteCTime = Write_CTime;
582 options.HeaderOptions.WriteATime = Write_ATime;
583 options.HeaderOptions.WriteMTime = Write_MTime;
584 */
585
586 options.NumSolidFiles = _numSolidFiles;
587 options.NumSolidBytes = _numSolidBytes;
588 options.SolidExtension = _solidExtension;
589 options.RemoveSfxBlock = _removeSfxBlock;
590 options.VolumeMode = _volumeMode;
591
592 COutArchive archive;
593 CArchiveDatabaseOut newDatabase;
594
595 CMyComPtr<ICryptoGetTextPassword> getPassword;
596 updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
597
598 /*
599 if (secureBlocks.Sorted.Size() > 1)
600 {
601 secureBlocks.GetReverseMap();
602 for (int i = 0; i < updateItems.Size(); i++)
603 {
604 int &secureIndex = updateItems[i].SecureIndex;
605 secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
606 }
607 }
608 */
609
610 res = Update(
611 EXTERNAL_CODECS_VARS
612 #ifdef _7Z_VOL
613 volume ? volume->Stream: 0,
614 volume ? db : 0,
615 #else
616 _inStream,
617 db,
618 #endif
619 updateItems,
620 // treeFolders,
621 // secureBlocks,
622 archive, newDatabase, outStream, updateCallback, options
623 #ifndef _NO_CRYPTO
624 , getPassword
625 #endif
626 );
627
628 RINOK(res);
629
630 updateItems.ClearAndFree();
631
632 return archive.WriteDatabase(EXTERNAL_CODECS_VARS
633 newDatabase, options.HeaderMethod, options.HeaderOptions);
634
635 COM_TRY_END
636 }
637
GetBindInfoPart(UString & srcString,UInt32 & coder,UInt32 & stream)638 static HRESULT GetBindInfoPart(UString &srcString, UInt32 &coder, UInt32 &stream)
639 {
640 stream = 0;
641 int index = ParseStringToUInt32(srcString, coder);
642 if (index == 0)
643 return E_INVALIDARG;
644 srcString.Delete(0, index);
645 if (srcString[0] == 's')
646 {
647 srcString.Delete(0);
648 int index = ParseStringToUInt32(srcString, stream);
649 if (index == 0)
650 return E_INVALIDARG;
651 srcString.Delete(0, index);
652 }
653 return S_OK;
654 }
655
InitProps()656 void COutHandler::InitProps()
657 {
658 CMultiMethodProps::Init();
659
660 _removeSfxBlock = false;
661 _compressHeaders = true;
662 _encryptHeadersSpecified = false;
663 _encryptHeaders = false;
664 // _useParents = false;
665
666 Write_CTime.Init();
667 Write_ATime.Init();
668 Write_MTime.Init();
669
670 _volumeMode = false;
671 InitSolid();
672 }
673
SetSolidFromString(const UString & s)674 HRESULT COutHandler::SetSolidFromString(const UString &s)
675 {
676 UString s2 = s;
677 s2.MakeLower_Ascii();
678 for (unsigned i = 0; i < s2.Len();)
679 {
680 const wchar_t *start = ((const wchar_t *)s2) + i;
681 const wchar_t *end;
682 UInt64 v = ConvertStringToUInt64(start, &end);
683 if (start == end)
684 {
685 if (s2[i++] != 'e')
686 return E_INVALIDARG;
687 _solidExtension = true;
688 continue;
689 }
690 i += (int)(end - start);
691 if (i == s2.Len())
692 return E_INVALIDARG;
693 wchar_t c = s2[i++];
694 if (c == 'f')
695 {
696 if (v < 1)
697 v = 1;
698 _numSolidFiles = v;
699 }
700 else
701 {
702 unsigned numBits;
703 switch (c)
704 {
705 case 'b': numBits = 0; break;
706 case 'k': numBits = 10; break;
707 case 'm': numBits = 20; break;
708 case 'g': numBits = 30; break;
709 case 't': numBits = 40; break;
710 default: return E_INVALIDARG;
711 }
712 _numSolidBytes = (v << numBits);
713 _numSolidBytesDefined = true;
714 }
715 }
716 return S_OK;
717 }
718
SetSolidFromPROPVARIANT(const PROPVARIANT & value)719 HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
720 {
721 bool isSolid;
722 switch (value.vt)
723 {
724 case VT_EMPTY: isSolid = true; break;
725 case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
726 case VT_BSTR:
727 if (StringToBool(value.bstrVal, isSolid))
728 break;
729 return SetSolidFromString(value.bstrVal);
730 default: return E_INVALIDARG;
731 }
732 if (isSolid)
733 InitSolid();
734 else
735 _numSolidFiles = 1;
736 return S_OK;
737 }
738
PROPVARIANT_to_BoolPair(const PROPVARIANT & prop,CBoolPair & dest)739 static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
740 {
741 RINOK(PROPVARIANT_to_bool(prop, dest.Val));
742 dest.Def = true;
743 return S_OK;
744 }
745
SetProperty(const wchar_t * nameSpec,const PROPVARIANT & value)746 HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
747 {
748 UString name = nameSpec;
749 name.MakeLower_Ascii();
750 if (name.IsEmpty())
751 return E_INVALIDARG;
752
753 if (name[0] == L's')
754 {
755 name.Delete(0);
756 if (name.IsEmpty())
757 return SetSolidFromPROPVARIANT(value);
758 if (value.vt != VT_EMPTY)
759 return E_INVALIDARG;
760 return SetSolidFromString(name);
761 }
762
763 UInt32 number;
764 int index = ParseStringToUInt32(name, number);
765 UString realName = name.Ptr(index);
766 if (index == 0)
767 {
768 if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
769 if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
770 // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
771
772 if (name.IsEqualTo("hcf"))
773 {
774 bool compressHeadersFull = true;
775 RINOK(PROPVARIANT_to_bool(value, compressHeadersFull));
776 return compressHeadersFull ? S_OK: E_INVALIDARG;
777 }
778
779 if (name.IsEqualTo("he"))
780 {
781 RINOK(PROPVARIANT_to_bool(value, _encryptHeaders));
782 _encryptHeadersSpecified = true;
783 return S_OK;
784 }
785
786 if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime);
787 if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime);
788 if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime);
789
790 if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
791 }
792 return CMultiMethodProps::SetProperty(name, value);
793 }
794
SetProperties(const wchar_t ** names,const PROPVARIANT * values,UInt32 numProps)795 STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, UInt32 numProps)
796 {
797 COM_TRY_BEGIN
798 _binds.Clear();
799 InitProps();
800
801 for (UInt32 i = 0; i < numProps; i++)
802 {
803 UString name = names[i];
804 name.MakeLower_Ascii();
805 if (name.IsEmpty())
806 return E_INVALIDARG;
807
808 const PROPVARIANT &value = values[i];
809
810 if (name[0] == 'b')
811 {
812 if (value.vt != VT_EMPTY)
813 return E_INVALIDARG;
814 name.Delete(0);
815 CBind bind;
816 RINOK(GetBindInfoPart(name, bind.OutCoder, bind.OutStream));
817 if (name[0] != ':')
818 return E_INVALIDARG;
819 name.Delete(0);
820 RINOK(GetBindInfoPart(name, bind.InCoder, bind.InStream));
821 if (!name.IsEmpty())
822 return E_INVALIDARG;
823 _binds.Add(bind);
824 continue;
825 }
826
827 RINOK(SetProperty(name, value));
828 }
829
830 unsigned numEmptyMethods = GetNumEmptyMethods();
831 if (numEmptyMethods > 0)
832 {
833 unsigned k;
834 for (k = 0; k < _binds.Size(); k++)
835 {
836 const CBind &bind = _binds[k];
837 if (bind.InCoder < (UInt32)numEmptyMethods ||
838 bind.OutCoder < (UInt32)numEmptyMethods)
839 return E_INVALIDARG;
840 }
841 for (k = 0; k < _binds.Size(); k++)
842 {
843 CBind &bind = _binds[k];
844 bind.InCoder -= (UInt32)numEmptyMethods;
845 bind.OutCoder -= (UInt32)numEmptyMethods;
846 }
847 _methods.DeleteFrontal(numEmptyMethods);
848 }
849
850 AddDefaultMethod();
851
852 if (!_filterMethod.MethodName.IsEmpty())
853 {
854 FOR_VECTOR (k, _binds)
855 {
856 CBind &bind = _binds[k];
857 bind.InCoder++;
858 bind.OutCoder++;
859 }
860 _methods.Insert(0, _filterMethod);
861 }
862
863 FOR_VECTOR (k, _binds)
864 {
865 const CBind &bind = _binds[k];
866 if (bind.InCoder >= (UInt32)_methods.Size() ||
867 bind.OutCoder >= (UInt32)_methods.Size())
868 return E_INVALIDARG;
869 }
870
871 return S_OK;
872 COM_TRY_END
873 }
874
875 }}
876