2 #include "MultiArc.hpp"
5 PluginClass::PluginClass(int ArcPluginNumber
)
9 PluginClass::ArcPluginNumber
= ArcPluginNumber
;
11 bGOPIFirstCall
= true;
16 PluginClass::~PluginClass()
21 void PluginClass::FreeArcData()
27 int PluginClass::PreReadArchive(const char *Name
)
29 if (sdc_stat(Name
, &ArcStat
) == -1) {
33 ArrayCpyZ(ArcName
, Name
);
35 if (strchr(FSF
.PointToName(ArcName
), '.') == NULL
)
41 static void SanitizeString(std::string
&s
)
43 while (!s
.empty() && !s
.back()) {
48 int PluginClass::ReadArchive(const char *Name
, int OpMode
)
50 bGOPIFirstCall
= true;
54 if (sdc_stat(Name
, &ArcStat
) == -1)
57 if (!ArcPlugin
->OpenArchive(ArcPluginNumber
, Name
, &ArcPluginType
, (OpMode
& OPM_SILENT
) != 0))
60 ItemsInfo
= ArcItemInfo
{};
62 TotalSize
= PackedSize
= 0;
65 HANDLE hScreen
= Info
.SaveScreen(0, 0, -1, -1);
67 DWORD UpdateTime
= GetProcessUptimeMSec() + 1000;
68 bool MessageShown
= false;
71 ArcItemInfo CurItemInfo
;
74 CurItemInfo
= ArcItemInfo();
75 GetItemCode
= ArcPlugin
->GetArcItem(ArcPluginNumber
, &CurItemInfo
);
76 if (GetItemCode
!= GETARC_SUCCESS
)
79 SanitizeString(CurItemInfo
.PathName
);
80 if (CurItemInfo
.Description
)
81 SanitizeString(*CurItemInfo
.Description
);
82 if (CurItemInfo
.LinkName
)
83 SanitizeString(*CurItemInfo
.LinkName
);
85 if ((ArcDataCount
& 0x1f) == 0) {
88 ArcPlugin
->CloseArchive(ArcPluginNumber
, &CurArcInfo
);
89 Info
.RestoreScreen(NULL
);
90 Info
.RestoreScreen(hScreen
);
94 const DWORD Now
= GetProcessUptimeMSec();
95 if (Now
>= UpdateTime
) {
96 UpdateTime
= Now
+ 100;
99 FSF
.sprintf(FilesMsg
, GetMsg(MArcReadFiles
), (unsigned int)ArcDataCount
);
100 const char *MsgItems
[] = {GetMsg(MArcReadTitle
), GetMsg(MArcReading
), NameMsg
, FilesMsg
};
101 ArrayCpyZ(NameMsg
, Name
);
102 FSF
.TruncPathStr(NameMsg
, MAX_WIDTH_MESSAGE
);
103 Info
.Message(Info
.ModuleNumber
, MessageShown
? FMSG_KEEPBACKGROUND
: 0, NULL
, MsgItems
,
104 ARRAYSIZE(MsgItems
), 0);
109 if (CurItemInfo
.Description
)
112 if (CurItemInfo
.HostOS
&& (!ItemsInfo
.HostOS
|| strcmp(ItemsInfo
.HostOS
, CurItemInfo
.HostOS
) != 0))
113 ItemsInfo
.HostOS
= (ItemsInfo
.HostOS
? CurItemInfo
.HostOS
: GetMsg(MSeveralOS
));
115 if (ItemsInfo
.Codepage
<= 0)
116 ItemsInfo
.Codepage
= CurItemInfo
.Codepage
;
118 ItemsInfo
.Solid
|= CurItemInfo
.Solid
;
119 ItemsInfo
.Comment
|= CurItemInfo
.Comment
;
120 ItemsInfo
.Encrypted
|= CurItemInfo
.Encrypted
;
122 if (CurItemInfo
.Encrypted
)
123 CurItemInfo
.Flags
|= F_ENCRYPTED
;
125 if (CurItemInfo
.DictSize
> ItemsInfo
.DictSize
)
126 ItemsInfo
.DictSize
= CurItemInfo
.DictSize
;
128 if (CurItemInfo
.UnpVer
> ItemsInfo
.UnpVer
)
129 ItemsInfo
.UnpVer
= CurItemInfo
.UnpVer
;
131 CurItemInfo
.NumberOfLinks
= 1;
133 size_t PrefixSize
= 0;
134 if (StrStartsFrom(CurItemInfo
.PathName
, "./"))
136 else if (StrStartsFrom(CurItemInfo
.PathName
, "../"))
138 while (PrefixSize
< CurItemInfo
.PathName
.size() && CurItemInfo
.PathName
[PrefixSize
] == '/')
142 CurItemInfo
.Prefix
.reset(new std::string(CurItemInfo
.PathName
.substr(0, PrefixSize
)));
143 CurItemInfo
.PathName
.erase(0, PrefixSize
);
146 if (!CurItemInfo
.PathName
.empty() && CurItemInfo
.PathName
.back() == '/')
147 CurItemInfo
.dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
149 TotalSize
+= CurItemInfo
.nFileSize
;
150 PackedSize
+= CurItemInfo
.nPhysicalSize
;
153 CurPP
.Traverse(CurItemInfo
.PathName
);
154 ArcItemAttributes
*CurAttrs
= ArcData
.Ensure(CurPP
.begin(), CurPP
.end());
155 *CurAttrs
= std::move(CurItemInfo
);
159 Info
.RestoreScreen(NULL
);
160 Info
.RestoreScreen(hScreen
);
162 ArcPlugin
->CloseArchive(ArcPluginNumber
, &CurArcInfo
);
164 if (GetItemCode
!= GETARC_EOF
&& GetItemCode
!= GETARC_SUCCESS
) {
165 switch (GetItemCode
) {
167 GetItemCode
= MBadArchive
;
170 case GETARC_UNEXPEOF
:
171 GetItemCode
= MUnexpEOF
;
174 case GETARC_READERROR
:
175 GetItemCode
= MReadError
;
180 const char *MsgItems
[] = {GetMsg(MError
), NameMsg
, GetMsg(GetItemCode
), GetMsg(MOk
)};
181 FSF
.TruncPathStr(strncpy(NameMsg
, Name
, sizeof(NameMsg
) - 1), MAX_WIDTH_MESSAGE
);
182 Info
.Message(Info
.ModuleNumber
, FMSG_WARNING
, NULL
, MsgItems
, ARRAYSIZE(MsgItems
), 1);
183 return FALSE
; // Mantis#0001241
186 // Info.RestoreScreen(NULL);
187 // Info.RestoreScreen(hScreen);
191 bool PluginClass::EnsureFindDataUpToDate(int OpMode
)
193 if (!ArcData
.empty()) {
194 struct stat NewArcStat
196 if (sdc_stat(ArcName
, &NewArcStat
) == -1)
199 if (ArcStat
.st_mtime
== NewArcStat
.st_mtime
&& ArcStat
.st_size
== NewArcStat
.st_size
)
203 DWORD size
= (DWORD
)Info
.AdvControl(Info
.ModuleNumber
, ACTL_GETPLUGINMAXREADDATA
, (void *)0);
204 int fd
= sdc_open(ArcName
, O_RDONLY
);
208 unsigned char *Data
= (unsigned char *)malloc(size
);
209 ssize_t read_size
= Data
? sdc_read(fd
, Data
, size
) : -1;
212 bool ReadArcOK
= false;
216 ReadArcOK
= (ArcPlugin
->IsArchive(ArcPluginNumber
, ArcName
, Data
, read_size
, &SFXSize
)
217 && ReadArchive(ArcName
, OpMode
));
224 int PluginClass::GetFindData(PluginPanelItem
**pPanelItem
, int *pItemsNumber
, int OpMode
)
230 CurDirPP
.Traverse(CurDir
);
232 if (!EnsureFindDataUpToDate(OpMode
)) {
233 fprintf(stderr
, "MA::GetFindData: can't update at '%s'\n", CurDirPP
.Join().c_str());
237 const auto *DirNode
= ArcData
.Find(CurDirPP
.begin(), CurDirPP
.end());
239 fprintf(stderr
, "MA::GetFindData: no node at '%s'\n", CurDirPP
.Join().c_str());
243 if (DirNode
->empty())
246 PluginPanelItem
*CurrentItem
= *pPanelItem
=
247 (PluginPanelItem
*)calloc(DirNode
->size(), sizeof(PluginPanelItem
));
249 fprintf(stderr
, "MA::GetFindData: can't alloc %lu items at '%s'\n", (unsigned long)DirNode
->size(),
250 CurDirPP
.Join().c_str());
253 *pItemsNumber
= (int)DirNode
->size();
255 for (const auto &it
: *DirNode
) {
256 CurrentItem
->FindData
.ftCreationTime
= it
.second
.ftCreationTime
;
257 CurrentItem
->FindData
.ftLastAccessTime
= it
.second
.ftLastAccessTime
;
258 CurrentItem
->FindData
.ftLastWriteTime
= it
.second
.ftLastWriteTime
;
259 CurrentItem
->FindData
.nPhysicalSize
= it
.second
.nPhysicalSize
;
260 CurrentItem
->FindData
.nFileSize
= it
.second
.nFileSize
;
261 CurrentItem
->FindData
.dwFileAttributes
= it
.second
.dwFileAttributes
;
262 CurrentItem
->FindData
.dwUnixMode
= it
.second
.dwUnixMode
;
263 strncpy(CurrentItem
->FindData
.cFileName
, it
.first
.c_str(),
264 ARRAYSIZE(CurrentItem
->FindData
.cFileName
));
265 CurrentItem
->Flags
= it
.second
.Flags
;
266 CurrentItem
->NumberOfLinks
= it
.second
.NumberOfLinks
;
267 CurrentItem
->CRC32
= it
.second
.CRC32
;
268 CurrentItem
->Description
= it
.second
.Description
? (char *)it
.second
.Description
->c_str() : nullptr;
269 CurrentItem
->UserData
= (DWORD_PTR
)&it
.second
;
271 if (!it
.second
.empty())
272 CurrentItem
->FindData
.dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
273 if (CurrentItem
->FindData
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
274 CurrentItem
->FindData
.nPhysicalSize
= CurrentItem
->FindData
.nFileSize
= 0;
282 void PluginClass::FreeFindData(PluginPanelItem
*PanelItem
, int ItemsNumber
)
288 int PluginClass::SetDirectory(const char *Dir
, int OpMode
)
290 if (*Dir
== '/' && *(++Dir
) == 0) {
296 NewDirPP
.Traverse(CurDir
);
297 NewDirPP
.Traverse(Dir
);
298 const auto &NewDir
= NewDirPP
.Join();
300 auto *DirNode
= ArcData
.Find(NewDirPP
.begin(), NewDirPP
.end());
302 fprintf(stderr
, "MA::SetDirectory('%s', %d): no node for '%s'\n", Dir
, OpMode
, NewDir
.c_str());
306 if (NewDir
.size() >= ARRAYSIZE(CurDir
)) {
307 fprintf(stderr
, "MA::SetDirectory('%s', %d): too long path '%s'\n", Dir
, OpMode
, NewDir
.c_str());
311 strcpy(CurDir
, NewDir
.c_str());
315 bool PluginClass::FarLangChanged()
317 const char *tmplang
= getenv("FARLANG");
322 if (!strcmp(tmplang
, farlang
))
325 ArrayCpyZ(farlang
, tmplang
);
330 static void AppendInfoData(std::string
&Str
, const char *Data
)
337 void PluginClass::SetInfoLineSZ(size_t Index
, int TextID
, const char *Data
)
339 ArrayCpyZ(InfoLines
[Index
].Text
, GetMsg(TextID
));
340 ArrayCpyZ(InfoLines
[Index
].Data
, Data
);
343 void PluginClass::SetInfoLine(size_t Index
, int TextID
, const std::string
&Data
)
345 SetInfoLineSZ(Index
, TextID
, Data
.c_str());
348 void PluginClass::SetInfoLine(size_t Index
, int TextID
, int DataID
)
350 SetInfoLineSZ(Index
, TextID
, GetMsg(DataID
));
353 void PluginClass::GetOpenPluginInfo(struct OpenPluginInfo
*Info
)
355 Info
->StructSize
= sizeof(*Info
);
357 OPIF_USEFILTER
| OPIF_USESORTGROUPS
| OPIF_USEHIGHLIGHTING
| OPIF_ADDDOTS
| OPIF_COMPAREFATTIME
;
358 Info
->HostFile
= ArcName
;
359 Info
->CurDir
= CurDir
;
362 ArcPlugin
->GetFormatName(ArcPluginNumber
, ArcPluginType
, FormatName
, DefExt
);
365 strncpy(NameTitle
, FSF
.PointToName(ArcName
), sizeof(NameTitle
) - 1);
368 struct PanelInfo PInfo
;
369 if (::Info
.Control((HANDLE
)this, FCTL_GETPANELSHORTINFO
, &PInfo
)) { // TruncStr
370 FSF
.TruncPathStr(NameTitle
,
371 (PInfo
.PanelRect
.right
- PInfo
.PanelRect
.left
+ 1 - (strlen(FormatName
) + 3 + 4)));
375 FSF
.snprintf(Title
, ARRAYSIZE(Title
) - 1, " %s:%s%s%s ", FormatName
, NameTitle
, *CurDir
? "/" : "",
376 *CurDir
? CurDir
: "");
378 Info
->PanelTitle
= Title
;
380 if (bGOPIFirstCall
|| FarLangChanged()) {
381 FSF
.snprintf(Format
, ARRAYSIZE(Format
) - 1, GetMsg(MArcFormat
), FormatName
);
384 FSF
.snprintf(InfoLines
[0].Text
, ARRAYSIZE(InfoLines
[0].Text
), GetMsg(MInfoTitle
),
385 FSF
.PointToName(ArcName
));
386 InfoLines
[0].Separator
= TRUE
;
388 std::string TmpInfoData
= FormatName
;
389 if (ItemsInfo
.UnpVer
!= 0)
390 TmpInfoData
+= StrPrintf(" %d.%d", ItemsInfo
.UnpVer
/ 256, ItemsInfo
.UnpVer
% 256);
391 if (ItemsInfo
.HostOS
)
392 TmpInfoData
+= StrPrintf("/%s", ItemsInfo
.HostOS
);
393 SetInfoLine(1, MInfoArchive
, TmpInfoData
);
395 TmpInfoData
= ItemsInfo
.Solid
? GetMsg(MInfoSolid
) : "";
396 if (CurArcInfo
.SFXSize
)
397 AppendInfoData(TmpInfoData
, GetMsg(MInfoSFX
));
398 if (CurArcInfo
.Flags
& AF_HDRENCRYPTED
)
399 AppendInfoData(TmpInfoData
, GetMsg(MInfoHdrEncrypted
));
400 if (CurArcInfo
.Volume
)
401 AppendInfoData(TmpInfoData
, GetMsg(MInfoVolume
));
402 if (TmpInfoData
.empty())
403 TmpInfoData
= GetMsg(MInfoNormal
);
404 SetInfoLine(2, MInfoArcType
, TmpInfoData
);
406 SetInfoLine(3, MInfoArcComment
, CurArcInfo
.Comment
? MInfoPresent
: MInfoAbsent
);
407 SetInfoLine(4, MInfoFileComments
, ItemsInfo
.Comment
? MInfoPresent
: MInfoAbsent
);
408 SetInfoLine(5, MInfoPasswords
, ItemsInfo
.Encrypted
? MInfoPresent
: MInfoAbsent
);
409 SetInfoLine(6, MInfoRecovery
, CurArcInfo
.Recovery
? MInfoPresent
: MInfoAbsent
);
410 SetInfoLine(7, MInfoLock
, CurArcInfo
.Lock
? MInfoPresent
: MInfoAbsent
);
411 SetInfoLine(8, MInfoAuthVer
, (CurArcInfo
.Flags
& AF_AVPRESENT
) ? MInfoPresent
: MInfoAbsent
);
413 if (ItemsInfo
.DictSize
)
414 SetInfoLine(9, MInfoDict
, StrPrintf("%d %s", ItemsInfo
.DictSize
, GetMsg(MInfoDictKb
)));
416 SetInfoLine(9, MInfoDict
, MInfoAbsent
);
418 if (CurArcInfo
.Chapters
)
419 SetInfoLine(10, MInfoChapters
, std::to_string(CurArcInfo
.Chapters
));
421 SetInfoLine(10, MInfoChapters
, MInfoAbsent
);
423 SetInfoLine(11, MInfoTotalFiles
, std::to_string(ArcDataCount
));
424 SetInfoLine(12, MInfoTotalSize
, NumberWithCommas(TotalSize
));
425 SetInfoLine(13, MInfoPackedSize
, NumberWithCommas(PackedSize
));
426 SetInfoLine(14, MInfoRatio
, StrPrintf("%d%%", MA_ToPercent(PackedSize
, TotalSize
)));
429 KeyBar
.ShiftTitles
[1 - 1] = (char *)"";
430 KeyBar
.AltTitles
[6 - 1] = (char *)GetMsg(MAltF6
);
431 KeyBar
.AltShiftTitles
[9 - 1] = (char *)GetMsg(MAltShiftF9
);
434 Info
->Format
= Format
;
435 Info
->KeyBar
= &KeyBar
;
436 Info
->InfoLines
= InfoLines
;
437 Info
->InfoLinesNumber
= ARRAYSIZE(InfoLines
);
439 ArrayCpyZ(DescrFilesString
, Opt
.DescriptionNames
.c_str());
441 size_t DescrFilesNumber
= 0;
442 char *NamePtr
= DescrFilesString
;
444 while (DescrFilesNumber
< ARRAYSIZE(DescrFiles
)) {
445 while (__isspace(*NamePtr
))
449 DescrFiles
[DescrFilesNumber
++] = NamePtr
;
450 if ((NamePtr
= strchr(NamePtr
, ',')) == NULL
)
455 Info
->DescrFiles
= DescrFiles
;
457 if (!Opt
.ReadDescriptions
|| DizPresent
)
458 Info
->DescrFilesNumber
= 0;
460 Info
->DescrFilesNumber
= (int)DescrFilesNumber
;
462 bGOPIFirstCall
= false;