xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Far/Plugin.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Plugin.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/IntToString.h"
6 #include "../../../Common/StringConvert.h"
7 #include "../../../Common/Wildcard.h"
8 
9 #include "../../../Windows/FileDir.h"
10 #include "../../../Windows/PropVariantConv.h"
11 
12 #include "../Common/PropIDUtils.h"
13 
14 #include "FarUtils.h"
15 #include "Messages.h"
16 #include "Plugin.h"
17 
18 using namespace NWindows;
19 using namespace NFile;
20 using namespace NDir;
21 using namespace NFar;
22 
23 // This function is used by CAgentFolder
24 int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2);
CompareFileNames_ForFolderList(const wchar_t * s1,const wchar_t * s2)25 int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2)
26 {
27   return MyStringCompareNoCase(s1, s2);
28 }
29 
CPlugin(const FString & fileName,CAgent * agent,UString archiveTypeName)30 CPlugin::CPlugin(const FString &fileName, CAgent *agent, UString archiveTypeName):
31     _agent(agent),
32     m_FileName(fileName),
33     _archiveTypeName(archiveTypeName),
34     PasswordIsDefined(false)
35 {
36   m_ArchiveHandler = agent;
37   if (!m_FileInfo.Find(m_FileName))
38     throw "error";
39   m_ArchiveHandler->BindToRootFolder(&_folder);
40 }
41 
~CPlugin()42 CPlugin::~CPlugin() {}
43 
MyGetFileTime(IFolderFolder * folder,UInt32 itemIndex,PROPID propID,FILETIME & fileTime)44 static void MyGetFileTime(IFolderFolder *folder, UInt32 itemIndex,
45     PROPID propID, FILETIME &fileTime)
46 {
47   NCOM::CPropVariant prop;
48   if (folder->GetProperty(itemIndex, propID, &prop) != S_OK)
49     throw 271932;
50   if (prop.vt == VT_EMPTY)
51   {
52     fileTime.dwHighDateTime = 0;
53     fileTime.dwLowDateTime = 0;
54   }
55   else
56   {
57     if (prop.vt != VT_FILETIME)
58       throw 4191730;
59     fileTime = prop.filetime;
60   }
61 }
62 
63 #define kDotsReplaceString "[[..]]"
64 #define kDotsReplaceStringU L"[[..]]"
65 
CopyStrLimited(char * dest,const AString & src,unsigned len)66 static void CopyStrLimited(char *dest, const AString &src, unsigned len)
67 {
68   len--;
69   if (src.Len() < len)
70     len = src.Len();
71   memcpy(dest, src, sizeof(dest[0]) * len);
72   dest[len] = 0;
73 }
74 
75 #define COPY_STR_LIMITED(dest, src) CopyStrLimited(dest, src, Z7_ARRAY_SIZE(dest))
76 
ReadPluginPanelItem(PluginPanelItem & panelItem,UInt32 itemIndex)77 void CPlugin::ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex)
78 {
79   NCOM::CPropVariant prop;
80   if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK)
81     throw 271932;
82 
83   if (prop.vt != VT_BSTR)
84     throw 272340;
85 
86   AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP));
87   if (oemString == "..")
88     oemString = kDotsReplaceString;
89 
90   COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString);
91   panelItem.FindData.cAlternateFileName[0] = 0;
92 
93   if (_folder->GetProperty(itemIndex, kpidAttrib, &prop) != S_OK)
94     throw 271932;
95   if (prop.vt == VT_UI4)
96     panelItem.FindData.dwFileAttributes  = prop.ulVal;
97   else if (prop.vt == VT_EMPTY)
98     panelItem.FindData.dwFileAttributes = m_FileInfo.Attrib;
99   else
100     throw 21631;
101 
102   if (_folder->GetProperty(itemIndex, kpidIsDir, &prop) != S_OK)
103     throw 271932;
104   if (prop.vt == VT_BOOL)
105   {
106     if (VARIANT_BOOLToBool(prop.boolVal))
107       panelItem.FindData.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
108   }
109   else if (prop.vt != VT_EMPTY)
110     throw 21632;
111 
112   if (_folder->GetProperty(itemIndex, kpidSize, &prop) != S_OK)
113     throw 271932;
114   UInt64 length = 0;
115   ConvertPropVariantToUInt64(prop, length);
116   panelItem.FindData.nFileSizeLow = (UInt32)length;
117   panelItem.FindData.nFileSizeHigh = (UInt32)(length >> 32);
118 
119   MyGetFileTime(_folder, itemIndex, kpidCTime, panelItem.FindData.ftCreationTime);
120   MyGetFileTime(_folder, itemIndex, kpidATime, panelItem.FindData.ftLastAccessTime);
121   MyGetFileTime(_folder, itemIndex, kpidMTime, panelItem.FindData.ftLastWriteTime);
122 
123   if (panelItem.FindData.ftLastWriteTime.dwHighDateTime == 0 &&
124       panelItem.FindData.ftLastWriteTime.dwLowDateTime == 0)
125     panelItem.FindData.ftLastWriteTime = m_FileInfo.MTime;
126 
127   if (_folder->GetProperty(itemIndex, kpidPackSize, &prop) != S_OK)
128     throw 271932;
129   length = 0;
130   ConvertPropVariantToUInt64(prop, length);
131   panelItem.PackSize = UInt32(length);
132   panelItem.PackSizeHigh = UInt32(length >> 32);
133 
134   panelItem.Flags = 0;
135   panelItem.NumberOfLinks = 0;
136 
137   panelItem.Description = NULL;
138   panelItem.Owner = NULL;
139   panelItem.CustomColumnData = NULL;
140   panelItem.CustomColumnNumber = 0;
141 
142   panelItem.CRC32 = 0;
143   panelItem.Reserved[0] = 0;
144   panelItem.Reserved[1] = 0;
145 }
146 
GetFindData(PluginPanelItem ** panelItems,int * itemsNumber,int opMode)147 int CPlugin::GetFindData(PluginPanelItem **panelItems, int *itemsNumber, int opMode)
148 {
149   // CScreenRestorer screenRestorer;
150   if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
151   {
152     /*
153     screenRestorer.Save();
154     const char *msgItems[]=
155     {
156       g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
157         g_StartupInfo.GetMsgString(NMessageID::kReadingList)
158     };
159     g_StartupInfo.ShowMessage(0, NULL, msgItems, Z7_ARRAY_SIZE(msgItems), 0);
160     */
161   }
162 
163   UInt32 numItems;
164   _folder->GetNumberOfItems(&numItems);
165   *panelItems = new PluginPanelItem[numItems];
166   try
167   {
168     for (UInt32 i = 0; i < numItems; i++)
169     {
170       PluginPanelItem &panelItem = (*panelItems)[i];
171       ReadPluginPanelItem(panelItem, i);
172       panelItem.UserData = i;
173     }
174   }
175   catch(...)
176   {
177     delete [](*panelItems);
178     throw;
179   }
180   *itemsNumber = (int)numItems;
181   return(TRUE);
182 }
183 
FreeFindData(struct PluginPanelItem * panelItems,int itemsNumber)184 void CPlugin::FreeFindData(struct PluginPanelItem *panelItems, int itemsNumber)
185 {
186   for (int i = 0; i < itemsNumber; i++)
187     if (panelItems[i].Description != NULL)
188       delete []panelItems[i].Description;
189   delete []panelItems;
190 }
191 
EnterToDirectory(const UString & dirName)192 void CPlugin::EnterToDirectory(const UString &dirName)
193 {
194   CMyComPtr<IFolderFolder> newFolder;
195   UString s = dirName;
196   if (dirName == kDotsReplaceStringU)
197     s = "..";
198   _folder->BindToFolder(s, &newFolder);
199   if (!newFolder)
200   {
201     if (dirName.IsEmpty())
202       return;
203     else
204       throw 40325;
205   }
206   _folder = newFolder;
207 }
208 
SetDirectory(const char * aszDir,int)209 int CPlugin::SetDirectory(const char *aszDir, int /* opMode */)
210 {
211   UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP);
212   if (path == WSTRING_PATH_SEPARATOR)
213   {
214     _folder.Release();
215     m_ArchiveHandler->BindToRootFolder(&_folder);
216   }
217   else if (path == L"..")
218   {
219     CMyComPtr<IFolderFolder> newFolder;
220     _folder->BindToParentFolder(&newFolder);
221     if (!newFolder)
222       throw 40312;
223     _folder = newFolder;
224   }
225   else if (path.IsEmpty())
226     EnterToDirectory(path);
227   else
228   {
229     if (path[0] == WCHAR_PATH_SEPARATOR)
230     {
231       _folder.Release();
232       m_ArchiveHandler->BindToRootFolder(&_folder);
233       path.DeleteFrontal(1);
234     }
235     UStringVector pathParts;
236     SplitPathToParts(path, pathParts);
237     FOR_VECTOR (i, pathParts)
238       EnterToDirectory(pathParts[i]);
239   }
240   SetCurrentDirVar();
241   return TRUE;
242 }
243 
GetPathParts(UStringVector & pathParts)244 void CPlugin::GetPathParts(UStringVector &pathParts)
245 {
246   pathParts.Clear();
247   CMyComPtr<IFolderFolder> folderItem = _folder;
248   for (;;)
249   {
250     CMyComPtr<IFolderFolder> newFolder;
251     folderItem->BindToParentFolder(&newFolder);
252     if (!newFolder)
253       break;
254     NCOM::CPropVariant prop;
255     if (folderItem->GetFolderProperty(kpidName, &prop) == S_OK)
256       if (prop.vt == VT_BSTR)
257         pathParts.Insert(0, (const wchar_t *)prop.bstrVal);
258     folderItem = newFolder;
259   }
260 }
261 
SetCurrentDirVar()262 void CPlugin::SetCurrentDirVar()
263 {
264   m_CurrentDir.Empty();
265 
266   /*
267   // kpidPath path has tail slash, but we don't need it for compatibility with default FAR style
268   NCOM::CPropVariant prop;
269   if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK)
270     if (prop.vt == VT_BSTR)
271     {
272       m_CurrentDir = (wchar_t *)prop.bstrVal;
273       // if (!m_CurrentDir.IsEmpty())
274     }
275   m_CurrentDir.InsertAtFront(WCHAR_PATH_SEPARATOR);
276   */
277 
278   UStringVector pathParts;
279   GetPathParts(pathParts);
280   FOR_VECTOR (i, pathParts)
281   {
282     m_CurrentDir.Add_PathSepar();
283     m_CurrentDir += pathParts[i];
284   }
285 }
286 
287 static const char * const kPluginFormatName = "7-ZIP";
288 
289 
FindPropNameID(PROPID propID)290 static int FindPropNameID(PROPID propID)
291 {
292   if (propID > NMessageID::k_Last_PropId_supported_by_plugin)
293     return -1;
294   return NMessageID::kNoProperty + (int)propID;
295 }
296 
297 /*
298 struct CPropertyIDInfo
299 {
300   PROPID PropID;
301   const char *FarID;
302   int Width;
303   // char CharID;
304 };
305 
306 static CPropertyIDInfo kPropertyIDInfos[] =
307 {
308   { kpidName, "N", 0},
309   { kpidSize, "S", 8},
310   { kpidPackSize, "P", 8},
311   { kpidAttrib, "A", 0},
312   { kpidCTime, "DC", 14},
313   { kpidATime, "DA", 14},
314   { kpidMTime, "DM", 14},
315 
316   { kpidSolid, NULL, 0, 'S'},
317   { kpidEncrypted, NULL, 0, 'P'},
318 
319   { kpidDictionarySize, IDS_PROPERTY_DICTIONARY_SIZE },
320   { kpidSplitBefore, NULL, 'B'},
321   { kpidSplitAfter, NULL, 'A'},
322   { kpidComment, NULL, 'C'},
323   { kpidCRC, IDS_PROPERTY_CRC }
324   // { kpidType, L"Type" }
325 };
326 
327 static const int kNumPropertyIDInfos = Z7_ARRAY_SIZE(kPropertyIDInfos);
328 
329 static int FindPropertyInfo(PROPID propID)
330 {
331   for (int i = 0; i < kNumPropertyIDInfos; i++)
332     if (kPropertyIDInfos[i].PropID == propID)
333       return i;
334   return -1;
335 }
336 */
337 
338 // char *g_Titles[] = { "a", "f", "v" };
339 /*
340 static void SmartAddToString(AString &destString, const char *srcString)
341 {
342   if (!destString.IsEmpty())
343     destString += ',';
344   destString += srcString;
345 }
346 */
347 
348 /*
349 void CPlugin::AddColumn(PROPID propID)
350 {
351   int index = FindPropertyInfo(propID);
352   if (index >= 0)
353   {
354     for (int i = 0; i < m_ProxyHandler->m_InternalProperties.Size(); i++)
355     {
356       const CArchiveItemProperty &aHandlerProperty = m_ProxyHandler->m_InternalProperties[i];
357       if (aHandlerProperty.ID == propID)
358         break;
359     }
360     if (i == m_ProxyHandler->m_InternalProperties.Size())
361       return;
362 
363     const CPropertyIDInfo &propertyIDInfo = kPropertyIDInfos[index];
364     SmartAddToString(PanelModeColumnTypes, propertyIDInfo.FarID);
365     char tmp[32];
366     itoa(propertyIDInfo.Width, tmp, 10);
367     SmartAddToString(PanelModeColumnWidths, tmp);
368     return;
369   }
370 }
371 */
372 
GetNameOfProp(PROPID propID,const wchar_t * name)373 static AString GetNameOfProp(PROPID propID, const wchar_t *name)
374 {
375   int farID = FindPropNameID(propID);
376   if (farID >= 0)
377     return (AString)g_StartupInfo.GetMsgString(farID);
378   if (name)
379     return UnicodeStringToMultiByte(name, CP_OEMCP);
380   char s[16];
381   ConvertUInt32ToString(propID, s);
382   return (AString)s;
383 }
384 
GetNameOfProp2(PROPID propID,const wchar_t * name)385 static AString GetNameOfProp2(PROPID propID, const wchar_t *name)
386 {
387   AString s (GetNameOfProp(propID, name));
388   if (s.Len() > (kInfoPanelLineSize - 1))
389     s.DeleteFrom(kInfoPanelLineSize - 1);
390   return s;
391 }
392 
ConvertSizeToString(UInt64 value)393 static AString ConvertSizeToString(UInt64 value)
394 {
395   char s[32];
396   ConvertUInt64ToString(value, s);
397   unsigned i = MyStringLen(s);
398   unsigned pos = Z7_ARRAY_SIZE(s);
399   s[--pos] = 0;
400   while (i > 3)
401   {
402     s[--pos] = s[--i];
403     s[--pos] = s[--i];
404     s[--pos] = s[--i];
405     s[--pos] = ' ';
406   }
407   while (i > 0)
408     s[--pos] = s[--i];
409   return (AString)(s + pos);
410 }
411 
PropToString(const NCOM::CPropVariant & prop,PROPID propID)412 static AString PropToString(const NCOM::CPropVariant &prop, PROPID propID)
413 {
414   if (prop.vt == VT_BSTR)
415   {
416     AString s (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP));
417     s.Replace((char)0xA, ' ');
418     s.Replace((char)0xD, ' ');
419     return s;
420   }
421   if (prop.vt == VT_BOOL)
422   {
423     int messageID = VARIANT_BOOLToBool(prop.boolVal) ?
424       NMessageID::kYes : NMessageID::kNo;
425     return (AString)g_StartupInfo.GetMsgString(messageID);
426   }
427   if (prop.vt != VT_EMPTY)
428   {
429     if ((prop.vt == VT_UI8 || prop.vt == VT_UI4) && (
430         propID == kpidSize ||
431         propID == kpidPackSize ||
432         propID == kpidNumSubDirs ||
433         propID == kpidNumSubFiles ||
434         propID == kpidNumBlocks ||
435         propID == kpidPhySize ||
436         propID == kpidHeadersSize ||
437         propID == kpidClusterSize ||
438         propID == kpidUnpackSize
439         ))
440     {
441       UInt64 v = 0;
442       ConvertPropVariantToUInt64(prop, v);
443       return ConvertSizeToString(v);
444     }
445     {
446       char sz[64];
447       ConvertPropertyToShortString2(sz, prop, propID);
448       return (AString)sz;
449     }
450   }
451   return AString();
452 }
453 
PropToString2(const NCOM::CPropVariant & prop,PROPID propID)454 static AString PropToString2(const NCOM::CPropVariant &prop, PROPID propID)
455 {
456   AString s (PropToString(prop, propID));
457   if (s.Len() > (kInfoPanelLineSize - 1))
458     s.DeleteFrom(kInfoPanelLineSize - 1);
459   return s;
460 }
461 
AddPropertyString(InfoPanelLine * lines,unsigned & numItems,PROPID propID,const wchar_t * name,const NCOM::CPropVariant & prop)462 static void AddPropertyString(InfoPanelLine *lines, unsigned &numItems, PROPID propID, const wchar_t *name,
463     const NCOM::CPropVariant &prop)
464 {
465   if (prop.vt != VT_EMPTY)
466   {
467     AString val (PropToString2(prop, propID));
468     if (!val.IsEmpty())
469     {
470       InfoPanelLine &item = lines[numItems++];
471       COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name));
472       COPY_STR_LIMITED(item.Data, val);
473     }
474   }
475 }
476 
InsertSeparator(InfoPanelLine * lines,unsigned & numItems)477 static void InsertSeparator(InfoPanelLine *lines, unsigned &numItems)
478 {
479   if (numItems < kNumInfoLinesMax)
480   {
481     InfoPanelLine &item = lines[numItems++];
482     *item.Text = 0;
483     *item.Data = 0;
484     item.Separator = TRUE;
485   }
486 }
487 
GetOpenPluginInfo(struct OpenPluginInfo * info)488 void CPlugin::GetOpenPluginInfo(struct OpenPluginInfo *info)
489 {
490   info->StructSize = sizeof(*info);
491   info->Flags = OPIF_USEFILTER | OPIF_USESORTGROUPS | OPIF_USEHIGHLIGHTING |
492               OPIF_ADDDOTS | OPIF_COMPAREFATTIME;
493 
494   COPY_STR_LIMITED(m_FileNameBuffer, UnicodeStringToMultiByte(fs2us(m_FileName), CP_OEMCP));
495   info->HostFile = m_FileNameBuffer; // test it it is not static
496 
497   COPY_STR_LIMITED(m_CurrentDirBuffer, UnicodeStringToMultiByte(m_CurrentDir, CP_OEMCP));
498   info->CurDir = m_CurrentDirBuffer;
499 
500   info->Format = kPluginFormatName;
501 
502   {
503   UString name;
504   {
505     FString dirPrefix, fileName;
506     GetFullPathAndSplit(m_FileName, dirPrefix, fileName);
507     name = fs2us(fileName);
508   }
509 
510   m_PannelTitle = ' ';
511   m_PannelTitle += _archiveTypeName;
512   m_PannelTitle.Add_Colon();
513   m_PannelTitle += name;
514   m_PannelTitle.Add_Space();
515   if (!m_CurrentDir.IsEmpty())
516   {
517     // m_PannelTitle += '\\';
518     m_PannelTitle += m_CurrentDir;
519   }
520 
521   COPY_STR_LIMITED(m_PannelTitleBuffer, UnicodeStringToMultiByte(m_PannelTitle, CP_OEMCP));
522   info->PanelTitle = m_PannelTitleBuffer;
523 
524   }
525 
526   memset(m_InfoLines, 0, sizeof(m_InfoLines));
527   m_InfoLines[0].Text[0] = 0;
528   m_InfoLines[0].Separator = TRUE;
529 
530   MyStringCopy(m_InfoLines[1].Text, g_StartupInfo.GetMsgString(NMessageID::kArchiveType));
531   MyStringCopy(m_InfoLines[1].Data, (const char *)UnicodeStringToMultiByte(_archiveTypeName, CP_OEMCP));
532 
533   unsigned numItems = 2;
534 
535   {
536     CMyComPtr<IFolderProperties> folderProperties;
537     _folder.QueryInterface(IID_IFolderProperties, &folderProperties);
538     if (folderProperties)
539     {
540       UInt32 numProps;
541       if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK)
542       {
543         for (UInt32 i = 0; i < numProps && numItems < kNumInfoLinesMax; i++)
544         {
545           CMyComBSTR name;
546           PROPID propID;
547           VARTYPE vt;
548           if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK)
549             continue;
550           NCOM::CPropVariant prop;
551           if (_folder->GetFolderProperty(propID, &prop) != S_OK || prop.vt == VT_EMPTY)
552             continue;
553 
554           InfoPanelLine &item = m_InfoLines[numItems++];
555           COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name));
556           COPY_STR_LIMITED(item.Data, PropToString2(prop, propID));
557         }
558       }
559     }
560   }
561 
562   /*
563   if (numItems < kNumInfoLinesMax)
564   {
565     InsertSeparator(m_InfoLines, numItems);
566   }
567   */
568 
569   {
570     CMyComPtr<IGetFolderArcProps> getFolderArcProps;
571     _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
572     if (getFolderArcProps)
573     {
574       CMyComPtr<IFolderArcProps> getProps;
575       getFolderArcProps->GetFolderArcProps(&getProps);
576       if (getProps)
577       {
578         UInt32 numLevels;
579         if (getProps->GetArcNumLevels(&numLevels) != S_OK)
580           numLevels = 0;
581         for (UInt32 level2 = 0; level2 < numLevels; level2++)
582         {
583           {
584             UInt32 level = numLevels - 1 - level2;
585             UInt32 numProps;
586             if (getProps->GetArcNumProps(level, &numProps) == S_OK)
587             {
588               InsertSeparator(m_InfoLines, numItems);
589               for (Int32 i = -3; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++)
590               {
591                 CMyComBSTR name;
592                 PROPID propID;
593                 VARTYPE vt;
594                 switch (i)
595                 {
596                   case -3: propID = kpidPath; break;
597                   case -2: propID = kpidType; break;
598                   case -1: propID = kpidError; break;
599                   default:
600                     if (getProps->GetArcPropInfo(level, (UInt32)i, &name, &propID, &vt) != S_OK)
601                       continue;
602                 }
603                 NCOM::CPropVariant prop;
604                 if (getProps->GetArcProp(level, propID, &prop) != S_OK)
605                   continue;
606                 AddPropertyString(m_InfoLines, numItems, propID, name, prop);
607               }
608             }
609           }
610           if (level2 != numLevels - 1)
611           {
612             UInt32 level = numLevels - 1 - level2;
613             UInt32 numProps;
614             if (getProps->GetArcNumProps2(level, &numProps) == S_OK)
615             {
616               InsertSeparator(m_InfoLines, numItems);
617               for (Int32 i = 0; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++)
618               {
619                 CMyComBSTR name;
620                 PROPID propID;
621                 VARTYPE vt;
622                 if (getProps->GetArcPropInfo2(level, (UInt32)i, &name, &propID, &vt) != S_OK)
623                   continue;
624                 NCOM::CPropVariant prop;
625                 if (getProps->GetArcProp2(level, propID, &prop) != S_OK)
626                   continue;
627                 AddPropertyString(m_InfoLines, numItems, propID, name, prop);
628               }
629             }
630           }
631         }
632       }
633     }
634   }
635 
636   //m_InfoLines[1].Separator = 0;
637 
638   info->InfoLines = m_InfoLines;
639   info->InfoLinesNumber = (int)numItems;
640 
641 
642   info->DescrFiles = NULL;
643   info->DescrFilesNumber = 0;
644 
645   PanelModeColumnTypes.Empty();
646   PanelModeColumnWidths.Empty();
647 
648   /*
649   AddColumn(kpidName);
650   AddColumn(kpidSize);
651   AddColumn(kpidPackSize);
652   AddColumn(kpidMTime);
653   AddColumn(kpidCTime);
654   AddColumn(kpidATime);
655   AddColumn(kpidAttrib);
656 
657   _panelMode.ColumnTypes = (char *)(const char *)PanelModeColumnTypes;
658   _panelMode.ColumnWidths = (char *)(const char *)PanelModeColumnWidths;
659   _panelMode.ColumnTitles = NULL;
660   _panelMode.FullScreen = TRUE;
661   _panelMode.DetailedStatus = FALSE;
662   _panelMode.AlignExtensions = FALSE;
663   _panelMode.CaseConversion = FALSE;
664   _panelMode.StatusColumnTypes = "N";
665   _panelMode.StatusColumnWidths = "0";
666   _panelMode.Reserved[0] = 0;
667   _panelMode.Reserved[1] = 0;
668 
669   info->PanelModesArray = &_panelMode;
670   info->PanelModesNumber = 1;
671   */
672 
673   info->PanelModesArray = NULL;
674   info->PanelModesNumber = 0;
675 
676   info->StartPanelMode = 0;
677   info->StartSortMode = 0;
678   info->KeyBar = NULL;
679   info->ShortcutData = NULL;
680 }
681 
682 struct CArchiveItemProperty
683 {
684   AString Name;
685   PROPID ID;
686   VARTYPE Type;
687 };
688 
GetHex_A_minus10(unsigned v,unsigned a10)689 static inline char GetHex_A_minus10(unsigned v, unsigned a10)
690 {
691   return (char)(v < 10 ? v + '0' : v + a10);
692 }
693 
ShowAttributesWindow()694 HRESULT CPlugin::ShowAttributesWindow()
695 {
696   PluginPanelItem pluginPanelItem;
697   if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem))
698     return S_FALSE;
699   if (strcmp(pluginPanelItem.FindData.cFileName, "..") == 0 &&
700         NFind::NAttributes::IsDir(pluginPanelItem.FindData.dwFileAttributes))
701     return S_FALSE;
702   const UInt32 itemIndex = (UInt32)pluginPanelItem.UserData;
703 
704   CObjectVector<CArchiveItemProperty> properties;
705   UInt32 numProps;
706   RINOK(_folder->GetNumberOfProperties(&numProps))
707   unsigned i;
708   for (i = 0; i < numProps; i++)
709   {
710     CMyComBSTR name;
711     PROPID propID;
712     VARTYPE vt;
713     RINOK(_folder->GetPropertyInfo(i, &name, &propID, &vt))
714     CArchiveItemProperty prop;
715     prop.Type = vt;
716     prop.ID = propID;
717     if (prop.ID  == kpidPath)
718       prop.ID = kpidName;
719     prop.Name = GetNameOfProp(propID, name);
720     properties.Add(prop);
721   }
722 
723   int size = 2;
724   CRecordVector<CInitDialogItem> initDialogItems;
725 
726   int xSize = 70;
727   {
728     const CInitDialogItem idi =
729       { DI_DOUBLEBOX, 3, 1, xSize - 4, size - 2, false, false, 0, false, NMessageID::kProperties, NULL, NULL };
730     initDialogItems.Add(idi);
731   }
732 
733   AStringVector values;
734 
735   const int kStartY = 3;
736 
737   for (i = 0; i < properties.Size(); i++)
738   {
739     const CArchiveItemProperty &property = properties[i];
740 
741     const int startY = kStartY + (int)values.Size();
742 
743     {
744       CInitDialogItem idi =
745         { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL };
746       idi.DataMessageId = FindPropNameID(property.ID);
747       if (idi.DataMessageId < 0)
748         idi.DataString = property.Name;
749       initDialogItems.Add(idi);
750     }
751 
752     NCOM::CPropVariant prop;
753     RINOK(_folder->GetProperty(itemIndex, property.ID, &prop))
754     values.Add(PropToString(prop, property.ID));
755 
756     {
757       const CInitDialogItem idi =
758         { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL };
759       initDialogItems.Add(idi);
760     }
761   }
762 
763   CMyComPtr<IArchiveGetRawProps> _folderRawProps;
764   _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps);
765 
766   CObjectVector<CArchiveItemProperty> properties2;
767 
768   if (_folderRawProps)
769   {
770     _folderRawProps->GetNumRawProps(&numProps);
771 
772     for (i = 0; i < numProps; i++)
773     {
774       CMyComBSTR name;
775       PROPID propID;
776       if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK)
777         continue;
778       CArchiveItemProperty prop;
779       prop.Type = VT_EMPTY;
780       prop.ID = propID;
781       if (prop.ID  == kpidPath)
782         prop.ID = kpidName;
783       prop.Name = GetNameOfProp(propID, name);
784       properties2.Add(prop);
785     }
786 
787     for (i = 0; i < properties2.Size(); i++)
788     {
789       const CArchiveItemProperty &property = properties2[i];
790       CMyComBSTR name;
791 
792       const void *data;
793       UInt32 dataSize;
794       UInt32 propType;
795       if (_folderRawProps->GetRawProp(itemIndex, property.ID, &data, &dataSize, &propType) != S_OK)
796         continue;
797 
798       if (dataSize != 0)
799       {
800         AString s;
801         if (property.ID == kpidNtSecure)
802           ConvertNtSecureToString((const Byte *)data, dataSize, s);
803         else
804         {
805           const UInt32 kMaxDataSize = 64;
806           if (dataSize > kMaxDataSize)
807           {
808             s += "data:";
809             s.Add_UInt32(dataSize);
810           }
811           else
812           {
813             const unsigned a = dataSize <= 8
814                 && (property.ID == kpidCRC || property.ID == kpidChecksum)
815                 ? 'A' - 10 : 'a' - 10;
816             for (UInt32 k = 0; k < dataSize; k++)
817             {
818               const unsigned b = ((const Byte *)data)[k];
819               s += GetHex_A_minus10(b >> 4, a);
820               s += GetHex_A_minus10(b & 15, a);
821             }
822           }
823         }
824 
825         const int startY = kStartY + (int)values.Size();
826 
827         {
828           CInitDialogItem idi =
829             { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL };
830           idi.DataMessageId = FindPropNameID(property.ID);
831           if (idi.DataMessageId < 0)
832             idi.DataString = property.Name;
833           initDialogItems.Add(idi);
834         }
835 
836         values.Add(s);
837 
838         {
839           const CInitDialogItem idi =
840             { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL };
841           initDialogItems.Add(idi);
842         }
843       }
844     }
845   }
846 
847   const unsigned numLines = values.Size();
848   for (i = 0; i < numLines; i++)
849   {
850     CInitDialogItem &idi = initDialogItems[1 + i * 2 + 1];
851     idi.DataString = values[i];
852   }
853 
854   const unsigned numDialogItems = initDialogItems.Size();
855 
856   CObjArray<FarDialogItem> dialogItems(numDialogItems);
857   g_StartupInfo.InitDialogItems(initDialogItems.ConstData(), dialogItems, numDialogItems);
858 
859   unsigned maxLen = 0;
860 
861   for (i = 0; i < numLines; i++)
862   {
863     FarDialogItem &dialogItem = dialogItems[1 + i * 2];
864     unsigned len = (unsigned)strlen(dialogItem.Data);
865     if (len > maxLen)
866       maxLen = len;
867   }
868 
869   unsigned maxLen2 = 0;
870   const unsigned kSpace = 10;
871 
872   for (i = 0; i < numLines; i++)
873   {
874     FarDialogItem &dialogItem = dialogItems[1 + i * 2 + 1];
875     const unsigned len = (unsigned)strlen(dialogItem.Data);
876     if (len > maxLen2)
877       maxLen2 = len;
878     dialogItem.X1 = (int)(maxLen + kSpace);
879   }
880 
881   size = (int)numLines + 6;
882   xSize = (int)(maxLen + kSpace + maxLen2 + 5);
883   FarDialogItem &firstDialogItem = dialogItems[0];
884   firstDialogItem.Y2 = size - 2;
885   firstDialogItem.X2 = xSize - 4;
886 
887   /* int askCode = */ g_StartupInfo.ShowDialog(xSize, size, NULL, dialogItems, numDialogItems);
888   return S_OK;
889 }
890 
ProcessKey(int key,unsigned controlState)891 int CPlugin::ProcessKey(int key, unsigned controlState)
892 {
893   if (key == VK_F7 && controlState == 0)
894   {
895     CreateFolder();
896     return TRUE;
897   }
898 
899   if (controlState == PKF_CONTROL && key == 'A')
900   {
901     HRESULT result = ShowAttributesWindow();
902     if (result == S_OK)
903       return TRUE;
904     if (result == S_FALSE)
905       return FALSE;
906     throw "Error";
907   }
908 
909   if ((controlState & PKF_ALT) != 0 && key == VK_F6)
910   {
911     FString folderPath;
912     if (!GetOnlyDirPrefix(m_FileName, folderPath))
913       return FALSE;
914     PanelInfo panelInfo;
915     g_StartupInfo.ControlGetActivePanelInfo(panelInfo);
916     GetFilesReal(panelInfo.SelectedItems,
917         (unsigned)panelInfo.SelectedItemsNumber, FALSE,
918         UnicodeStringToMultiByte(fs2us(folderPath), CP_OEMCP), OPM_SILENT, true);
919     g_StartupInfo.Control(this, FCTL_UPDATEPANEL, NULL);
920     g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL);
921     g_StartupInfo.Control(this, FCTL_UPDATEANOTHERPANEL, NULL);
922     g_StartupInfo.Control(this, FCTL_REDRAWANOTHERPANEL, NULL);
923     return TRUE;
924   }
925 
926   return FALSE;
927 }
928