2 #include "MultiArc.hpp"
5 PluginClass::PluginClass(int ArcPluginNumber
)
8 PluginClass::ArcPluginNumber
= ArcPluginNumber
;
10 bGOPIFirstCall
= true;
14 PluginClass::~PluginClass()
19 void PluginClass::FreeArcData()
25 int PluginClass::PreReadArchive(const char *Name
)
27 if (sdc_stat(Name
, &ArcStat
) == -1) {
33 if (FindExt(ArcName
) == std::string::npos
) {
40 static void SanitizeString(std::string
&s
)
42 while (!s
.empty() && !s
.back()) {
47 int PluginClass::ReadArchive(const char *Name
, int OpMode
)
49 bGOPIFirstCall
= true;
53 if (sdc_stat(Name
, &ArcStat
) == -1)
56 if (!ArcPlugin
->OpenArchive(ArcPluginNumber
, Name
, &ArcPluginType
, (OpMode
& OPM_SILENT
) != 0))
59 ItemsInfo
= ArcItemInfo
{};
61 TotalSize
= PackedSize
= 0;
64 HANDLE hScreen
= Info
.SaveScreen(0, 0, -1, -1);
66 DWORD UpdateTime
= GetProcessUptimeMSec() + 1000;
67 bool MessageShown
= false;
70 ArcItemInfo CurItemInfo
;
73 CurItemInfo
= ArcItemInfo();
74 GetItemCode
= ArcPlugin
->GetArcItem(ArcPluginNumber
, &CurItemInfo
);
75 if (GetItemCode
!= GETARC_SUCCESS
)
78 SanitizeString(CurItemInfo
.PathName
);
79 if (CurItemInfo
.Description
)
80 SanitizeString(*CurItemInfo
.Description
);
81 if (CurItemInfo
.LinkName
)
82 SanitizeString(*CurItemInfo
.LinkName
);
84 if ((ArcDataCount
& 0x1f) == 0) {
87 ArcPlugin
->CloseArchive(ArcPluginNumber
, &CurArcInfo
);
88 Info
.RestoreScreen(NULL
);
89 Info
.RestoreScreen(hScreen
);
93 const DWORD Now
= GetProcessUptimeMSec();
94 if (Now
>= UpdateTime
) {
95 UpdateTime
= Now
+ 100;
96 const auto &NameMsg
= FormatMessagePath(Name
, false);
97 const auto &FilesMsg
= StrPrintf(GetMsg(MArcReadFiles
), (unsigned int)ArcDataCount
);
98 const char *MsgItems
[] = {GetMsg(MArcReadTitle
), GetMsg(MArcReading
), NameMsg
.c_str(), FilesMsg
.c_str()};
99 Info
.Message(Info
.ModuleNumber
, MessageShown
? FMSG_KEEPBACKGROUND
: 0, NULL
, MsgItems
,
100 ARRAYSIZE(MsgItems
), 0);
105 if (CurItemInfo
.Description
)
108 if (CurItemInfo
.HostOS
&& (!ItemsInfo
.HostOS
|| strcmp(ItemsInfo
.HostOS
, CurItemInfo
.HostOS
) != 0))
109 ItemsInfo
.HostOS
= (ItemsInfo
.HostOS
? CurItemInfo
.HostOS
: GetMsg(MSeveralOS
));
111 if (ItemsInfo
.Codepage
<= 0)
112 ItemsInfo
.Codepage
= CurItemInfo
.Codepage
;
114 ItemsInfo
.Solid
|= CurItemInfo
.Solid
;
115 ItemsInfo
.Comment
|= CurItemInfo
.Comment
;
116 ItemsInfo
.Encrypted
|= CurItemInfo
.Encrypted
;
118 if (CurItemInfo
.Encrypted
)
119 CurItemInfo
.Flags
|= F_ENCRYPTED
;
121 if (CurItemInfo
.DictSize
> ItemsInfo
.DictSize
)
122 ItemsInfo
.DictSize
= CurItemInfo
.DictSize
;
124 if (CurItemInfo
.UnpVer
> ItemsInfo
.UnpVer
)
125 ItemsInfo
.UnpVer
= CurItemInfo
.UnpVer
;
127 CurItemInfo
.NumberOfLinks
= 1;
129 size_t PrefixSize
= 0;
130 if (StrStartsFrom(CurItemInfo
.PathName
, "./"))
132 else if (StrStartsFrom(CurItemInfo
.PathName
, "../"))
134 while (PrefixSize
< CurItemInfo
.PathName
.size() && CurItemInfo
.PathName
[PrefixSize
] == '/')
138 CurItemInfo
.Prefix
.reset(new std::string(CurItemInfo
.PathName
.substr(0, PrefixSize
)));
139 CurItemInfo
.PathName
.erase(0, PrefixSize
);
142 if (!CurItemInfo
.PathName
.empty() && CurItemInfo
.PathName
.back() == '/')
143 CurItemInfo
.dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
145 TotalSize
+= CurItemInfo
.nFileSize
;
146 PackedSize
+= CurItemInfo
.nPhysicalSize
;
149 CurPP
.Traverse(CurItemInfo
.PathName
);
150 ArcItemAttributes
*CurAttrs
= ArcData
.Ensure(CurPP
.begin(), CurPP
.end());
151 *CurAttrs
= std::move(CurItemInfo
);
155 Info
.RestoreScreen(NULL
);
156 Info
.RestoreScreen(hScreen
);
158 ArcPlugin
->CloseArchive(ArcPluginNumber
, &CurArcInfo
);
160 if (GetItemCode
!= GETARC_EOF
&& GetItemCode
!= GETARC_SUCCESS
) {
161 switch (GetItemCode
) {
163 GetItemCode
= MBadArchive
;
166 case GETARC_UNEXPEOF
:
167 GetItemCode
= MUnexpEOF
;
170 case GETARC_READERROR
:
171 GetItemCode
= MReadError
;
175 const auto &NameMsg
= FormatMessagePath(Name
, true);
176 const char *MsgItems
[] = {GetMsg(MError
), NameMsg
.c_str(), GetMsg(GetItemCode
), GetMsg(MOk
)};
177 Info
.Message(Info
.ModuleNumber
, FMSG_WARNING
, NULL
, MsgItems
, ARRAYSIZE(MsgItems
), 1);
178 return FALSE
; // Mantis#0001241
181 // Info.RestoreScreen(NULL);
182 // Info.RestoreScreen(hScreen);
186 bool PluginClass::EnsureFindDataUpToDate(int OpMode
)
188 if (!ArcData
.empty()) {
189 struct stat NewArcStat
{};
190 if (sdc_stat(ArcName
.c_str(), &NewArcStat
) == -1)
193 if (ArcStat
.st_mtime
== NewArcStat
.st_mtime
&& ArcStat
.st_size
== NewArcStat
.st_size
)
197 DWORD size
= (DWORD
)Info
.AdvControl(Info
.ModuleNumber
, ACTL_GETPLUGINMAXREADDATA
, (void *)0);
198 int fd
= sdc_open(ArcName
.c_str(), O_RDONLY
);
202 unsigned char *Data
= (unsigned char *)malloc(size
);
203 ssize_t read_size
= Data
? sdc_read(fd
, Data
, size
) : -1;
206 bool ReadArcOK
= false;
210 ReadArcOK
= (ArcPlugin
->IsArchive(ArcPluginNumber
, ArcName
.c_str(), Data
, read_size
, &SFXSize
)
211 && ReadArchive(ArcName
.c_str(), OpMode
));
218 int PluginClass::GetFindData(PluginPanelItem
**pPanelItem
, int *pItemsNumber
, int OpMode
)
224 CurDirPP
.Traverse(CurDir
);
226 if (!EnsureFindDataUpToDate(OpMode
)) {
227 fprintf(stderr
, "MA::GetFindData: can't update at '%s'\n", CurDirPP
.Join().c_str());
231 const auto *DirNode
= ArcData
.Find(CurDirPP
.begin(), CurDirPP
.end());
233 fprintf(stderr
, "MA::GetFindData: no node at '%s'\n", CurDirPP
.Join().c_str());
237 if (DirNode
->empty())
240 PluginPanelItem
*CurrentItem
= *pPanelItem
=
241 (PluginPanelItem
*)calloc(DirNode
->size(), sizeof(PluginPanelItem
));
243 fprintf(stderr
, "MA::GetFindData: can't alloc %lu items at '%s'\n", (unsigned long)DirNode
->size(),
244 CurDirPP
.Join().c_str());
247 *pItemsNumber
= (int)DirNode
->size();
249 for (const auto &it
: *DirNode
) {
250 CurrentItem
->FindData
.ftCreationTime
= it
.second
.ftCreationTime
;
251 CurrentItem
->FindData
.ftLastAccessTime
= it
.second
.ftLastAccessTime
;
252 CurrentItem
->FindData
.ftLastWriteTime
= it
.second
.ftLastWriteTime
;
253 CurrentItem
->FindData
.nPhysicalSize
= it
.second
.nPhysicalSize
;
254 CurrentItem
->FindData
.nFileSize
= it
.second
.nFileSize
;
255 CurrentItem
->FindData
.dwFileAttributes
= it
.second
.dwFileAttributes
;
256 CurrentItem
->FindData
.dwUnixMode
= it
.second
.dwUnixMode
;
257 strncpy(CurrentItem
->FindData
.cFileName
, it
.first
.c_str(),
258 ARRAYSIZE(CurrentItem
->FindData
.cFileName
));
259 CurrentItem
->Flags
= it
.second
.Flags
;
260 CurrentItem
->NumberOfLinks
= it
.second
.NumberOfLinks
;
261 CurrentItem
->CRC32
= it
.second
.CRC32
;
262 CurrentItem
->Description
= it
.second
.Description
? (char *)it
.second
.Description
->c_str() : nullptr;
263 CurrentItem
->UserData
= (DWORD_PTR
)&it
.second
;
265 if (!it
.second
.empty())
266 CurrentItem
->FindData
.dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
267 if (CurrentItem
->FindData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
268 CurrentItem
->FindData
.nPhysicalSize
= CurrentItem
->FindData
.nFileSize
= 0;
276 void PluginClass::FreeFindData(PluginPanelItem
*PanelItem
, int ItemsNumber
)
282 int PluginClass::SetDirectory(const char *Dir
, int OpMode
)
284 if (*Dir
== '/' && *(++Dir
) == 0) {
290 NewDirPP
.Traverse(CurDir
);
291 NewDirPP
.Traverse(Dir
);
292 const auto &NewDir
= NewDirPP
.Join();
294 auto *DirNode
= ArcData
.Find(NewDirPP
.begin(), NewDirPP
.end());
296 fprintf(stderr
, "MA::SetDirectory('%s', %d): no node for '%s'\n", Dir
, OpMode
, NewDir
.c_str());
300 if (NewDir
.size() >= ARRAYSIZE(CurDir
)) {
301 fprintf(stderr
, "MA::SetDirectory('%s', %d): too long path '%s'\n", Dir
, OpMode
, NewDir
.c_str());
305 CharArrayCpyZ(CurDir
, NewDir
.c_str());
309 bool PluginClass::FarLangChanged()
311 const char *tmplang
= getenv("FARLANG");
316 if (farlang
== tmplang
)
323 static void AppendInfoData(std::string
&Str
, const char *Data
)
330 void PluginClass::SetInfoLineSZ(size_t Index
, int TextID
, const char *Data
)
332 CharArrayCpyZ(InfoLines
[Index
].Text
, GetMsg(TextID
));
333 CharArrayCpyZ(InfoLines
[Index
].Data
, Data
);
336 void PluginClass::SetInfoLine(size_t Index
, int TextID
, const std::string
&Data
)
338 SetInfoLineSZ(Index
, TextID
, Data
.c_str());
341 void PluginClass::SetInfoLine(size_t Index
, int TextID
, int DataID
)
343 SetInfoLineSZ(Index
, TextID
, GetMsg(DataID
));
346 void PluginClass::GetOpenPluginInfo(struct OpenPluginInfo
*Info
)
348 Info
->StructSize
= sizeof(*Info
);
349 Info
->Flags
= OPIF_USEFILTER
| OPIF_USESORTGROUPS
| OPIF_USEHIGHLIGHTING
| OPIF_ADDDOTS
| OPIF_COMPAREFATTIME
;
350 Info
->HostFile
= ArcName
.c_str();
351 Info
->CurDir
= CurDir
;
354 ArcPlugin
->GetFormatName(ArcPluginNumber
, ArcPluginType
, FormatName
, DefExt
);
356 std::string NameTitle
;
357 struct PanelInfo PInfo
;
358 if (::Info
.Control((HANDLE
)this, FCTL_GETPANELSHORTINFO
, &PInfo
)) { // TruncStr
359 NameTitle
= FormatMessagePath(ArcName
.c_str(), true,
360 (PInfo
.PanelRect
.right
- PInfo
.PanelRect
.left
+ 1 - (FormatName
.size() + 3 + 4)));
362 NameTitle
= FormatMessagePath(ArcName
.c_str(), true, -1);
365 PanelTitle
= StrPrintf(" %s:%s%s%s ", FormatName
.c_str(), NameTitle
.c_str(), *CurDir
? "/" : "", *CurDir
? CurDir
: "");
367 Info
->PanelTitle
= PanelTitle
.c_str();
369 if (bGOPIFirstCall
|| FarLangChanged()) {
370 Format
= StrPrintf(GetMsg(MArcFormat
), FormatName
.c_str());
373 FSF
.snprintf(InfoLines
[0].Text
, ARRAYSIZE(InfoLines
[0].Text
), GetMsg(MInfoTitle
), FSF
.PointToName((char *)ArcName
.c_str()));
374 InfoLines
[0].Separator
= TRUE
;
376 std::string TmpInfoData
= FormatName
;
377 if (ItemsInfo
.UnpVer
!= 0)
378 TmpInfoData
+= StrPrintf(" %d.%d", ItemsInfo
.UnpVer
/ 256, ItemsInfo
.UnpVer
% 256);
379 if (ItemsInfo
.HostOS
)
380 TmpInfoData
+= StrPrintf("/%s", ItemsInfo
.HostOS
);
381 SetInfoLine(1, MInfoArchive
, TmpInfoData
);
383 TmpInfoData
= ItemsInfo
.Solid
? GetMsg(MInfoSolid
) : "";
384 if (CurArcInfo
.SFXSize
)
385 AppendInfoData(TmpInfoData
, GetMsg(MInfoSFX
));
386 if (CurArcInfo
.Flags
& AF_HDRENCRYPTED
)
387 AppendInfoData(TmpInfoData
, GetMsg(MInfoHdrEncrypted
));
388 if (CurArcInfo
.Volume
)
389 AppendInfoData(TmpInfoData
, GetMsg(MInfoVolume
));
390 if (TmpInfoData
.empty())
391 TmpInfoData
= GetMsg(MInfoNormal
);
392 SetInfoLine(2, MInfoArcType
, TmpInfoData
);
394 SetInfoLine(3, MInfoArcComment
, CurArcInfo
.Comment
? MInfoPresent
: MInfoAbsent
);
395 SetInfoLine(4, MInfoFileComments
, ItemsInfo
.Comment
? MInfoPresent
: MInfoAbsent
);
396 SetInfoLine(5, MInfoPasswords
, ItemsInfo
.Encrypted
? MInfoPresent
: MInfoAbsent
);
397 SetInfoLine(6, MInfoRecovery
, CurArcInfo
.Recovery
? MInfoPresent
: MInfoAbsent
);
398 SetInfoLine(7, MInfoLock
, CurArcInfo
.Lock
? MInfoPresent
: MInfoAbsent
);
399 SetInfoLine(8, MInfoAuthVer
, (CurArcInfo
.Flags
& AF_AVPRESENT
) ? MInfoPresent
: MInfoAbsent
);
401 if (ItemsInfo
.DictSize
)
402 SetInfoLine(9, MInfoDict
, StrPrintf("%d %s", ItemsInfo
.DictSize
, GetMsg(MInfoDictKb
)));
404 SetInfoLine(9, MInfoDict
, MInfoAbsent
);
406 if (CurArcInfo
.Chapters
)
407 SetInfoLine(10, MInfoChapters
, std::to_string(CurArcInfo
.Chapters
));
409 SetInfoLine(10, MInfoChapters
, MInfoAbsent
);
411 SetInfoLine(11, MInfoTotalFiles
, std::to_string(ArcDataCount
));
412 SetInfoLine(12, MInfoTotalSize
, NumberWithCommas(TotalSize
));
413 SetInfoLine(13, MInfoPackedSize
, NumberWithCommas(PackedSize
));
414 SetInfoLine(14, MInfoRatio
, StrPrintf("%d%%", MA_ToPercent(PackedSize
, TotalSize
)));
417 KeyBar
.ShiftTitles
[1 - 1] = (char *)"";
418 KeyBar
.AltTitles
[6 - 1] = (char *)GetMsg(MAltF6
);
419 KeyBar
.AltShiftTitles
[9 - 1] = (char *)GetMsg(MAltShiftF9
);
422 Info
->Format
= Format
.c_str();
423 Info
->KeyBar
= &KeyBar
;
424 Info
->InfoLines
= InfoLines
;
425 Info
->InfoLinesNumber
= ARRAYSIZE(InfoLines
);
427 CharArrayCpyZ(DescrFilesString
, Opt
.DescriptionNames
.c_str());
429 size_t DescrFilesNumber
= 0;
430 char *NamePtr
= DescrFilesString
;
432 while (DescrFilesNumber
< ARRAYSIZE(DescrFiles
)) {
433 while (__isspace(*NamePtr
))
437 DescrFiles
[DescrFilesNumber
++] = NamePtr
;
438 if ((NamePtr
= strchr(NamePtr
, ',')) == NULL
)
443 Info
->DescrFiles
= DescrFiles
;
445 if (!Opt
.ReadDescriptions
|| DizPresent
)
446 Info
->DescrFilesNumber
= 0;
448 Info
->DescrFilesNumber
= (int)DescrFilesNumber
;
450 bGOPIFirstCall
= false;