xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Far/PluginWrite.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // PluginWrite.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <stdio.h>
6 
7 #include "Plugin.h"
8 
9 #include "../../../Common/StringConvert.h"
10 #include "../../../Common/Wildcard.h"
11 
12 #include "../../../Windows/FileName.h"
13 #include "../../../Windows/FileFind.h"
14 
15 #include "../Common/ZipRegistry.h"
16 
17 #include "../Agent/Agent.h"
18 
19 #include "ProgressBox.h"
20 #include "Messages.h"
21 #include "UpdateCallbackFar.h"
22 
23 using namespace NWindows;
24 using namespace NFile;
25 using namespace NDir;
26 using namespace NFar;
27 
28 using namespace NUpdateArchive;
29 
30 static const char * const kHelpTopic = "Update";
31 
32 static const char * const kArchiveHistoryKeyName = "7-ZipArcName";
33 
34 static const UInt32 g_MethodMap[] = { 0, 1, 3, 5, 7, 9 };
35 
SetOutProperties(IOutFolderArchive * outArchive,UInt32 method)36 static HRESULT SetOutProperties(IOutFolderArchive *outArchive, UInt32 method)
37 {
38   CMyComPtr<ISetProperties> setProperties;
39   if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK)
40   {
41     /*
42     UStringVector realNames;
43     realNames.Add(UString("x"));
44     NCOM::CPropVariant value = (UInt32)method;
45     CRecordVector<const wchar_t *> names;
46     FOR_VECTOR (i, realNames)
47       names.Add(realNames[i]);
48     RINOK(setProperties->SetProperties(&names.Front(), &value, names.Size()));
49     */
50     NCOM::CPropVariant value = (UInt32)method;
51     const wchar_t *name = L"x";
52     RINOK(setProperties->SetProperties(&name, &value, 1))
53   }
54   return S_OK;
55 }
56 
57 /*
58 HRESULT CPlugin::AfterUpdate(CWorkDirTempFile &tempFile, const UStringVector &pathVector)
59 {
60   _folder.Release();
61   m_ArchiveHandler->Close();
62 
63   RINOK(tempFile.MoveToOriginal(true));
64 
65   RINOK(m_ArchiveHandler->ReOpen(NULL)); // check it
66 
67   m_ArchiveHandler->BindToRootFolder(&_folder);
68   FOR_VECTOR (i, pathVector)
69   {
70     CMyComPtr<IFolderFolder> newFolder;
71     _folder->BindToFolder(pathVector[i], &newFolder);
72     if (!newFolder)
73       break;
74     _folder = newFolder;
75   }
76   return S_OK;
77 }
78 */
79 
PutFiles(struct PluginPanelItem * panelItems,unsigned numItems,int moveMode,int opMode)80 NFileOperationReturnCode::EEnum CPlugin::PutFiles(
81   struct PluginPanelItem *panelItems, unsigned numItems,
82   int moveMode, int opMode)
83 {
84   if (moveMode != 0
85       && _agent->_isHashHandler)
86   {
87     g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported);
88     return NFileOperationReturnCode::kError;
89   }
90 
91   if (numItems <= 0)
92     return NFileOperationReturnCode::kError;
93 
94   if (_agent->IsThere_ReadOnlyArc())
95   {
96     g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
97     return NFileOperationReturnCode::kError;
98   }
99 
100   const int kYSize = 14;
101   const int kXMid = 38;
102 
103   NCompression::CInfo compressionInfo;
104   compressionInfo.Load();
105 
106   unsigned methodIndex = 0;
107 
108   unsigned i;
109   for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;)
110   {
111     i--;
112     if (compressionInfo.Level >= g_MethodMap[i])
113     {
114       methodIndex = i;
115       break;
116     }
117   }
118 
119   const int kMethodRadioIndex = 2;
120   const int kModeRadioIndex = kMethodRadioIndex + 7;
121 
122   struct CInitDialogItem initItems[]={
123     { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL },
124 
125     { DI_SINGLEBOX, 4, 2, kXMid - 2, 2 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL },
126 
127     { DI_RADIOBUTTON, 6, 3, 0, 0, methodIndex == 0, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL },
128     { DI_RADIOBUTTON, 6, 4, 0, 0, methodIndex == 1, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL },
129     { DI_RADIOBUTTON, 6, 5, 0, 0, methodIndex == 2, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL },
130     { DI_RADIOBUTTON, 6, 6, 0, 0, methodIndex == 3, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL },
131     { DI_RADIOBUTTON, 6, 7, 0, 0, methodIndex == 4, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL },
132     { DI_RADIOBUTTON, 6, 8, 0, 0, methodIndex == 5, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL },
133 
134     { DI_SINGLEBOX, kXMid, 2, 70, 2 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL },
135 
136     { DI_RADIOBUTTON, kXMid + 2, 3, 0, 0, false, true, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL },
137     { DI_RADIOBUTTON, kXMid + 2, 4, 0, 0, false, false,        0, false, NMessageID::kUpdateMode_Update, NULL, NULL },
138     { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, false,        0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL },
139     { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, false,        0, false, NMessageID::kUpdateMode_Sync, NULL, NULL },
140 
141     { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL  },
142 
143     { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL  },
144     { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL  }
145   };
146 
147   const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
148   const int kOkButtonIndex = kNumDialogItems - 2;
149   FarDialogItem dialogItems[kNumDialogItems];
150   g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
151   const int askCode = g_StartupInfo.ShowDialog(76, kYSize,
152       kHelpTopic, dialogItems, kNumDialogItems);
153   if (askCode != kOkButtonIndex)
154     return NFileOperationReturnCode::kInterruptedByUser;
155 
156   compressionInfo.Level = g_MethodMap[0];
157   for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++)
158     if (dialogItems[kMethodRadioIndex + i].Selected)
159       compressionInfo.Level = g_MethodMap[i];
160 
161   const CActionSet *actionSet;
162 
163        if (dialogItems[kModeRadioIndex    ].Selected) actionSet = &k_ActionSet_Add;
164   else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update;
165   else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh;
166   else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync;
167   else throw 51751;
168 
169   compressionInfo.Save();
170 
171   CWorkDirTempFile tempFile;
172   if (tempFile.CreateTempFile(m_FileName) != S_OK)
173     return NFileOperationReturnCode::kError;
174 
175 
176   /*
177   CSysStringVector fileNames;
178   for (int i = 0; i < numItems; i++)
179   {
180     const PluginPanelItem &panelItem = panelItems[i];
181     CSysString fullName;
182     if (!MyGetFullPathName(panelItem.FindData.cFileName, fullName))
183       return NFileOperationReturnCode::kError;
184     fileNames.Add(fullName);
185   }
186   */
187 
188   CScreenRestorer screenRestorer;
189   CProgressBox progressBox;
190   CProgressBox *progressBoxPointer = NULL;
191   if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
192   {
193     screenRestorer.Save();
194 
195     progressBoxPointer = &progressBox;
196     progressBox.Init(
197         // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
198         g_StartupInfo.GetMsgString(NMessageID::kUpdating));
199   }
200 
201   UStringVector pathVector;
202   GetPathParts(pathVector);
203 
204   UStringVector fileNames;
205   fileNames.ClearAndReserve(numItems);
206   for (i = 0; i < (unsigned)numItems; i++)
207     fileNames.AddInReserved(MultiByteToUnicodeString(panelItems[i].FindData.cFileName, CP_OEMCP));
208   CObjArray<const wchar_t *> fileNamePointers(numItems);
209   for (i = 0; i < (unsigned)numItems; i++)
210     fileNamePointers[i] = fileNames[i];
211 
212   CMyComPtr<IOutFolderArchive> outArchive;
213   HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive);
214   if (result != S_OK)
215   {
216     g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
217     return NFileOperationReturnCode::kError;
218   }
219 
220   /*
221   BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues];
222   for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
223     actionSetByte[i] = (BYTE)actionSet->StateActions[i];
224   */
225 
226   CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp;
227   CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec );
228 
229   updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer);
230   updateCallbackSpec->PasswordIsDefined = PasswordIsDefined;
231   updateCallbackSpec->Password = Password;
232 
233   if (!_agent->_isHashHandler)
234   {
235     if (SetOutProperties(outArchive, compressionInfo.Level) != S_OK)
236       return NFileOperationReturnCode::kError;
237   }
238 
239   /*
240   outArchive->SetFolder(_folder);
241   outArchive->SetFiles(L"", fileNamePointers, numItems);
242   // FStringVector requestedPaths;
243   // FStringVector processedPaths;
244   result = outArchive->DoOperation2(
245       // &requestedPaths, &processedPaths,
246       NULL, NULL,
247       tempFile.OutStream, actionSetByte, NULL, updateCallback);
248   updateCallback.Release();
249   outArchive.Release();
250 
251   if (result == S_OK)
252   {
253     result = AfterUpdate(tempFile, pathVector);
254   }
255   */
256 
257   {
258     result = _agent->SetFiles(L"", fileNamePointers, numItems);
259     if (result == S_OK)
260     {
261       CAgentFolder *agentFolder = NULL;
262       {
263         CMyComPtr<IArchiveFolderInternal> afi;
264         _folder.QueryInterface(IID_IArchiveFolderInternal, &afi);
265         if (afi)
266           afi->GetAgentFolder(&agentFolder);
267       }
268       if (agentFolder)
269         result = agentFolder->CommonUpdateOperation(AGENT_OP_Uni,
270             (moveMode != 0), NULL, actionSet, NULL, 0, updateCallback);
271       else
272         result = E_FAIL;
273     }
274   }
275 
276   if (result != S_OK)
277   {
278     ShowSysErrorMessage(result);
279     return NFileOperationReturnCode::kError;
280   }
281 
282   return NFileOperationReturnCode::kSuccess;
283 }
284 
285 namespace NPathType
286 {
287   enum EEnum
288   {
289     kLocal,
290     kUNC
291   };
292   EEnum GetPathType(const UString &path);
293 }
294 
295 struct CParsedPath
296 {
297   UString Prefix; // Disk or UNC with slash
298   UStringVector PathParts;
299   void ParsePath(const UString &path);
300   UString MergePath() const;
301 };
302 
303 static const char kDirDelimiter = CHAR_PATH_SEPARATOR;
304 static const wchar_t kDiskDelimiter = L':';
305 
306 namespace NPathType
307 {
GetPathType(const UString & path)308   EEnum GetPathType(const UString &path)
309   {
310     if (path.Len() <= 2)
311       return kLocal;
312     if (path[0] == kDirDelimiter && path[1] == kDirDelimiter)
313       return kUNC;
314     return kLocal;
315   }
316 }
317 
ParsePath(const UString & path)318 void CParsedPath::ParsePath(const UString &path)
319 {
320   int curPos = 0;
321   switch (NPathType::GetPathType(path))
322   {
323     case NPathType::kLocal:
324     {
325       const int posDiskDelimiter = path.Find(kDiskDelimiter);
326       if (posDiskDelimiter >= 0)
327       {
328         curPos = posDiskDelimiter + 1;
329         if ((int)path.Len() > curPos)
330           if (path[curPos] == kDirDelimiter)
331             curPos++;
332       }
333       break;
334     }
335     case NPathType::kUNC:
336     {
337       // the bug was fixed:
338       curPos = path.Find((wchar_t)kDirDelimiter, 2);
339       if (curPos < 0)
340         curPos = (int)path.Len();
341       else
342         curPos++;
343     }
344   }
345   Prefix = path.Left(curPos);
346   SplitPathToParts(path.Ptr(curPos), PathParts);
347 }
348 
MergePath() const349 UString CParsedPath::MergePath() const
350 {
351   UString result = Prefix;
352   FOR_VECTOR (i, PathParts)
353   {
354     if (i != 0)
355       // result += kDirDelimiter;
356       result.Add_PathSepar();
357     result += PathParts[i];
358   }
359   return result;
360 }
361 
362 
SetArcName(UString & arcName,const CArcInfoEx & arcInfo)363 static void SetArcName(UString &arcName, const CArcInfoEx &arcInfo)
364 {
365   if (!arcInfo.Flags_KeepName())
366   {
367     int dotPos = arcName.ReverseFind_Dot();
368     int slashPos = arcName.ReverseFind_PathSepar();
369     if (dotPos > slashPos + 1)
370       arcName.DeleteFrom(dotPos);
371   }
372   arcName.Add_Dot();
373   arcName += arcInfo.GetMainExt();
374 }
375 
CompressFiles(const CObjectVector<PluginPanelItem> & pluginPanelItems)376 HRESULT CompressFiles(const CObjectVector<PluginPanelItem> &pluginPanelItems)
377 {
378   if (pluginPanelItems.Size() == 0)
379     return E_FAIL;
380 
381   UStringVector fileNames;
382   {
383     FOR_VECTOR (i, pluginPanelItems)
384     {
385       const PluginPanelItem &panelItem = pluginPanelItems[i];
386       if (strcmp(panelItem.FindData.cFileName, "..") == 0 &&
387           NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes))
388         return E_FAIL;
389       if (strcmp(panelItem.FindData.cFileName, ".") == 0 &&
390           NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes))
391         return E_FAIL;
392       FString fullPath;
393       FString fileNameUnicode = us2fs(MultiByteToUnicodeString(panelItem.FindData.cFileName, CP_OEMCP));
394       if (!MyGetFullPathName(fileNameUnicode, fullPath))
395         return E_FAIL;
396       fileNames.Add(fs2us(fullPath));
397     }
398   }
399 
400   NCompression::CInfo compressionInfo;
401   compressionInfo.Load();
402 
403   int archiverIndex = -1;
404 
405   /*
406   CCodecs *codecs = new CCodecs;
407   CMyComPtr<ICompressCodecsInfo> compressCodecsInfo = codecs;
408   if (codecs->Load() != S_OK)
409     throw "Can't load 7-Zip codecs";
410   */
411 
412   if (LoadGlobalCodecs() != S_OK)
413     throw "Can't load 7-Zip codecs";
414 
415   CCodecs *codecs = g_CodecsObj;
416 
417   {
418     FOR_VECTOR (i, codecs->Formats)
419     {
420       const CArcInfoEx &arcInfo = codecs->Formats[i];
421       if (arcInfo.UpdateEnabled)
422       {
423         if (archiverIndex == -1)
424           archiverIndex = (int)i;
425         if (MyStringCompareNoCase(arcInfo.Name, compressionInfo.ArcType) == 0)
426           archiverIndex = (int)i;
427       }
428     }
429   }
430 
431   if (archiverIndex < 0)
432     throw "there is no output handler";
433 
434   UString resultPath;
435   {
436     CParsedPath parsedPath;
437     parsedPath.ParsePath(fileNames.Front());
438     if (parsedPath.PathParts.Size() == 0)
439       return E_FAIL;
440     if (fileNames.Size() == 1 || parsedPath.PathParts.Size() == 1)
441     {
442       // CSysString pureName, dot, extension;
443       resultPath = parsedPath.PathParts.Back();
444     }
445     else
446     {
447       parsedPath.PathParts.DeleteBack();
448       resultPath = parsedPath.PathParts.Back();
449     }
450   }
451   UString archiveNameSrc = resultPath;
452   UString arcName = archiveNameSrc;
453 
454   int prevFormat = archiverIndex;
455   SetArcName(arcName, codecs->Formats[archiverIndex]);
456 
457   const CActionSet *actionSet = &k_ActionSet_Add;
458 
459   for (;;)
460   {
461     AString archiveNameA (UnicodeStringToMultiByte(arcName, CP_OEMCP));
462     const int kYSize = 16;
463     const int kXMid = 38;
464 
465     const int kArchiveNameIndex = 2;
466     const int kMethodRadioIndex = kArchiveNameIndex + 2;
467     const int kModeRadioIndex = kMethodRadioIndex + 7;
468 
469     // char updateAddToArchiveString[512];
470     AString str1;
471     {
472       const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex];
473       const AString s (UnicodeStringToMultiByte(arcInfo.Name, CP_OEMCP));
474       str1 = g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive);
475       str1.Replace(AString ("%s"), s);
476       /*
477       sprintf(updateAddToArchiveString,
478         g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive), (const char *)s);
479       */
480     }
481 
482     unsigned methodIndex = 0;
483     unsigned i;
484     for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;)
485     {
486       i--;
487       if (compressionInfo.Level >= g_MethodMap[i])
488       {
489         methodIndex = i;
490         break;
491       }
492     }
493 
494     const struct CInitDialogItem initItems[]=
495     {
496       { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL },
497 
498       { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, str1, NULL },
499 
500       { DI_EDIT, 5, 3, 70, 3, true, false, DIF_HISTORY, false, -1, archiveNameA, kArchiveHistoryKeyName},
501       // { DI_EDIT, 5, 3, 70, 3, true, false, 0, false, -1, arcName, NULL},
502 
503       { DI_SINGLEBOX, 4, 4, kXMid - 2, 4 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL },
504 
505       { DI_RADIOBUTTON, 6, 5, 0, 0, false, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL },
506       { DI_RADIOBUTTON, 6, 6, 0, 0, false, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL },
507       { DI_RADIOBUTTON, 6, 7, 0, 0, false, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL },
508       { DI_RADIOBUTTON, 6, 8, 0, 0, false, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL },
509       { DI_RADIOBUTTON, 6, 9, 0, 0, false, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL },
510       { DI_RADIOBUTTON, 6,10, 0, 0, false, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL },
511 
512       { DI_SINGLEBOX, kXMid, 4, 70, 4 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL },
513 
514       { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, actionSet == &k_ActionSet_Add, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL },
515       { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, actionSet == &k_ActionSet_Update,      0, false, NMessageID::kUpdateMode_Update, NULL, NULL },
516       { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false, actionSet == &k_ActionSet_Fresh,       0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL },
517       { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false, actionSet == &k_ActionSet_Sync,        0, false, NMessageID::kUpdateMode_Sync, NULL, NULL },
518 
519       { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL  },
520 
521       { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL  },
522       { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kUpdateSelectArchiver, NULL, NULL  },
523       { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL  }
524     };
525 
526     const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
527 
528     const int kOkButtonIndex = kNumDialogItems - 3;
529     const int kSelectarchiverButtonIndex = kNumDialogItems - 2;
530 
531     FarDialogItem dialogItems[kNumDialogItems];
532     g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
533     int askCode = g_StartupInfo.ShowDialog(76, kYSize,
534         kHelpTopic, dialogItems, kNumDialogItems);
535 
536     archiveNameA = dialogItems[kArchiveNameIndex].Data;
537     archiveNameA.Trim();
538     MultiByteToUnicodeString2(arcName, archiveNameA, CP_OEMCP);
539 
540     compressionInfo.Level = g_MethodMap[0];
541     for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++)
542       if (dialogItems[kMethodRadioIndex + i].Selected)
543         compressionInfo.Level = g_MethodMap[i];
544 
545          if (dialogItems[kModeRadioIndex    ].Selected) actionSet = &k_ActionSet_Add;
546     else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update;
547     else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh;
548     else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync;
549     else throw 51751;
550 
551     if (askCode == kSelectarchiverButtonIndex)
552     {
553       CUIntVector indices;
554       AStringVector archiverNames;
555       FOR_VECTOR (k, codecs->Formats)
556       {
557         const CArcInfoEx &arc = codecs->Formats[k];
558         if (arc.UpdateEnabled)
559         {
560           indices.Add(k);
561           archiverNames.Add(GetOemString(arc.Name));
562         }
563       }
564 
565       const int index = g_StartupInfo.Menu(FMENU_AUTOHIGHLIGHT,
566           g_StartupInfo.GetMsgString(NMessageID::kUpdateSelectArchiverMenuTitle),
567           NULL, archiverNames, archiverIndex);
568       if (index >= 0)
569       {
570         const CArcInfoEx &prevArchiverInfo = codecs->Formats[prevFormat];
571         if (prevArchiverInfo.Flags_KeepName())
572         {
573           const UString &prevExtension = prevArchiverInfo.GetMainExt();
574           const unsigned prevExtensionLen = prevExtension.Len();
575           if (arcName.Len() >= prevExtensionLen &&
576               MyStringCompareNoCase(arcName.RightPtr(prevExtensionLen), prevExtension) == 0)
577           {
578             const unsigned pos = arcName.Len() - prevExtensionLen;
579             if (pos > 2)
580             {
581               if (arcName[pos - 1] == '.')
582                 arcName.DeleteFrom(pos - 1);
583             }
584           }
585         }
586 
587         archiverIndex = (int)indices[index];
588         const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex];
589         prevFormat = archiverIndex;
590 
591         if (arcInfo.Flags_KeepName())
592           arcName = archiveNameSrc;
593         SetArcName(arcName, arcInfo);
594       }
595       continue;
596     }
597 
598     if (askCode != kOkButtonIndex)
599       return E_ABORT;
600 
601     break;
602   }
603 
604   const CArcInfoEx &archiverInfoFinal = codecs->Formats[archiverIndex];
605   compressionInfo.ArcType = archiverInfoFinal.Name;
606   compressionInfo.Save();
607 
608   NWorkDir::CInfo workDirInfo;
609   workDirInfo.Load();
610 
611   FString fullArcName;
612   if (!MyGetFullPathName(us2fs(arcName), fullArcName))
613     return E_FAIL;
614 
615   CWorkDirTempFile tempFile;
616   RINOK(tempFile.CreateTempFile(fullArcName))
617   CScreenRestorer screenRestorer;
618   CProgressBox progressBox;
619   CProgressBox *progressBoxPointer = NULL;
620 
621   screenRestorer.Save();
622 
623   progressBoxPointer = &progressBox;
624   progressBox.Init(
625       // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
626       g_StartupInfo.GetMsgString(NMessageID::kUpdating));
627 
628 
629   NFind::CFileInfo fileInfo;
630 
631   CMyComPtr<IOutFolderArchive> outArchive;
632 
633   CMyComPtr<IInFolderArchive> archiveHandler;
634   if (fileInfo.Find(fullArcName))
635   {
636     if (fileInfo.IsDir())
637       throw "There is Directory with such name";
638 
639     CAgent *agentSpec = new CAgent;
640     archiveHandler = agentSpec;
641     // CLSID realClassID;
642     CMyComBSTR archiveType;
643     RINOK(archiveHandler->Open(NULL,
644         GetUnicodeString(fullArcName, CP_OEMCP), UString(),
645         // &realClassID,
646         &archiveType,
647         NULL))
648 
649     if (MyStringCompareNoCase(archiverInfoFinal.Name, (const wchar_t *)archiveType) != 0)
650       throw "Type of existing archive differs from specified type";
651     const HRESULT result = archiveHandler.QueryInterface(
652         IID_IOutFolderArchive, &outArchive);
653     if (result != S_OK)
654     {
655       g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
656       return E_FAIL;
657     }
658   }
659   else
660   {
661     // HRESULT result = outArchive.CoCreateInstance(classID);
662     CAgent *agentSpec = new CAgent;
663     outArchive = agentSpec;
664 
665     /*
666     HRESULT result = outArchive.CoCreateInstance(CLSID_CAgentArchiveHandler);
667     if (result != S_OK)
668     {
669       g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
670       return E_FAIL;
671     }
672     */
673   }
674 
675   CObjArray<const wchar_t *> fileNamePointers(fileNames.Size());
676 
677   unsigned i;
678   for (i = 0; i < fileNames.Size(); i++)
679     fileNamePointers[i] = fileNames[i];
680 
681   outArchive->SetFolder(NULL);
682   outArchive->SetFiles(L"", fileNamePointers, fileNames.Size());
683   BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues];
684   for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
685     actionSetByte[i] = (BYTE)actionSet->StateActions[i];
686 
687   CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp;
688   CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec );
689 
690   updateCallbackSpec->Init(/* archiveHandler, */ progressBoxPointer);
691 
692 
693   RINOK(SetOutProperties(outArchive, compressionInfo.Level))
694 
695   // FStringVector requestedPaths;
696   // FStringVector processedPaths;
697   HRESULT result = outArchive->DoOperation(
698       // &requestedPaths, &processedPaths,
699       NULL, NULL,
700       codecs, archiverIndex,
701       tempFile.OutStream, actionSetByte,
702       NULL, updateCallback);
703   updateCallback.Release();
704   outArchive.Release();
705 
706   if (result != S_OK)
707   {
708     ShowSysErrorMessage(result);
709     return result;
710   }
711 
712   if (archiveHandler)
713   {
714     archiveHandler->Close();
715   }
716 
717   result = tempFile.MoveToOriginal(archiveHandler != NULL);
718   if (result != S_OK)
719   {
720     ShowSysErrorMessage(result);
721     return result;
722   }
723   return S_OK;
724 }
725 
726 
727 static const char * const k_CreateFolder_History = "NewFolder"; // we use default FAR folder name
728 
CreateFolder()729 HRESULT CPlugin::CreateFolder()
730 {
731   if (_agent->IsThere_ReadOnlyArc())
732   {
733     g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
734     return TRUE;
735   }
736 
737   UString destPathU;
738   {
739     const int kXSize = 60;
740     const int kYSize = 8;
741     const int kPathIndex = 2;
742 
743     AString destPath ("New Folder");
744 
745     const struct CInitDialogItem initItems[]={
746       { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false,
747           -1, "Create Folder", NULL },
748 
749       { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, "Folder name:", NULL },
750 
751       { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, k_CreateFolder_History },
752 
753       { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kOk, NULL, NULL },
754       { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL }
755     };
756 
757     const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
758     const int kOkButtonIndex = kNumDialogItems - 2;
759 
760     FarDialogItem dialogItems[kNumDialogItems];
761     g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
762     for (;;)
763     {
764       int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize,
765           NULL, // kHelpTopic
766           dialogItems, kNumDialogItems);
767       if (askCode != kOkButtonIndex)
768         return E_ABORT;
769       destPath = dialogItems[kPathIndex].Data;
770       destPathU = GetUnicodeString(destPath, CP_OEMCP);
771       destPathU.Trim();
772       if (!destPathU.IsEmpty())
773         break;
774       g_StartupInfo.ShowErrorMessage("You must specify folder name");
775     }
776 
777   }
778 
779   CScreenRestorer screenRestorer;
780   CProgressBox progressBox;
781   CProgressBox *progressBoxPointer = NULL;
782   // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
783   {
784     screenRestorer.Save();
785 
786     progressBoxPointer = &progressBox;
787     progressBox.Init(
788         // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
789         g_StartupInfo.GetMsgString(NMessageID::kDeleting));
790   }
791 
792   CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp;
793   CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec);
794 
795   updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer);
796   updateCallbackSpec->PasswordIsDefined = PasswordIsDefined;
797   updateCallbackSpec->Password = Password;
798 
799   HRESULT result;
800   {
801     CMyComPtr<IFolderOperations> folderOperations;
802     result = _folder.QueryInterface(IID_IFolderOperations, &folderOperations);
803     if (folderOperations)
804       result = folderOperations->CreateFolder(destPathU, updateCallback);
805     else if (result != S_OK)
806       result = E_FAIL;
807   }
808 
809   if (result != S_OK)
810   {
811     ShowSysErrorMessage(result);
812     return result;
813   }
814 
815   g_StartupInfo.Control(this, FCTL_UPDATEPANEL, (void *)1);
816   g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL);
817 
818   PanelInfo panelInfo;
819 
820   if (g_StartupInfo.ControlGetActivePanelInfo(panelInfo))
821   {
822     const AString destPath (GetOemString(destPathU));
823 
824     for (int i = 0; i < panelInfo.ItemsNumber; i++)
825     {
826       const PluginPanelItem &pi = panelInfo.PanelItems[i];
827       if (strcmp(destPath, pi.FindData.cFileName) == 0)
828       {
829         PanelRedrawInfo panelRedrawInfo;
830         panelRedrawInfo.CurrentItem = i;
831         panelRedrawInfo.TopPanelItem = 0;
832         g_StartupInfo.Control(this, FCTL_REDRAWPANEL, &panelRedrawInfo);
833         break;
834       }
835     }
836   }
837 
838   SetCurrentDirVar();
839   return S_OK;
840 }
841