[RAPPS] unuglify icons. CORE-10642
[reactos.git] / reactos / base / applications / rapps / available.c
index ec43a8b..421eacd 100644 (file)
@@ -3,11 +3,31 @@
  * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            base/applications/rapps/available.c
  * PURPOSE:         Functions for working with availabled applications
- * PROGRAMMERS:     Dmitry Chapyshev (dmitry@reactos.org)
+ * PROGRAMMERS:     Dmitry Chapyshev           (dmitry@reactos.org)
+ *                  Ismael Ferreras Morezuelas (swyterzone+ros@gmail.com)
  */
 
 #include "rapps.h"
 
+#define ADD_TEXT(a, b, c, d) \
+    if (b[0] != '\0') \
+    { \
+        LoadStringW(hInst, a, szText, _countof(szText)); \
+        InsertRichEditText(szText, c); \
+        InsertRichEditText(b, d); \
+    } \
+
+#define GET_STRING1(a, b)  \
+    if (!ParserGetString(a, b, MAX_PATH, FindFileData.cFileName)) \
+        continue;
+
+#define GET_STRING2(a, b)  \
+    if (!ParserGetString(a, b, MAX_PATH, FindFileData.cFileName)) \
+        b[0] = '\0';
+
+LIST_ENTRY CachedEntriesHead = { &CachedEntriesHead, &CachedEntriesHead };
+PLIST_ENTRY pCachedEntry = &CachedEntriesHead;
+
 BOOL
 ShowAvailableAppInfo(INT Index)
 {
@@ -20,19 +40,11 @@ ShowAvailableAppInfo(INT Index)
 
     InsertRichEditText(L"\n", 0);
 
-#define ADD_TEXT(a, b, c, d) \
-    if (b[0] != '\0') \
-    { \
-        LoadStringW(hInst, a, szText, sizeof(szText) / sizeof(WCHAR)); \
-        InsertRichEditText(szText, c); \
-        InsertRichEditText(b, d); \
-    } \
-
-    ADD_TEXT(IDS_AINFO_VERSION, Info->szVersion, CFE_BOLD, 0);
-    ADD_TEXT(IDS_AINFO_LICENCE, Info->szLicence, CFE_BOLD, 0);
-    ADD_TEXT(IDS_AINFO_SIZE, Info->szSize, CFE_BOLD, 0);
-    ADD_TEXT(IDS_AINFO_URLSITE, Info->szUrlSite, CFE_BOLD, CFE_LINK);
-    ADD_TEXT(IDS_AINFO_DESCRIPTION, Info->szDesc, CFE_BOLD, 0);
+    ADD_TEXT(IDS_AINFO_VERSION,     Info->szVersion, CFE_BOLD, 0);
+    ADD_TEXT(IDS_AINFO_LICENSE,     Info->szLicense, CFE_BOLD, 0);
+    ADD_TEXT(IDS_AINFO_SIZE,        Info->szSize,    CFE_BOLD, 0);
+    ADD_TEXT(IDS_AINFO_URLSITE,     Info->szUrlSite, CFE_BOLD, CFE_LINK);
+    ADD_TEXT(IDS_AINFO_DESCRIPTION, Info->szDesc,    CFE_BOLD, 0);
 
     return TRUE;
 }
@@ -46,39 +58,50 @@ DeleteCurrentAppsDB(VOID)
     WCHAR szSearchPath[MAX_PATH];
     WCHAR szPath[MAX_PATH];
     WCHAR szTmp[MAX_PATH];
+    HRESULT hr;
+    BOOL result = TRUE;
 
-    if (!GetCurrentDirectoryW(MAX_PATH, szPath))
+    if (!GetStorageDirectory(szPath, _countof(szPath)))
         return FALSE;
 
-    swprintf(szCabPath, L"%s\\rappmgr.cab", szPath);
+    hr = StringCbPrintfW(szCabPath, sizeof(szCabPath),
+                         L"%ls\\rappmgr.cab",
+                         szPath);
+    if (FAILED(hr))
+        return FALSE;
 
-    if (GetFileAttributesW(szCabPath) != INVALID_FILE_ATTRIBUTES)
-    {
-        if (!DeleteFileW(szCabPath))
-            return FALSE;
-    }
+    result = result && DeleteFileW(szCabPath);
 
-    wcscat(szPath, L"\\rapps\\");
-    swprintf(szSearchPath, L"%s*.txt", szPath);
+    hr = StringCbCatW(szPath, sizeof(szPath), L"\\rapps\\");
+
+    if (FAILED(hr))
+        return FALSE;
+
+    hr = StringCbPrintfW(szSearchPath, sizeof(szSearchPath),
+                         L"%ls*.txt",
+                         szPath);
+    if (FAILED(hr))
+        return FALSE;
 
     hFind = FindFirstFileW(szSearchPath, &FindFileData);
+
     if (hFind == INVALID_HANDLE_VALUE)
-        return TRUE;
+        return result;
 
     do
     {
-        swprintf(szTmp, L"%s%s", szPath, FindFileData.cFileName);
-        if (!DeleteFileW(szTmp))
-        {
-            FindClose(hFind);
-            return FALSE;
-        }
-    }
-    while (FindNextFileW(hFind, &FindFileData) != 0);
+        hr = StringCbPrintfW(szTmp, sizeof(szTmp),
+                             L"%ls%ls",
+                             szPath, FindFileData.cFileName);
+        if (FAILED(hr))
+            continue;
+        result = result && DeleteFileW(szTmp);
+
+    while (FindNextFileW(hFind, &FindFileData) != 0);
 
     FindClose(hFind);
 
-    return TRUE;
+    return result;
 }
 
 
@@ -92,15 +115,24 @@ UpdateAppsDB(VOID)
     if (!DeleteCurrentAppsDB())
         return FALSE;
 
-    DownloadApplicationsDB(APPLICATION_DATEBASE_URL);
+    DownloadApplicationsDB(APPLICATION_DATABASE_URL);
 
-    if (!GetCurrentDirectoryW(MAX_PATH, szPath))
+    if (!GetStorageDirectory(szPath, _countof(szPath)))
         return FALSE;
 
-    swprintf(szCabPath, L"%s\\rappmgr.cab", szPath);
+    if (FAILED(StringCbPrintfW(szCabPath, sizeof(szCabPath),
+                               L"%ls\\rappmgr.cab",
+                               szPath)))
+    {
+        return FALSE;
+    }
 
-    wcscat(szPath, L"\\rapps\\");
-    wcscpy(szAppsPath, szPath);
+    if (FAILED(StringCbPrintfW(szAppsPath, sizeof(szAppsPath),
+                               L"%ls\\rapps\\",
+                               szPath)))
+    {
+        return FALSE;
+    }
 
     ExtractFilesFromCab(szCabPath, szAppsPath);
 
@@ -115,20 +147,28 @@ EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnumProc)
     WIN32_FIND_DATAW FindFileData;
     WCHAR szPath[MAX_PATH];
     WCHAR szAppsPath[MAX_PATH];
-    WCHAR szSectionLocale[MAX_PATH] = L"Section.";
     WCHAR szCabPath[MAX_PATH];
-    WCHAR szLocale[4 + 1];
-    APPLICATION_INFO Info;
+    PAPPLICATION_INFO Info;
+    HRESULT hr;
 
-    if (!GetCurrentDirectoryW(MAX_PATH, szPath))
-    {
+    if (!GetStorageDirectory(szPath, _countof(szPath)))
+        return FALSE;
+
+    hr = StringCbPrintfW(szCabPath, sizeof(szCabPath),
+                         L"%ls\\rappmgr.cab",
+                         szPath);
+    if (FAILED(hr))
         return FALSE;
-    }
 
-    swprintf(szCabPath, L"%s\\rappmgr.cab", szPath);
+    hr = StringCbCatW(szPath, sizeof(szPath), L"\\rapps\\");
+
+    if (FAILED(hr))
+        return FALSE;
 
-    wcscat(szPath, L"\\rapps\\");
-    wcscpy(szAppsPath, szPath);
+    hr = StringCbCopyW(szAppsPath, sizeof(szAppsPath), szPath);
+
+    if (FAILED(hr))
+        return FALSE;
 
     if (!CreateDirectory(szPath, NULL) &&
         GetLastError() != ERROR_ALREADY_EXISTS)
@@ -136,61 +176,117 @@ EnumAvailableApplications(INT EnumType, AVAILENUMPROC lpEnumProc)
         return FALSE;
     }
 
-    GetLocaleInfoW(GetUserDefaultLCID(), LOCALE_ILANGUAGE, szLocale, sizeof(szLocale) / sizeof(WCHAR));
-    wcscat(szSectionLocale, szLocale);
+    hr = StringCbCatW(szPath, sizeof(szPath), L"*.txt");
 
-    wcscat(szPath, L"*.txt");
+    if (FAILED(hr))
+        return FALSE;
 
     hFind = FindFirstFileW(szPath, &FindFileData);
+
     if (hFind == INVALID_HANDLE_VALUE)
     {
         if (GetFileAttributesW(szCabPath) == INVALID_FILE_ATTRIBUTES)
-            DownloadApplicationsDB(APPLICATION_DATEBASE_URL);
+            DownloadApplicationsDB(APPLICATION_DATABASE_URL);
 
         ExtractFilesFromCab(szCabPath, szAppsPath);
         hFind = FindFirstFileW(szPath, &FindFileData);
+
         if (hFind == INVALID_HANDLE_VALUE)
             return FALSE;
     }
 
-#define GET_STRING1(a, b)  \
-    if (!ParserGetString(szSectionLocale, a, b, MAX_PATH, FindFileData.cFileName)) \
-        if (!ParserGetString(L"Section", a, b, MAX_PATH, FindFileData.cFileName)) \
-            continue;
-
-#define GET_STRING2(a, b)  \
-    if (!ParserGetString(szSectionLocale, a, b, MAX_PATH, FindFileData.cFileName)) \
-        if (!ParserGetString(L"Section", a, b, MAX_PATH, FindFileData.cFileName)) \
-            b[0] = '\0';
-
     do
     {
-        Info.Category = ParserGetInt(szSectionLocale, L"Category", FindFileData.cFileName);
-        if (Info.Category == -1)
+        /* loop for all the cached entries */
+        for (pCachedEntry = CachedEntriesHead.Flink; pCachedEntry != &CachedEntriesHead; pCachedEntry = pCachedEntry->Flink)
         {
-            Info.Category = ParserGetInt(L"Section", L"Category", FindFileData.cFileName);
-            if (Info.Category == -1)
-                continue;
+            Info = CONTAINING_RECORD(pCachedEntry, APPLICATION_INFO, List);
+
+            /* do we already have this entry in cache? */
+            if(_wcsicmp(FindFileData.cFileName, Info->cFileName) == 0)
+            {
+                /* is it current enough, or the file has been modified since our last time here? */
+                if (CompareFileTime(&FindFileData.ftLastWriteTime, &Info->ftCacheStamp) == 1)
+                {
+                    /* recreate our cache, this is the slow path */
+                    RemoveEntryList(&Info->List);
+                    HeapFree(GetProcessHeap(), 0, Info);
+                }
+                else
+                {
+                    /* speedy path, compare directly, we already have the data */
+                    goto skip_if_cached;
+                }
+
+                break;
+            }
         }
 
-        if (EnumType != Info.Category && EnumType != ENUM_ALL_AVAILABLE) continue;
+        /* create a new entry */
+        Info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APPLICATION_INFO));
 
-        GET_STRING1(L"Name", Info.szName);
-        GET_STRING1(L"URLDownload", Info.szUrlDownload);
+        if(!Info)
+            break;
 
-        GET_STRING2(L"RegName", Info.szRegName);
-        GET_STRING2(L"Version", Info.szVersion);
-        GET_STRING2(L"Licence", Info.szLicence);
-        GET_STRING2(L"Description", Info.szDesc);
-        GET_STRING2(L"Size", Info.szSize);
-        GET_STRING2(L"URLSite", Info.szUrlSite);
-        GET_STRING2(L"CDPath", Info.szCDPath);
+        Info->Category = ParserGetInt(L"Category", FindFileData.cFileName);
 
-        if (!lpEnumProc(Info)) break;
-    }
-    while (FindNextFileW(hFind, &FindFileData) != 0);
+        /* copy the cache-related fields for the next time */
+        RtlCopyMemory(&Info->cFileName,    &FindFileData.cFileName, MAX_PATH);
+        RtlCopyMemory(&Info->ftCacheStamp, &FindFileData.ftLastWriteTime, sizeof(FILETIME));
+
+        /* add our cached entry to the cached list */
+        InsertTailList(&CachedEntriesHead, &Info->List);
+
+skip_if_cached:
+
+        if (Info->Category == FALSE)
+            continue;
+
+        if (EnumType != Info->Category && EnumType != ENUM_ALL_AVAILABLE)
+            continue;
+
+        /* if our cache hit was only partial, we need to parse
+           and lazily fill the rest of fields only when needed */
+
+        if (Info->szUrlDownload[0] == 0)
+        {
+            GET_STRING1(L"Name",        Info->szName);
+            GET_STRING1(L"URLDownload", Info->szUrlDownload);
+
+            GET_STRING2(L"RegName",     Info->szRegName);
+            GET_STRING2(L"Version",     Info->szVersion);
+            GET_STRING2(L"License",     Info->szLicense);
+            GET_STRING2(L"Description", Info->szDesc);
+            GET_STRING2(L"Size",        Info->szSize);
+            GET_STRING2(L"URLSite",     Info->szUrlSite);
+            GET_STRING2(L"CDPath",      Info->szCDPath);
+            GET_STRING2(L"SHA1",        Info->szSHA1);
+        }
+
+        if (!lpEnumProc(Info))
+            break;
+
+    } while (FindNextFileW(hFind, &FindFileData) != 0);
 
     FindClose(hFind);
 
     return TRUE;
 }
+
+VOID FreeCachedAvailableEntries(VOID)
+{
+     PAPPLICATION_INFO Info;
+    /* loop and deallocate all the cached app infos in the list */
+    for (pCachedEntry = CachedEntriesHead.Flink; pCachedEntry != &CachedEntriesHead;)
+    {
+         Info = CONTAINING_RECORD(pCachedEntry, APPLICATION_INFO, List);
+        /* grab a reference to the next linked entry before getting rid of the current one */
+        pCachedEntry = pCachedEntry->Flink;
+        /* flush them down the toilet :D */
+        RemoveEntryList(&Info->List);
+        HeapFree(GetProcessHeap(), 0, Info);
+    }
+}
\ No newline at end of file