Files
easy7zip/CPP/7zip/UI/Far/Plugin.cpp
Igor Pavlov b82f80647d 4.54 beta
2016-05-28 00:15:54 +01:00

700 lines
19 KiB
C++
Executable File

// Plugin.cpp
#include "StdAfx.h"
#include "Plugin.h"
#include "Common/StringConvert.h"
#include "Common/Wildcard.h"
#include "Windows/PropVariantConversions.h"
#include "Windows/FileName.h"
#include "Windows/FileDir.h"
#include "../Common/PropIDUtils.h"
#include "Messages.h"
#include "FarUtils.h"
using namespace NWindows;
using namespace NFar;
CSysString ConvertPropertyToString2(const PROPVARIANT &propVariant, PROPID propID)
{
if (propVariant.vt == VT_BSTR)
return GetSystemString(propVariant.bstrVal, CP_OEMCP);
if (propVariant.vt != VT_BOOL)
return GetSystemString(ConvertPropertyToString(propVariant, propID), CP_OEMCP);
int messageID = VARIANT_BOOLToBool(propVariant.boolVal) ?
NMessageID::kYes : NMessageID::kNo;
return g_StartupInfo.GetMsgString(messageID);
}
CPlugin::CPlugin(const UString &fileName,
// const UString &defaultName,
IInFolderArchive *archiveHandler,
UString archiveTypeName
):
m_ArchiveHandler(archiveHandler),
m_FileName(fileName),
_archiveTypeName(archiveTypeName)
// , m_DefaultName(defaultName)
// , m_ArchiverInfo(archiverInfo)
{
if (!NFile::NFind::FindFile(m_FileName, m_FileInfo))
throw "error";
archiveHandler->BindToRootFolder(&_folder);
}
CPlugin::~CPlugin()
{
}
static void MyGetFileTime(IFolderFolder *anArchiveFolder, UInt32 itemIndex,
PROPID propID, FILETIME &fileTime)
{
NCOM::CPropVariant propVariant;
if (anArchiveFolder->GetProperty(itemIndex, propID, &propVariant) != S_OK)
throw 271932;
if (propVariant.vt == VT_EMPTY)
{
fileTime.dwHighDateTime = 0;
fileTime.dwLowDateTime = 0;
}
else
{
if (propVariant.vt != VT_FILETIME)
throw 4191730;
fileTime = propVariant.filetime;
}
}
void CPlugin::ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex)
{
NCOM::CPropVariant propVariant;
if (_folder->GetProperty(itemIndex, kpidName, &propVariant) != S_OK)
throw 271932;
if (propVariant.vt != VT_BSTR)
throw 272340;
CSysString oemString = UnicodeStringToMultiByte(propVariant.bstrVal, CP_OEMCP);
const int kFileNameSizeMax = (int)(sizeof(panelItem.FindData.cFileName) / sizeof(panelItem.FindData.cFileName[0]) - 1);
if (oemString.Length() > kFileNameSizeMax)
oemString = oemString.Left(kFileNameSizeMax);
MyStringCopy(panelItem.FindData.cFileName, (const char *)oemString);
panelItem.FindData.cAlternateFileName[0] = 0;
if (_folder->GetProperty(itemIndex, kpidAttributes, &propVariant) != S_OK)
throw 271932;
if (propVariant.vt == VT_UI4)
panelItem.FindData.dwFileAttributes = propVariant.ulVal;
else if (propVariant.vt == VT_EMPTY)
panelItem.FindData.dwFileAttributes = m_FileInfo.Attributes;
else
throw 21631;
if (_folder->GetProperty(itemIndex, kpidIsFolder, &propVariant) != S_OK)
throw 271932;
if (propVariant.vt == VT_BOOL)
{
if (VARIANT_BOOLToBool(propVariant.boolVal))
panelItem.FindData.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
}
else if (propVariant.vt != VT_EMPTY)
throw 21632;
if (_folder->GetProperty(itemIndex, kpidSize, &propVariant) != S_OK)
throw 271932;
UInt64 length;
if (propVariant.vt == VT_EMPTY)
length = 0;
else
length = ::ConvertPropVariantToUInt64(propVariant);
panelItem.FindData.nFileSizeLow = (UInt32)length;
panelItem.FindData.nFileSizeHigh = (UInt32)(length >> 32);
MyGetFileTime(_folder, itemIndex, kpidCreationTime, panelItem.FindData.ftCreationTime);
MyGetFileTime(_folder, itemIndex, kpidLastAccessTime, panelItem.FindData.ftLastAccessTime);
MyGetFileTime(_folder, itemIndex, kpidLastWriteTime, panelItem.FindData.ftLastWriteTime);
if (panelItem.FindData.ftLastWriteTime.dwHighDateTime == 0 &&
panelItem.FindData.ftLastWriteTime.dwLowDateTime == 0)
panelItem.FindData.ftLastWriteTime = m_FileInfo.LastWriteTime;
if (_folder->GetProperty(itemIndex, kpidPackedSize, &propVariant) != S_OK)
throw 271932;
if (propVariant.vt == VT_EMPTY)
length = 0;
else
length = ::ConvertPropVariantToUInt64(propVariant);
panelItem.PackSize = UInt32(length);
panelItem.PackSizeHigh = UInt32(length >> 32);
panelItem.Flags = 0;
panelItem.NumberOfLinks = 0;
panelItem.Description = NULL;
panelItem.Owner = NULL;
panelItem.CustomColumnData = NULL;
panelItem.CustomColumnNumber = 0;
panelItem.Reserved[0] = 0;
panelItem.Reserved[1] = 0;
panelItem.Reserved[2] = 0;
}
int CPlugin::GetFindData(PluginPanelItem **panelItems,
int *itemsNumber, int opMode)
{
// CScreenRestorer screenRestorer;
if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
{
/*
screenRestorer.Save();
const char *msgItems[]=
{
g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
g_StartupInfo.GetMsgString(NMessageID::kReadingList)
};
g_StartupInfo.ShowMessage(0, NULL, msgItems,
sizeof(msgItems) / sizeof(msgItems[0]), 0);
*/
}
UInt32 numItems;
_folder->GetNumberOfItems(&numItems);
*panelItems = new PluginPanelItem[numItems];
try
{
for (UInt32 i = 0; i < numItems; i++)
{
PluginPanelItem &panelItem = (*panelItems)[i];
ReadPluginPanelItem(panelItem, i);
panelItem.UserData = i;
}
}
catch(...)
{
delete [](*panelItems);
throw;
}
*itemsNumber = numItems;
return(TRUE);
}
void CPlugin::FreeFindData(struct PluginPanelItem *panelItems,
int itemsNumber)
{
for (int i = 0; i < itemsNumber; i++)
if (panelItems[i].Description != NULL)
delete []panelItems[i].Description;
delete []panelItems;
}
void CPlugin::EnterToDirectory(const UString &aDirName)
{
CMyComPtr<IFolderFolder> newFolder;
_folder->BindToFolder(aDirName, &newFolder);
if (newFolder == NULL)
if (aDirName.IsEmpty())
return;
else
throw 40325;
_folder = newFolder;
}
int CPlugin::SetDirectory(const char *aszDir, int /* opMode */)
{
UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP);
if (path == L"\\")
{
_folder.Release();
m_ArchiveHandler->BindToRootFolder(&_folder);
}
else if (path == L"..")
{
CMyComPtr<IFolderFolder> newFolder;
_folder->BindToParentFolder(&newFolder);
if (newFolder == NULL)
throw 40312;
_folder = newFolder;
}
else if (path.IsEmpty())
EnterToDirectory(path);
else
{
if (path[0] == L'\\')
{
_folder.Release();
m_ArchiveHandler->BindToRootFolder(&_folder);
path = path.Mid(1);
}
UStringVector pathParts;
SplitPathToParts(path, pathParts);
for (int i = 0; i < pathParts.Size(); i++)
EnterToDirectory(pathParts[i]);
}
GetCurrentDir();
return TRUE;
}
void CPlugin::GetPathParts(UStringVector &pathParts)
{
pathParts.Clear();
CMyComPtr<IFolderFolder> folderItem = _folder;
for (;;)
{
CMyComPtr<IFolderFolder> newFolder;
folderItem->BindToParentFolder(&newFolder);
if (newFolder == NULL)
break;
NCOM::CPropVariant prop;
if (folderItem->GetFolderProperty(kpidName, &prop) == S_OK)
if (prop.vt == VT_BSTR)
pathParts.Insert(0, (const wchar_t *)prop.bstrVal);
folderItem = newFolder;
}
}
void CPlugin::GetCurrentDir()
{
m_CurrentDir.Empty();
UStringVector pathParts;
GetPathParts(pathParts);
for (int i = 0; i < pathParts.Size(); i++)
{
m_CurrentDir += L'\\';
m_CurrentDir += pathParts[i];
}
}
static char *kPluginFormatName = "7-ZIP";
struct CPROPIDToName
{
PROPID PropID;
int PluginID;
};
static CPROPIDToName kPROPIDToName[] =
{
{ kpidName, NMessageID::kName },
{ kpidExtension, NMessageID::kExtension },
{ kpidIsFolder, NMessageID::kIsFolder },
{ kpidSize, NMessageID::kSize },
{ kpidPackedSize, NMessageID::kPackedSize },
{ kpidAttributes, NMessageID::kAttributes },
{ kpidCreationTime, NMessageID::kCreationTime },
{ kpidLastAccessTime, NMessageID::kLastAccessTime },
{ kpidLastWriteTime, NMessageID::kLastWriteTime },
{ kpidSolid, NMessageID::kSolid },
{ kpidCommented, NMessageID::kCommented },
{ kpidEncrypted, NMessageID::kEncrypted },
{ kpidSplitBefore, NMessageID::kSplitBefore },
{ kpidSplitAfter, NMessageID::kSplitAfter },
{ kpidDictionarySize, NMessageID::kDictionarySize },
{ kpidCRC, NMessageID::kCRC },
{ kpidType, NMessageID::kType },
{ kpidIsAnti, NMessageID::kAnti },
{ kpidMethod, NMessageID::kMethod },
{ kpidHostOS, NMessageID::kHostOS },
{ kpidFileSystem, NMessageID::kFileSystem },
{ kpidUser, NMessageID::kUser },
{ kpidGroup, NMessageID::kGroup },
{ kpidBlock, NMessageID::kBlock },
{ kpidComment, NMessageID::kComment },
{ kpidPosition, NMessageID::kPosition },
{ kpidNumSubFolders, NMessageID::kNumSubFolders },
{ kpidNumSubFiles, NMessageID::kNumSubFiles },
{ kpidUnpackVer, NMessageID::kUnpackVer },
{ kpidVolume, NMessageID::kVolume },
{ kpidIsVolume, NMessageID::kIsVolume },
{ kpidOffset, NMessageID::kOffset },
{ kpidLinks, NMessageID::kLinks },
{ kpidNumBlocks, NMessageID::kNumBlocks },
{ kpidNumVolumes, NMessageID::kNumVolumes }
};
static const int kNumPROPIDToName = sizeof(kPROPIDToName) / sizeof(kPROPIDToName[0]);
static int FindPropertyToName(PROPID propID)
{
for (int i = 0; i < kNumPROPIDToName; i++)
if (kPROPIDToName[i].PropID == propID)
return i;
return -1;
}
/*
struct CPropertyIDInfo
{
PROPID PropID;
const char *FarID;
int Width;
// char CharID;
};
static CPropertyIDInfo kPropertyIDInfos[] =
{
{ kpidName, "N", 0},
{ kpidSize, "S", 8},
{ kpidPackedSize, "P", 8},
{ kpidAttributes, "A", 0},
{ kpidCreationTime, "DC", 14},
{ kpidLastAccessTime, "DA", 14},
{ kpidLastWriteTime, "DM", 14},
{ kpidSolid, NULL, 0, 'S'},
{ kpidEncrypted, NULL, 0, 'P'}
{ kpidDictionarySize, IDS_PROPERTY_DICTIONARY_SIZE },
{ kpidSplitBefore, NULL, 'B'},
{ kpidSplitAfter, NULL, 'A'},
{ kpidComment, , NULL, 'C'},
{ kpidCRC, IDS_PROPERTY_CRC }
// { kpidType, L"Type" }
};
static const int kNumPropertyIDInfos = sizeof(kPropertyIDInfos) /
sizeof(kPropertyIDInfos[0]);
static int FindPropertyInfo(PROPID propID)
{
for (int i = 0; i < kNumPropertyIDInfos; i++)
if (kPropertyIDInfos[i].PropID == propID)
return i;
return -1;
}
*/
// char *g_Titles[] = { "a", "f", "v" };
/*
static void SmartAddToString(AString &destString, const char *srcString)
{
if (!destString.IsEmpty())
destString += ',';
destString += srcString;
}
*/
/*
void CPlugin::AddColumn(PROPID propID)
{
int index = FindPropertyInfo(propID);
if (index >= 0)
{
for (int i = 0; i < m_ProxyHandler->m_InternalProperties.Size(); i++)
{
const CArchiveItemProperty &aHandlerProperty = m_ProxyHandler->m_InternalProperties[i];
if (aHandlerProperty.ID == propID)
break;
}
if (i == m_ProxyHandler->m_InternalProperties.Size())
return;
const CPropertyIDInfo &propertyIDInfo = kPropertyIDInfos[index];
SmartAddToString(PanelModeColumnTypes, propertyIDInfo.FarID);
char tmp[32];
itoa(propertyIDInfo.Width, tmp, 10);
SmartAddToString(PanelModeColumnWidths, tmp);
return;
}
}
*/
void CPlugin::GetOpenPluginInfo(struct OpenPluginInfo *info)
{
info->StructSize = sizeof(*info);
info->Flags = OPIF_USEFILTER | OPIF_USESORTGROUPS| OPIF_USEHIGHLIGHTING|
OPIF_ADDDOTS | OPIF_COMPAREFATTIME;
UINT codePage = ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;
MyStringCopy(m_FileNameBuffer, (const char *)UnicodeStringToMultiByte(m_FileName, codePage));
info->HostFile = m_FileNameBuffer; // test it it is not static
MyStringCopy(m_CurrentDirBuffer, (const char *)UnicodeStringToMultiByte(m_CurrentDir, CP_OEMCP));
info->CurDir = m_CurrentDirBuffer;
info->Format = kPluginFormatName;
UString name;
{
UString fullName;
int index;
NFile::NDirectory::MyGetFullPathName(m_FileName, fullName, index);
name = fullName.Mid(index);
}
m_PannelTitle =
UString(L' ') +
_archiveTypeName +
UString(L':') +
name +
UString(L' ');
if (!m_CurrentDir.IsEmpty())
{
// m_PannelTitle += '\\';
m_PannelTitle += m_CurrentDir;
}
MyStringCopy(m_PannelTitleBuffer, (const char *)UnicodeStringToMultiByte(m_PannelTitle, CP_OEMCP));
info->PanelTitle = m_PannelTitleBuffer;
memset(m_InfoLines, 0, sizeof(m_InfoLines));
MyStringCopy(m_InfoLines[0].Text, "");
m_InfoLines[0].Separator = TRUE;
MyStringCopy(m_InfoLines[1].Text, g_StartupInfo.GetMsgString(NMessageID::kArchiveType));
MyStringCopy(m_InfoLines[1].Data, (const char *)UnicodeStringToMultiByte(_archiveTypeName, CP_OEMCP));
int numItems = 2;
CMyComPtr<IFolderProperties> folderProperties;
_folder.QueryInterface(IID_IFolderProperties, &folderProperties);
if (folderProperties)
{
UInt32 numProps;
if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK)
{
for (UInt32 i = 0; i < numProps && numItems < kNumInfoLinesMax; i++)
{
CMyComBSTR name;
PROPID propID;
VARTYPE vt;
if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK)
continue;
InfoPanelLine &item = m_InfoLines[numItems];
int index = FindPropertyToName(propID);
AString s;
if (index < 0)
{
if (name != 0)
s = (const char *)UnicodeStringToMultiByte((const wchar_t *)name, CP_OEMCP);
}
else
s = g_StartupInfo.GetMsgString(kPROPIDToName[index].PluginID);
if (s.Length() > (kInfoPanelLineSize - 1))
s = s.Left(kInfoPanelLineSize - 1);
MyStringCopy(item.Text, (const char *)s);
NCOM::CPropVariant propVariant;
if (_folder->GetFolderProperty(propID, &propVariant) != S_OK)
continue;
s = ConvertPropertyToString2(propVariant, propID);
s.Replace((char)0xA, ' ');
s.Replace((char)0xD, ' ');
if (s.Length() > (kInfoPanelLineSize - 1))
s = s.Left(kInfoPanelLineSize - 1);
MyStringCopy(item.Data, (const char *)s);
numItems++;
}
}
}
//m_InfoLines[1].Separator = 0;
info->InfoLines = m_InfoLines;
info->InfoLinesNumber = numItems;
info->DescrFiles = NULL;
info->DescrFilesNumber = 0;
PanelModeColumnTypes.Empty();
PanelModeColumnWidths.Empty();
/*
AddColumn(kpidName);
AddColumn(kpidSize);
AddColumn(kpidPackedSize);
AddColumn(kpidLastWriteTime);
AddColumn(kpidCreationTime);
AddColumn(kpidLastAccessTime);
AddColumn(kpidAttributes);
PanelMode.ColumnTypes = (char *)(const char *)PanelModeColumnTypes;
PanelMode.ColumnWidths = (char *)(const char *)PanelModeColumnWidths;
PanelMode.ColumnTitles = NULL;
PanelMode.FullScreen = TRUE;
PanelMode.DetailedStatus = FALSE;
PanelMode.AlignExtensions = FALSE;
PanelMode.CaseConversion = FALSE;
PanelMode.StatusColumnTypes = "N";
PanelMode.StatusColumnWidths = "0";
PanelMode.Reserved[0] = 0;
PanelMode.Reserved[1] = 0;
info->PanelModesArray = &PanelMode;
info->PanelModesNumber = 1;
*/
info->PanelModesArray = NULL;
info->PanelModesNumber = 0;
info->StartPanelMode = 0;
info->StartSortMode = 0;
info->KeyBar = NULL;
info->ShortcutData = NULL;
}
struct CArchiveItemProperty
{
AString Name;
PROPID ID;
VARTYPE Type;
};
HRESULT CPlugin::ShowAttributesWindow()
{
PluginPanelItem pluginPanelItem;
if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem))
return S_FALSE;
if (strcmp(pluginPanelItem.FindData.cFileName, "..") == 0 &&
NFile::NFind::NAttributes::IsDirectory(pluginPanelItem.FindData.dwFileAttributes))
return S_FALSE;
int itemIndex = pluginPanelItem.UserData;
CObjectVector<CArchiveItemProperty> properties;
UInt32 numProps;
RINOK(_folder->GetNumberOfProperties(&numProps));
int i;
for (i = 0; i < (int)numProps; i++)
{
CMyComBSTR name;
PROPID propID;
VARTYPE vt;
RINOK(_folder->GetPropertyInfo(i, &name, &propID, &vt));
CArchiveItemProperty destProperty;
destProperty.Type = vt;
destProperty.ID = propID;
if (destProperty.ID == kpidPath)
destProperty.ID = kpidName;
AString propName;
{
if (name != NULL)
destProperty.Name = UnicodeStringToMultiByte((const wchar_t *)name, CP_OEMCP);
else
destProperty.Name = "?";
}
properties.Add(destProperty);
}
int size = 2;
CRecordVector<CInitDialogItem> initDialogItems;
int xSize = 70;
CInitDialogItem initDialogItem =
{ DI_DOUBLEBOX, 3, 1, xSize - 4, size - 2, false, false, 0, false, NMessageID::kProperties, NULL, NULL };
initDialogItems.Add(initDialogItem);
AStringVector values;
for (i = 0; i < properties.Size(); i++)
{
const CArchiveItemProperty &property = properties[i];
CInitDialogItem initDialogItem =
{ DI_TEXT, 5, 3 + i, 0, 0, false, false, 0, false, 0, NULL, NULL };
int index = FindPropertyToName(property.ID);
if (index < 0)
{
initDialogItem.DataMessageId = -1;
initDialogItem.DataString = property.Name;
}
else
initDialogItem.DataMessageId = kPROPIDToName[index].PluginID;
initDialogItems.Add(initDialogItem);
NCOM::CPropVariant propVariant;
RINOK(_folder->GetProperty(itemIndex, property.ID, &propVariant));
CSysString s = ConvertPropertyToString2(propVariant, property.ID);
values.Add(s);
{
CInitDialogItem initDialogItem =
{ DI_TEXT, 30, 3 + i, 0, 0, false, false, 0, false, -1, NULL, NULL };
initDialogItems.Add(initDialogItem);
}
}
int numLines = values.Size();
for (i = 0; i < numLines; i++)
{
CInitDialogItem &initDialogItem = initDialogItems[1 + i * 2 + 1];
initDialogItem.DataString = values[i];
}
int numDialogItems = initDialogItems.Size();
CRecordVector<FarDialogItem> dialogItems;
dialogItems.Reserve(numDialogItems);
for (i = 0; i < numDialogItems; i++)
dialogItems.Add(FarDialogItem());
g_StartupInfo.InitDialogItems(&initDialogItems.Front(),
&dialogItems.Front(), numDialogItems);
int maxLen = 0;
for (i = 0; i < numLines; i++)
{
FarDialogItem &dialogItem = dialogItems[1 + i * 2];
int len = (int)strlen(dialogItem.Data);
if (len > maxLen)
maxLen = len;
}
int maxLen2 = 0;
const int kSpace = 10;
for (i = 0; i < numLines; i++)
{
FarDialogItem &dialogItem = dialogItems[1 + i * 2 + 1];
int len = (int)strlen(dialogItem.Data);
if (len > maxLen2)
maxLen2 = len;
dialogItem.X1 = maxLen + kSpace;
}
size = numLines + 6;
xSize = maxLen + kSpace + maxLen2 + 5;
FarDialogItem &firstDialogItem = dialogItems.Front();
firstDialogItem.Y2 = size - 2;
firstDialogItem.X2 = xSize - 4;
/* int askCode = */ g_StartupInfo.ShowDialog(xSize, size, NULL, &dialogItems.Front(), numDialogItems);
return S_OK;
}
int CPlugin::ProcessKey(int key, unsigned int controlState)
{
if (controlState == PKF_CONTROL && key == 'A')
{
HRESULT result = ShowAttributesWindow();
if (result == S_OK)
return TRUE;
if (result == S_FALSE)
return FALSE;
throw "Error";
}
if ((controlState & PKF_ALT) != 0 && key == VK_F6)
{
UString folderPath;
if (!NFile::NDirectory::GetOnlyDirPrefix(m_FileName, folderPath))
return FALSE;
PanelInfo panelInfo;
g_StartupInfo.ControlGetActivePanelInfo(panelInfo);
GetFilesReal(panelInfo.SelectedItems,
panelInfo.SelectedItemsNumber, FALSE,
UnicodeStringToMultiByte(folderPath, CP_OEMCP), OPM_SILENT, true);
g_StartupInfo.Control(this, FCTL_UPDATEPANEL, NULL);
g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL);
g_StartupInfo.Control(this, FCTL_UPDATEANOTHERPANEL, NULL);
g_StartupInfo.Control(this, FCTL_REDRAWANOTHERPANEL, NULL);
return TRUE;
}
return FALSE;
}