2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * FILE: base/applications/rapps/available.cpp
5 * PURPOSE: Classes for working with available applications
6 * COPYRIGHT: Copyright 2009 Dmitry Chapyshev (dmitry@reactos.org)
7 * Copyright 2015 Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
8 * Copyright 2017 Alexander Shaposhnikov (chaez.san@gmail.com)
12 #include "available.h"
17 #include <atlsimpcoll.h>
20 // CAvailableApplicationInfo
21 CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW
& sFileNameParam
)
22 : m_Parser(sFileNameParam
)
24 m_LicenseType
= LicenseType::LICENSE_NONE
;
26 m_sFileName
= sFileNameParam
;
28 RetrieveGeneralInfo();
31 VOID
CAvailableApplicationInfo::RefreshAppInfo()
33 if (m_szUrlDownload
.IsEmpty())
35 RetrieveGeneralInfo();
39 // Lazily load general info from the file
40 VOID
CAvailableApplicationInfo::RetrieveGeneralInfo()
42 m_Category
= m_Parser
.GetInt(L
"Category");
44 if (!GetString(L
"Name", m_szName
)
45 || !GetString(L
"URLDownload", m_szUrlDownload
))
50 GetString(L
"RegName", m_szRegName
);
51 GetString(L
"Version", m_szVersion
);
52 GetString(L
"License", m_szLicense
);
53 GetString(L
"Description", m_szDesc
);
54 GetString(L
"Size", m_szSize
);
55 GetString(L
"URLSite", m_szUrlSite
);
56 GetString(L
"CDPath", m_szCDPath
);
57 GetString(L
"Language", m_szRegName
);
58 GetString(L
"SHA1", m_szSHA1
);
60 RetrieveLicenseType();
62 RetrieveInstalledStatus();
65 RetrieveInstalledVersion();
69 VOID
CAvailableApplicationInfo::RetrieveInstalledStatus()
71 m_IsInstalled
= ::GetInstalledVersion(NULL
, m_szRegName
)
72 || ::GetInstalledVersion(NULL
, m_szName
);
75 VOID
CAvailableApplicationInfo::RetrieveInstalledVersion()
77 ATL::CStringW szNameVersion
= m_szName
+ L
" " + m_szVersion
;
78 m_HasInstalledVersion
= ::GetInstalledVersion(&m_szInstalledVersion
, m_szRegName
)
79 || ::GetInstalledVersion(&m_szInstalledVersion
, m_szName
)
80 || ::GetInstalledVersion(&m_szInstalledVersion
, szNameVersion
);
83 VOID
CAvailableApplicationInfo::RetrieveLanguages()
85 const WCHAR cDelimiter
= L
'|';
86 ATL::CStringW szBuffer
;
88 // TODO: Get multiline parameter
89 if (!m_Parser
.GetString(L
"Languages", szBuffer
))
91 m_HasLanguageInfo
= FALSE
;
95 // Parse parameter string
96 ATL::CStringW m_szLocale
;
98 for (INT i
= 0; szBuffer
[i
] != UNICODE_NULL
; ++i
)
100 if (szBuffer
[i
] != cDelimiter
&& szBuffer
[i
] != L
'\n')
102 m_szLocale
+= szBuffer
[i
];
106 if (StrToIntExW(m_szLocale
.GetString(), STIF_DEFAULT
, &iLCID
))
108 m_LanguageLCIDs
.Add(static_cast<LCID
>(iLCID
));
114 // For the text after delimiter
115 if (!m_szLocale
.IsEmpty())
117 if (StrToIntExW(m_szLocale
.GetString(), STIF_DEFAULT
, &iLCID
))
119 m_LanguageLCIDs
.Add(static_cast<LCID
>(iLCID
));
123 m_HasLanguageInfo
= TRUE
;
126 VOID
CAvailableApplicationInfo::RetrieveLicenseType()
128 INT IntBuffer
= m_Parser
.GetInt(L
"LicenseType");
130 if (IsLicenseType(IntBuffer
))
132 m_LicenseType
= static_cast<LicenseType
>(IntBuffer
);
136 m_LicenseType
= LicenseType::LICENSE_NONE
;
140 BOOL
CAvailableApplicationInfo::FindInLanguages(LCID what
) const
142 if (!m_HasLanguageInfo
)
147 //Find locale code in the list
148 const INT nLanguagesSize
= m_LanguageLCIDs
.GetSize();
149 for (INT i
= 0; i
< nLanguagesSize
; ++i
)
151 if (m_LanguageLCIDs
[i
] == what
)
160 BOOL
CAvailableApplicationInfo::HasLanguageInfo() const
162 return m_HasLanguageInfo
;
165 BOOL
CAvailableApplicationInfo::HasNativeLanguage() const
167 return FindInLanguages(GetUserDefaultLCID());
170 BOOL
CAvailableApplicationInfo::HasEnglishLanguage() const
172 return FindInLanguages(MAKELCID(MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
), SORT_DEFAULT
));
175 BOOL
CAvailableApplicationInfo::IsInstalled() const
177 return m_IsInstalled
;
180 BOOL
CAvailableApplicationInfo::HasInstalledVersion() const
182 return m_HasInstalledVersion
;
185 BOOL
CAvailableApplicationInfo::HasUpdate() const
187 return (m_szInstalledVersion
.Compare(m_szVersion
) < 0) ? TRUE
: FALSE
;
190 VOID
CAvailableApplicationInfo::SetLastWriteTime(FILETIME
* ftTime
)
192 RtlCopyMemory(&m_ftCacheStamp
, ftTime
, sizeof(FILETIME
));
195 inline BOOL
CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName
, ATL::CStringW
& ReturnedString
)
197 if (!m_Parser
.GetString(lpKeyName
, ReturnedString
))
199 ReturnedString
.Empty();
204 // CAvailableApplicationInfo
207 ATL::CStringW
CAvailableApps::m_szPath
;
208 ATL::CStringW
CAvailableApps::m_szCabPath
;
209 ATL::CStringW
CAvailableApps::m_szAppsPath
;
210 ATL::CStringW
CAvailableApps::m_szSearchPath
;
212 BOOL
CAvailableApps::InitializeStaticStrings()
215 if (!m_szPath
.IsEmpty())
217 // strings are filled
221 //FIXME: maybe provide a fallback?
222 if (GetStorageDirectory(m_szPath
))
224 m_szAppsPath
= m_szPath
+ L
"\\rapps\\";
225 m_szCabPath
= m_szPath
+ L
"\\rappmgr.cab";
226 m_szSearchPath
= m_szAppsPath
+ L
"*.txt";
233 CAvailableApps::CAvailableApps()
236 InitializeStaticStrings();
239 VOID
CAvailableApps::FreeCachedEntries()
241 POSITION InfoListPosition
= m_InfoList
.GetHeadPosition();
243 /* loop and deallocate all the cached app infos in the list */
244 while (InfoListPosition
)
246 CAvailableApplicationInfo
* Info
= m_InfoList
.GetNext(InfoListPosition
);
250 m_InfoList
.RemoveAll();
253 VOID
CAvailableApps::DeleteCurrentAppsDB()
255 HANDLE hFind
= INVALID_HANDLE_VALUE
;
256 WIN32_FIND_DATAW FindFileData
;
258 if (!InitializeStaticStrings())
263 hFind
= FindFirstFileW(m_szSearchPath
.GetString(), &FindFileData
);
265 if (hFind
!= INVALID_HANDLE_VALUE
)
270 szTmp
= m_szAppsPath
+ FindFileData
.cFileName
;
271 DeleteFileW(szTmp
.GetString());
272 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
276 RemoveDirectoryW(m_szAppsPath
);
277 RemoveDirectoryW(m_szPath
);
280 BOOL
CAvailableApps::UpdateAppsDB()
282 HANDLE hFind
= INVALID_HANDLE_VALUE
;
283 WIN32_FIND_DATAW FindFileData
;
285 if (!InitializeStaticStrings())
290 if (!CreateDirectoryW(m_szPath
.GetString(), NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
295 //if there are some files in the db folder - we're good
296 hFind
= FindFirstFileW(m_szSearchPath
.GetString(), &FindFileData
);
297 if (hFind
!= INVALID_HANDLE_VALUE
)
302 CDownloadManager::DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
304 if (!ExtractFilesFromCab(m_szCabPath
, m_szAppsPath
))
309 DeleteFileW(m_szCabPath
.GetString());
314 BOOL
CAvailableApps::ForceUpdateAppsDB()
316 DeleteCurrentAppsDB();
317 return UpdateAppsDB();
320 BOOL
CAvailableApps::Enum(INT EnumType
, AVAILENUMPROC lpEnumProc
)
323 HANDLE hFind
= INVALID_HANDLE_VALUE
;
324 WIN32_FIND_DATAW FindFileData
;
326 hFind
= FindFirstFileW(m_szSearchPath
.GetString(), &FindFileData
);
328 if (hFind
== INVALID_HANDLE_VALUE
)
336 // loop for all the cached entries
337 POSITION CurrentListPosition
= m_InfoList
.GetHeadPosition();
338 CAvailableApplicationInfo
* Info
= NULL
;
340 while (CurrentListPosition
!= NULL
)
342 POSITION LastListPosition
= CurrentListPosition
;
343 Info
= m_InfoList
.GetNext(CurrentListPosition
);
345 // do we already have this entry in cache?
346 if (Info
->m_sFileName
== FindFileData
.cFileName
)
348 // is it current enough, or the file has been modified since our last time here?
349 if (CompareFileTime(&FindFileData
.ftLastWriteTime
, &Info
->m_ftCacheStamp
) == 1)
351 // recreate our cache, this is the slow path
352 m_InfoList
.RemoveAt(LastListPosition
);
360 // speedy path, compare directly, we already have the data
366 // create a new entry
367 Info
= new CAvailableApplicationInfo(FindFileData
.cFileName
);
369 // set a timestamp for the next time
370 Info
->SetLastWriteTime(&FindFileData
.ftLastWriteTime
);
371 m_InfoList
.AddTail(Info
);
374 if (Info
->m_Category
== FALSE
)
377 if (EnumType
!= Info
->m_Category
&& EnumType
!= ENUM_ALL_AVAILABLE
)
380 Info
->RefreshAppInfo();
383 lpEnumProc(static_cast<CAvailableApplicationInfo
*>(Info
), m_szAppsPath
.GetString());
385 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
391 CAvailableApplicationInfo
* CAvailableApps::FindInfo(const ATL::CStringW
& szAppName
) const
393 if (m_InfoList
.IsEmpty())
399 POSITION CurrentListPosition
= m_InfoList
.GetHeadPosition();
400 CAvailableApplicationInfo
* info
;
401 while (CurrentListPosition
!= NULL
)
403 info
= m_InfoList
.GetNext(CurrentListPosition
);
404 if (info
->m_szName
== szAppName
)
412 ATL::CSimpleArray
<CAvailableApplicationInfo
*> CAvailableApps::FindInfoList(const ATL::CSimpleArray
<ATL::CStringW
> &arrAppsNames
) const
414 ATL::CSimpleArray
<CAvailableApplicationInfo
*> result
;
415 for (INT i
= 0; i
< arrAppsNames
.GetSize(); ++i
)
417 CAvailableApplicationInfo
* Info
= FindInfo(arrAppsNames
[i
]);
426 const ATL::CStringW
& CAvailableApps::GetFolderPath() const
431 const ATL::CStringW
& CAvailableApps::GetAppPath() const
436 const ATL::CStringW
& CAvailableApps::GetCabPath() const
441 LPCWSTR
CAvailableApps::GetFolderPathString() const
443 return m_szPath
.GetString();
446 LPCWSTR
CAvailableApps::GetAppPathString() const
448 return m_szPath
.GetString();
451 LPCWSTR
CAvailableApps::GetCabPathString() const
453 return m_szPath
.GetString();