2 * PROJECT: ReactOS Applications Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/rapps/available.cpp
5 * PURPOSE: Classes for working with available applications
6 * PROGRAMMERS: Dmitry Chapyshev (dmitry@reactos.org)
7 * Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
8 * Alexander Shaposhnikov (chaez.san@gmail.com)
13 // CAvailableApplicationInfo
15 CAvailableApplicationInfo::CAvailableApplicationInfo(const ATL::CStringW
& sFileNameParam
)
16 : m_Parser(sFileNameParam
)
18 LicenseType
= LICENSE_TYPE::None
;
19 sFileName
= sFileNameParam
;
21 RetrieveGeneralInfo();
24 VOID
CAvailableApplicationInfo::RefreshAppInfo()
26 if (szUrlDownload
.IsEmpty())
28 RetrieveGeneralInfo();
32 VOID
CAvailableApplicationInfo::RetrieveGeneralInfo()
34 Category
= m_Parser
.GetInt(L
"Category");
36 if (!GetString(L
"Name", szName
)
37 || !GetString(L
"URLDownload", szUrlDownload
))
42 GetString(L
"RegName", szRegName
);
43 GetString(L
"Version", szVersion
);
44 GetString(L
"License", szLicense
);
45 GetString(L
"Description", szDesc
);
46 GetString(L
"Size", szSize
);
47 GetString(L
"URLSite", szUrlSite
);
48 GetString(L
"CDPath", szCDPath
);
49 GetString(L
"Language", szRegName
);
50 GetString(L
"SHA1", szSHA1
);
52 RetrieveLicenseType();
54 RetrieveInstalledStatus();
57 RetrieveInstalledVersion();
61 VOID
CAvailableApplicationInfo::RetrieveInstalledStatus()
63 m_IsInstalled
= ::GetInstalledVersion(NULL
, szRegName
)
64 || ::GetInstalledVersion(NULL
, szName
);
67 VOID
CAvailableApplicationInfo::RetrieveInstalledVersion()
69 m_HasInstalledVersion
= ::GetInstalledVersion(&szInstalledVersion
, szRegName
)
70 || ::GetInstalledVersion(&szInstalledVersion
, szName
);
73 VOID
CAvailableApplicationInfo::RetrieveLanguages()
75 const WCHAR cDelimiter
= L
'|';
76 ATL::CStringW szBuffer
;
78 // TODO: Get multiline parameter
79 if (!m_Parser
.GetString(L
"Languages", szBuffer
))
81 m_HasLanguageInfo
= FALSE
;
85 // Parse parameter string
86 ATL::CStringW m_szLocale
;
87 for (INT i
= 0; szBuffer
[i
] != UNICODE_NULL
; ++i
)
89 if (szBuffer
[i
] != cDelimiter
)
91 m_szLocale
+= szBuffer
[i
];
95 Languages
.Add(m_szLocale
);
100 // For the text after delimiter
101 if (!m_szLocale
.IsEmpty())
103 Languages
.Add(m_szLocale
);
106 m_HasLanguageInfo
= TRUE
;
109 VOID
CAvailableApplicationInfo::RetrieveLicenseType()
111 INT IntBuffer
= m_Parser
.GetInt(L
"LicenseType");
113 if (IntBuffer
< 0 || IntBuffer
> LICENSE_TYPE::Max
)
115 LicenseType
= LICENSE_TYPE::None
;
119 LicenseType
= (LICENSE_TYPE
) IntBuffer
;
123 BOOL
CAvailableApplicationInfo::HasLanguageInfo() const
125 return m_HasLanguageInfo
;
128 BOOL
CAvailableApplicationInfo::HasNativeLanguage() const
130 if (!m_HasLanguageInfo
)
135 //Find locale code in the list
136 const INT nLanguagesSize
= Languages
.GetSize();
137 for (INT i
= 0; i
< nLanguagesSize
; ++i
)
139 if (Languages
[i
] == CConfigParser::GetLocale())
148 BOOL
CAvailableApplicationInfo::HasEnglishLanguage() const
150 static ATL::CStringW szEnglishLocaleID
;
151 const INT cchLocaleSize
= m_Parser
.GetLocaleSize();
152 if (!m_HasLanguageInfo
)
157 //Get English locale code
158 if (szEnglishLocaleID
.IsEmpty())
160 INT result
= GetLocaleInfoW(MAKELCID(LANG_ENGLISH
, SORT_DEFAULT
), LOCALE_ILANGUAGE
,
161 szEnglishLocaleID
.GetBuffer(cchLocaleSize
), cchLocaleSize
);
162 szEnglishLocaleID
.ReleaseBuffer();
163 if (result
!= ERROR_SUCCESS
)
170 //Find locale code in the list
171 const INT nLanguagesSize
= Languages
.GetSize();
172 for (INT i
= 0; i
< nLanguagesSize
; ++i
)
174 if (Languages
[i
] == szEnglishLocaleID
)
183 BOOL
CAvailableApplicationInfo::IsInstalled() const
185 return m_IsInstalled
;
188 BOOL
CAvailableApplicationInfo::HasInstalledVersion() const
190 return m_HasInstalledVersion
;
193 BOOL
CAvailableApplicationInfo::HasUpdate() const
195 return (szInstalledVersion
.Compare(szVersion
) < 0) ? TRUE
: FALSE
;
198 VOID
CAvailableApplicationInfo::SetLastWriteTime(FILETIME
* ftTime
)
200 RtlCopyMemory(&ftCacheStamp
, ftTime
, sizeof(FILETIME
));
203 inline BOOL
CAvailableApplicationInfo::GetString(LPCWSTR lpKeyName
, ATL::CStringW
& ReturnedString
)
205 if (!m_Parser
.GetString(lpKeyName
, ReturnedString
))
207 ReturnedString
.Empty();
212 // CAvailableApplicationInfo
215 CAvailableApps::CAvailableApps()
218 if (GetStorageDirectory(m_szPath
))
220 m_szAppsPath
= m_szPath
+ L
"\\rapps\\";
221 m_szCabPath
= m_szPath
+ L
"\\rappmgr.cab";
222 m_szSearchPath
= m_szAppsPath
+ L
"*.txt";
226 VOID
CAvailableApps::FreeCachedEntries()
228 POSITION InfoListPosition
= m_InfoList
.GetHeadPosition();
230 /* loop and deallocate all the cached app infos in the list */
231 while (InfoListPosition
)
233 CAvailableApplicationInfo
* Info
= m_InfoList
.GetAt(InfoListPosition
);
234 m_InfoList
.RemoveHead();
237 InfoListPosition
= m_InfoList
.GetHeadPosition();
241 BOOL
CAvailableApps::DeleteCurrentAppsDB()
243 HANDLE hFind
= INVALID_HANDLE_VALUE
;
244 WIN32_FIND_DATAW FindFileData
;
247 if (m_szPath
.IsEmpty())
250 result
= result
&& DeleteFileW(m_szCabPath
.GetString());
251 hFind
= FindFirstFileW(m_szSearchPath
.GetString(), &FindFileData
);
253 if (hFind
== INVALID_HANDLE_VALUE
)
259 szTmp
= m_szPath
+ FindFileData
.cFileName
;
260 result
= result
&& DeleteFileW(szTmp
.GetString());
261 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
268 BOOL
CAvailableApps::UpdateAppsDB()
270 if (!DeleteCurrentAppsDB())
273 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
275 if (m_szPath
.IsEmpty())
278 if (!ExtractFilesFromCab(m_szCabPath
, m_szAppsPath
))
286 BOOL
CAvailableApps::EnumAvailableApplications(INT EnumType
, AVAILENUMPROC lpEnumProc
)
288 HANDLE hFind
= INVALID_HANDLE_VALUE
;
289 WIN32_FIND_DATAW FindFileData
;
291 if (!CreateDirectoryW(m_szPath
.GetString(), NULL
) &&
292 GetLastError() != ERROR_ALREADY_EXISTS
)
297 hFind
= FindFirstFileW(m_szSearchPath
.GetString(), &FindFileData
);
299 if (hFind
== INVALID_HANDLE_VALUE
)
301 if (GetFileAttributesW(m_szCabPath
) == INVALID_FILE_ATTRIBUTES
)
302 DownloadApplicationsDB(APPLICATION_DATABASE_URL
);
304 ExtractFilesFromCab(m_szCabPath
, m_szAppsPath
);
305 hFind
= FindFirstFileW(m_szSearchPath
.GetString(), &FindFileData
);
307 if (hFind
== INVALID_HANDLE_VALUE
)
313 // loop for all the cached entries
314 POSITION CurrentListPosition
= m_InfoList
.GetHeadPosition();
315 CAvailableApplicationInfo
* Info
= NULL
;
317 while (CurrentListPosition
!= NULL
)
319 POSITION LastListPosition
= CurrentListPosition
;
320 Info
= m_InfoList
.GetNext(CurrentListPosition
);
322 // do we already have this entry in cache?
323 if (Info
->sFileName
== FindFileData
.cFileName
)
325 // is it current enough, or the file has been modified since our last time here?
326 if (CompareFileTime(&FindFileData
.ftLastWriteTime
, &Info
->ftCacheStamp
) == 1)
328 // recreate our cache, this is the slow path
329 m_InfoList
.RemoveAt(LastListPosition
);
337 // speedy path, compare directly, we already have the data
343 // create a new entry
344 Info
= new CAvailableApplicationInfo(FindFileData
.cFileName
);
346 // set a timestamp for the next time
347 Info
->SetLastWriteTime(&FindFileData
.ftLastWriteTime
);
348 m_InfoList
.AddTail(Info
);
351 if (Info
->Category
== FALSE
)
354 if (EnumType
!= Info
->Category
&& EnumType
!= ENUM_ALL_AVAILABLE
)
357 Info
->RefreshAppInfo();
359 if (!lpEnumProc(static_cast<PAPPLICATION_INFO
>(Info
), m_szAppsPath
.GetString()))
362 } while (FindNextFileW(hFind
, &FindFileData
) != 0);
368 const ATL::CStringW
& CAvailableApps::GetFolderPath()
373 const ATL::CStringW
& CAvailableApps::GetAppPath()
378 const ATL::CStringW
& CAvailableApps::GetCabPath()
383 const LPCWSTR
CAvailableApps::GetFolderPathString()
385 return m_szPath
.GetString();
388 const LPCWSTR
CAvailableApps::GetAppPathString()
390 return m_szPath
.GetString();
393 const LPCWSTR
CAvailableApps::GetCabPathString()
395 return m_szPath
.GetString();
400 ATL::CStringW
CConfigParser::m_szLocale
;
401 ATL::CStringW
CConfigParser::m_szCachedINISectionLocale
;
402 ATL::CStringW
CConfigParser::m_szCachedINISectionLocaleNeutral
;
404 CConfigParser::CConfigParser(const ATL::CStringW
& FileName
) : szConfigPath(GetINIFullPath(FileName
))
406 // we don't have cached section strings for the current system language, create them, lazy
407 CacheINILocaleLazy();
410 ATL::CStringW
CConfigParser::GetINIFullPath(const ATL::CStringW
& FileName
)
413 static ATL::CStringW szBuffer
;
415 GetStorageDirectory(szDir
);
416 szBuffer
.Format(L
"%ls\\rapps\\%ls", szDir
, FileName
);
421 VOID
CConfigParser::CacheINILocaleLazy()
423 if (m_szLocale
.IsEmpty())
425 // TODO: Set default locale if call fails
426 // find out what is the current system lang code (e.g. "0a") and append it to SectionLocale
427 GetLocaleInfoW(LOCALE_USER_DEFAULT
, LOCALE_ILANGUAGE
,
428 m_szLocale
.GetBuffer(m_cchLocaleSize
), m_cchLocaleSize
);
429 m_szLocale
.ReleaseBuffer();
430 m_szCachedINISectionLocale
= L
"Section." + m_szLocale
;
432 // turn "Section.0c0a" into "Section.0a", keeping just the neutral lang part
433 m_szCachedINISectionLocaleNeutral
= m_szCachedINISectionLocale
+ m_szLocale
.Right(2);
437 const ATL::CStringW
& CConfigParser::GetLocale()
439 CacheINILocaleLazy();
443 INT
CConfigParser::GetLocaleSize()
445 return m_cchLocaleSize
;
448 UINT
CConfigParser::GetString(const ATL::CStringW
& KeyName
, ATL::CStringW
& ResultString
)
452 LPWSTR ResultStringBuffer
= ResultString
.GetBuffer(MAX_PATH
);
453 // 1st - find localized strings (e.g. "Section.0c0a")
454 dwResult
= GetPrivateProfileStringW(m_szCachedINISectionLocale
.GetString(),
459 szConfigPath
.GetString());
463 // 2nd - if they weren't present check for neutral sub-langs/ generic translations (e.g. "Section.0a")
464 dwResult
= GetPrivateProfileStringW(m_szCachedINISectionLocaleNeutral
.GetString(),
469 szConfigPath
.GetString());
472 // 3rd - if they weren't present fallback to standard english strings (just "Section")
473 dwResult
= GetPrivateProfileStringW(L
"Section",
478 szConfigPath
.GetString());
482 ResultString
.ReleaseBuffer();
483 return (dwResult
!= 0 ? TRUE
: FALSE
);
486 UINT
CConfigParser::GetInt(const ATL::CStringW
& KeyName
)
488 ATL::CStringW Buffer
;
489 UNICODE_STRING BufferW
;
492 // grab the text version of our entry
493 if (!GetString(KeyName
, Buffer
))
496 if (Buffer
.IsEmpty())
499 // convert it to an actual integer
500 RtlInitUnicodeString(&BufferW
, Buffer
.GetString());
501 RtlUnicodeStringToInteger(&BufferW
, 0, &Result
);
503 return (UINT
) Result
;