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