From c6d2efd76594f092ac3614c2f54541aca2e5c3f7 Mon Sep 17 00:00:00 2001 From: wiidev Date: Sat, 12 Dec 2020 21:33:31 +0000 Subject: [PATCH] Added extra caching options Thanks to Oddx & geoGolem --- Languages/czech.lang | 9 + Languages/danish.lang | 9 + Languages/dutch.lang | 9 + Languages/english.lang | 9 + Languages/finnish.lang | 9 + Languages/french.lang | 9 + Languages/german.lang | 9 + Languages/greek.lang | 9 + Languages/hungarian.lang | 9 + Languages/italian.lang | 9 + Languages/japanese.lang | 9 + Languages/korean.lang | 13 +- Languages/norwegian.lang | 9 + Languages/polish.lang | 9 + Languages/portuguese_br.lang | 9 + Languages/portuguese_pt.lang | 9 + Languages/russian.lang | 9 + Languages/schinese.lang | 9 + Languages/spanish.lang | 9 + Languages/swedish.lang | 9 + Languages/tchinese.lang | 9 + Languages/thai.lang | 9 + Languages/turkish.lang | 9 + Makefile | 3 +- source/Channels/channels.cpp | 1048 +++++++++-------- source/GameCube/GCGames.cpp | 253 ++-- source/cache/cache.cpp | 338 ++++++ source/cache/cache.hpp | 54 + source/menu/menu_install.cpp | 2 + source/settings/CSettings.cpp | 14 + source/settings/CSettings.h | 2 + source/settings/menus/CustomPathsSM.cpp | 11 + source/settings/menus/FeatureSettingsMenu.cpp | 46 +- source/settings/menus/UninstallSM.cpp | 5 + source/usbloader/GameList.cpp | 206 ++-- 35 files changed, 1473 insertions(+), 720 deletions(-) create mode 100644 source/cache/cache.cpp create mode 100644 source/cache/cache.hpp diff --git a/Languages/czech.lang b/Languages/czech.lang index 53e246a1..88692225 100644 --- a/Languages/czech.lang +++ b/Languages/czech.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID hry" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "Obnovit hudbu na pozadí" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Vynulovat cítac spuštení" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Odinstalace" diff --git a/Languages/danish.lang b/Languages/danish.lang index a3367d26..7b7a567e 100644 --- a/Languages/danish.lang +++ b/Languages/danish.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Spil-ID" @@ -1824,6 +1827,9 @@ msgstr "Nulstil" msgid "Reset BG Music" msgstr "Nulstil BG-musik" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Nulstil spiltæller" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Afinstaller" diff --git a/Languages/dutch.lang b/Languages/dutch.lang index 74911fe4..c1d23ca7 100644 --- a/Languages/dutch.lang +++ b/Languages/dutch.lang @@ -1101,6 +1101,9 @@ msgstr "GameCube Spel Verwijderen" msgid "GameCube Install Menu" msgstr "GameCube Installatie Menu" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Spel ID" @@ -1824,6 +1827,9 @@ msgstr "Resetten" msgid "Reset BG Music" msgstr "Reset achtergrond muziek" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Speeltellers resetten" @@ -2253,6 +2259,9 @@ msgstr "USBLoaderGX kon Nintendont config bestand niet schrijven. Nintendont toc msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Verwijderen" diff --git a/Languages/english.lang b/Languages/english.lang index 6573c7b6..88aaf2de 100644 --- a/Languages/english.lang +++ b/Languages/english.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "" diff --git a/Languages/finnish.lang b/Languages/finnish.lang index f77d2536..bbfaff46 100644 --- a/Languages/finnish.lang +++ b/Languages/finnish.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Peli ID" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Resetoi pelauksen määrä" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Poista" diff --git a/Languages/french.lang b/Languages/french.lang index 4b78b7ea..21fb0a6d 100644 --- a/Languages/french.lang +++ b/Languages/french.lang @@ -1101,6 +1101,9 @@ msgstr "Menu de suppression GameCube" msgid "GameCube Install Menu" msgstr "Menu d'installation GameCube" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID du jeu" @@ -1824,6 +1827,9 @@ msgstr "Réinitialisation" msgid "Reset BG Music" msgstr "Fond sonore par defaut" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Remise à zéro du compteur d'utilisations" @@ -2253,6 +2259,9 @@ msgstr "USBLoaderGX n'a pas pu créer le fichier de configuration de Nintendont. msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "Nintendont Alpha v0.1 ne fonctionne qu'avec USBLoaderGX r1218. Veuillez mettre à jour votre version de Nintendont." +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Désinstaller" diff --git a/Languages/german.lang b/Languages/german.lang index 65aff785..f8a1c068 100644 --- a/Languages/german.lang +++ b/Languages/german.lang @@ -1101,6 +1101,9 @@ msgstr "GameCube Spiele Löschen" msgid "GameCube Install Menu" msgstr "GameCube Installationsmenü" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Spiel ID" @@ -1824,6 +1827,9 @@ msgstr "Zurücksetzen" msgid "Reset BG Music" msgstr "Musik zurücksetzen" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Spielzähler zurücksetzen" @@ -2253,6 +2259,9 @@ msgstr "USBLoaderGX konnte die Nintendont config Dateien nicht ändern. Nintendo msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "USBLoaderGX r1218 wird benötigt um Nintendont Alpha v0.1 starten zu können. Bitte aktualisiere deine Nintendont Version." +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Deinstallieren" diff --git a/Languages/greek.lang b/Languages/greek.lang index 41505cdf..423b99bd 100644 --- a/Languages/greek.lang +++ b/Languages/greek.lang @@ -1101,6 +1101,9 @@ msgstr "Διαγραφή παιχνιδιών GameCube" msgid "GameCube Install Menu" msgstr "menu εγκατάστασης παιχνιδιών GameCube" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID παιχνιδιού" @@ -1824,6 +1827,9 @@ msgstr "Επανεκκίνηση" msgid "Reset BG Music" msgstr "Επαναφορά μουσικής υπόκρουσης." +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Επαναφορά του Playcounter" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Απεγκατάσταση" diff --git a/Languages/hungarian.lang b/Languages/hungarian.lang index a639575f..2b58ba37 100644 --- a/Languages/hungarian.lang +++ b/Languages/hungarian.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Játék ID" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Elindítások nullázása" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Törlés" diff --git a/Languages/italian.lang b/Languages/italian.lang index 90e06b92..4391e3ea 100644 --- a/Languages/italian.lang +++ b/Languages/italian.lang @@ -1101,6 +1101,9 @@ msgstr "Menu disinstallazioni GC" msgid "GameCube Install Menu" msgstr "Menu installazioni GC" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID gioco" @@ -1824,6 +1827,9 @@ msgstr "Riavvia" msgid "Reset BG Music" msgstr "Ripristina musica sottofondo" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Azzera contatore" @@ -2253,6 +2259,9 @@ msgstr "USBLoader GX non può sceivere il file configurazione. Avviare comuqnue msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "USBLoaderGX r1218 o successivo è richiesto per Nintendont Alpha v0.1. Per favore aggiorna la tua versione di Nintendont" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Disinstalla" diff --git a/Languages/japanese.lang b/Languages/japanese.lang index 7668c804..022ab1c9 100644 --- a/Languages/japanese.lang +++ b/Languages/japanese.lang @@ -1101,6 +1101,9 @@ msgstr "GCゲームの削除" msgid "GameCube Install Menu" msgstr "GCインストールメニュー" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "IDのみ" @@ -1824,6 +1827,9 @@ msgstr "リセット" msgid "Reset BG Music" msgstr "BGMをリセット" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "プレイ回数をリセット" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "アンインストール" diff --git a/Languages/korean.lang b/Languages/korean.lang index d90cc99d..8267eb69 100644 --- a/Languages/korean.lang +++ b/Languages/korean.lang @@ -1095,12 +1095,15 @@ msgstr "" msgid "GXFlush" msgstr "" -msgid "Game Cube Games Delete" +msgid "GameCube Games Delete" msgstr "게임큐브 게임 삭제" -msgid "Game Cube Install Menu" +msgid "GameCube Install Menu" msgstr "게임큐브 설치 메뉴" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "게임 ID" @@ -1824,6 +1827,9 @@ msgstr "리셋" msgid "Reset BG Music" msgstr "배경 음악 리셋" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Playcounter 리셋" @@ -2247,6 +2253,9 @@ msgstr "USBloaderGX는 닌텐돈트 구성 파일을 기록할 수 없습니다. msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "USBloaderGX r1218은 닌텐돈트 알파 v0.1에 필요합니다. 닌텐돈트 boot.dol 버전을 업데이트하십시오." +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "제거" diff --git a/Languages/norwegian.lang b/Languages/norwegian.lang index 2cd33fc9..b756514b 100644 --- a/Languages/norwegian.lang +++ b/Languages/norwegian.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Spill ID" @@ -1824,6 +1827,9 @@ msgstr "Tilbakestill" msgid "Reset BG Music" msgstr "Tilbakestill BG musikk" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Nullstill teller" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "" diff --git a/Languages/polish.lang b/Languages/polish.lang index 6ffabe12..d2b24096 100644 --- a/Languages/polish.lang +++ b/Languages/polish.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID gry" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Zrestartuj licznik" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Odinstaluj" diff --git a/Languages/portuguese_br.lang b/Languages/portuguese_br.lang index b283b1c0..0e890031 100644 --- a/Languages/portuguese_br.lang +++ b/Languages/portuguese_br.lang @@ -1101,6 +1101,9 @@ msgstr "Desinstalar Jogos GameCube" msgid "GameCube Install Menu" msgstr "Instalar Jogos GameCube" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID do Jogo" @@ -1824,6 +1827,9 @@ msgstr "Reiniciar" msgid "Reset BG Music" msgstr "Música padrão" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Limpar Contagem" @@ -2253,6 +2259,9 @@ msgstr "USB Loader GX não conseguiu gravar configurações do Nintendont. Rodar msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "USB Loader GX r1218 é exigido para usar o Nintendont Alpha v0.1. Atualize sua versão do Nintendont" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Desinstalar" diff --git a/Languages/portuguese_pt.lang b/Languages/portuguese_pt.lang index 0a2fd16b..9e82df11 100644 --- a/Languages/portuguese_pt.lang +++ b/Languages/portuguese_pt.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID do Jogo" @@ -1824,6 +1827,9 @@ msgstr "Reinicializar" msgid "Reset BG Music" msgstr "Reinicializar Música de Fundo" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Limpar Contagem" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "" diff --git a/Languages/russian.lang b/Languages/russian.lang index fcdf025f..9900f0f1 100644 --- a/Languages/russian.lang +++ b/Languages/russian.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID игры" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Сбросить счетчик запусков" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Деинсталлировать" diff --git a/Languages/schinese.lang b/Languages/schinese.lang index b88a919b..c22ffd6a 100644 --- a/Languages/schinese.lang +++ b/Languages/schinese.lang @@ -1101,6 +1101,9 @@ msgstr "GameCube 游戏删除" msgid "GameCube Install Menu" msgstr "GameCube 安装菜单" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "游戏 ID" @@ -1824,6 +1827,9 @@ msgstr "重启" msgid "Reset BG Music" msgstr "重置背景音乐" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "重置游戏计数" @@ -2253,6 +2259,9 @@ msgstr "USBloaderGX不能写Nintendont设置文件,是否运行Nintendont?" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "USBloaderGX r1218之针对nintendont Alpha v0.1,请更新你的Nintendont boot。dol版本。" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "删除" diff --git a/Languages/spanish.lang b/Languages/spanish.lang index 263f603c..aec3f8dc 100644 --- a/Languages/spanish.lang +++ b/Languages/spanish.lang @@ -1101,6 +1101,9 @@ msgstr "Borrar Juego de GameCube" msgid "GameCube Install Menu" msgstr "Menu de instalación GameCube" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "ID del Juego" @@ -1824,6 +1827,9 @@ msgstr "Reiniciar" msgid "Reset BG Music" msgstr "Reiniciar Música de Fondo" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Reiniciar Partidas" @@ -2253,6 +2259,9 @@ msgstr "No se puede escribir la configuración de Nintendont, ¿desea continuar msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "Se necesita la versión r1218 para Nintendont Alpha 0.1. Por favor, actualiza el boot.dol de Nintendont." +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Desinstalar" diff --git a/Languages/swedish.lang b/Languages/swedish.lang index 9fccaad0..6b38fa0a 100644 --- a/Languages/swedish.lang +++ b/Languages/swedish.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Spel-ID" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "återställ BG musik" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Återställ spelat-räknaren" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Avinstallera" diff --git a/Languages/tchinese.lang b/Languages/tchinese.lang index 0b68cd83..e795ea1b 100644 --- a/Languages/tchinese.lang +++ b/Languages/tchinese.lang @@ -1101,6 +1101,9 @@ msgstr "GameCube 遊戲刪除" msgid "GameCube Install Menu" msgstr "GameCube 安裝畫面" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "遊戲 ID" @@ -1824,6 +1827,9 @@ msgstr "重新啟動" msgid "Reset BG Music" msgstr "重設背景音樂" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "重設執行次數" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "移除" diff --git a/Languages/thai.lang b/Languages/thai.lang index 45622235..ccb141a2 100644 --- a/Languages/thai.lang +++ b/Languages/thai.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "เกมส์ ID" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "เคลียร์การนับจำนวนที่เล่น" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "ถอนการติดตั้ง" diff --git a/Languages/turkish.lang b/Languages/turkish.lang index 36f37dc5..ad89353d 100644 --- a/Languages/turkish.lang +++ b/Languages/turkish.lang @@ -1101,6 +1101,9 @@ msgstr "" msgid "GameCube Install Menu" msgstr "" +msgid "Game Header Cache Files Path" +msgstr "" + msgid "Game ID" msgstr "Oyun ID" @@ -1824,6 +1827,9 @@ msgstr "" msgid "Reset BG Music" msgstr "" +msgid "Reset Game Header Cache" +msgstr "" + msgid "Reset Playcounter" msgstr "Sayacı sıfırla" @@ -2253,6 +2259,9 @@ msgstr "" msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgstr "" +msgid "Use Game Header Cache" +msgstr "" + msgid "Uninstall" msgstr "Kaldır" diff --git a/Makefile b/Makefile index 42f8e7a2..bd9a4381 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,8 @@ SOURCES := source \ source/SystemMenu \ source/utils \ source/utils/minizip \ - source/usbloader/wbfs + source/usbloader/wbfs \ + source/cache DATA := data \ data/images \ data/fonts \ diff --git a/source/Channels/channels.cpp b/source/Channels/channels.cpp index db5a338a..278ee87a 100755 --- a/source/Channels/channels.cpp +++ b/source/Channels/channels.cpp @@ -26,6 +26,7 @@ #include #include #include + #include "FileOperations/fileops.h" #include "Controls/DeviceHandler.hpp" #include "settings/CSettings.h" @@ -35,720 +36,735 @@ #include "memory/memory.h" #include "utils/lz77.h" #include "gecko.h" - +#include "cache/cache.hpp" #include "channels.h" -typedef struct _dolheader{ - u32 section_pos[18]; - u32 section_start[18]; - u32 section_size[18]; - u32 bss_start; - u32 bss_size; - u32 entry_point; - u32 padding[7]; +typedef struct _dolheader +{ + u32 section_pos[18]; + u32 section_start[18]; + u32 section_size[18]; + u32 bss_start; + u32 bss_size; + u32 entry_point; + u32 padding[7]; } __attribute__((packed)) dolheader; Channels *Channels::instance = NULL; void Channels::GetEmuChannelList() { - EmuChannels.clear(); + EmuChannels.clear(); - char filepath[1024]; - int language = CONF_GetLanguage(); + char filepath[1024]; + int language = CONF_GetLanguage(); - snprintf(filepath, sizeof(filepath), "%s/title/00010001", Settings.NandEmuChanPath); - ParseTitleDir(filepath, language); + snprintf(filepath, sizeof(filepath), "%s/title/00010001", Settings.NandEmuChanPath); + ParseTitleDir(filepath, language); - snprintf(filepath, sizeof(filepath), "%s/title/00010004", Settings.NandEmuChanPath); - ParseTitleDir(filepath, language); + snprintf(filepath, sizeof(filepath), "%s/title/00010004", Settings.NandEmuChanPath); + ParseTitleDir(filepath, language); - snprintf(filepath, sizeof(filepath), "%s/title/00010002", Settings.NandEmuChanPath); - ParseTitleDir(filepath, language); + snprintf(filepath, sizeof(filepath), "%s/title/00010002", Settings.NandEmuChanPath); + ParseTitleDir(filepath, language); } void Channels::GetChannelList() { - NandChannels.clear(); + NandChannels.clear(); - // Get count of titles of the good titles - InternalGetNandChannelList(0x00010001); - InternalGetNandChannelList(0x00010004); - InternalGetNandChannelList(0x00010002); + // Get count of titles of the good titles + InternalGetNandChannelList(0x00010001); + InternalGetNandChannelList(0x00010004); + InternalGetNandChannelList(0x00010002); } void Channels::InternalGetNandChannelList(u32 type) { - // Get count of system titles - u32 num_titles = NandTitles.SetType(type); + // Get count of system titles + u32 num_titles = NandTitles.SetType(type); - for (u32 i = 0; i < num_titles; i++) - { - u64 tid = NandTitles.Next(); - if (!tid) - break; + for (u32 i = 0; i < num_titles; i++) + { + u64 tid = NandTitles.Next(); + if (!tid) + break; - //these can't be booted anyways - if (TITLE_LOWER( tid ) == 0x48414741 || TITLE_LOWER( tid ) == 0x48414141 || TITLE_LOWER( tid ) == 0x48414641) - continue; + //these can't be booted anyways + if (TITLE_LOWER(tid) == 0x48414741 || TITLE_LOWER(tid) == 0x48414141 || TITLE_LOWER(tid) == 0x48414641) + continue; - //these aren't installed on the nand - if (!NandTitles.Exists(tid)) - continue; + //these aren't installed on the nand + if (!NandTitles.Exists(tid)) + continue; - char id[5]; - NandTitles.AsciiTID(tid, id); + char id[5]; + NandTitles.AsciiTID(tid, id); - // Force old and new format to be "JODI" which is known by GameTDB - if(tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) - strcpy(id, "JODI"); + // Force old and new format to be "JODI" which is known by GameTDB + if (tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) + strcpy(id, "JODI"); - const char *name = GameTitles.GetTitle(id); - std::string TitleName; + const char *name = GameTitles.GetTitle(id); + std::string TitleName; - if(!name || *name == '\0') - { - name = NandTitles.NameOf(tid); - // Set title for caching - if(name) - GameTitles.SetGameTitle(id, name); - } + if (!name || *name == '\0') + { + name = NandTitles.NameOf(tid); + // Set title for caching + if (name) + GameTitles.SetGameTitle(id, name); + } - int s = NandChannels.size(); - NandChannels.resize(s + 1); - memset(&NandChannels[s], 0, sizeof(struct discHdr)); - memcpy(NandChannels[s].id, id, 4); - NandChannels[s].tid = tid; - NandChannels[s].type = TYPE_GAME_NANDCHAN; - strncpy(NandChannels[s].title, name ? name : "", sizeof(NandChannels[s].title)-1); - } + int s = NandChannels.size(); + NandChannels.resize(s + 1); + memset(&NandChannels[s], 0, sizeof(struct discHdr)); + memcpy(NandChannels[s].id, id, 4); + NandChannels[s].tid = tid; + NandChannels[s].type = TYPE_GAME_NANDCHAN; + strncpy(NandChannels[s].title, name ? name : "", sizeof(NandChannels[s].title) - 1); + } } -vector & Channels::GetNandHeaders(void) +vector &Channels::GetNandHeaders(void) { - if(NandChannels.empty()) - this->GetChannelList(); + if (NandChannels.empty()) + this->GetChannelList(); - return NandChannels; + return NandChannels; } -vector & Channels::GetEmuHeaders(void) +vector &Channels::GetEmuHeaders(void) { - if(EmuChannels.empty()) - this->GetEmuChannelList(); + if (Settings.UseGameHeaderCache && isCacheFile(EMUNAND_HEADER_CACHE_FILE)) + { + if (EmuChannels.empty()) + LoadGameHeaderCache(EmuChannels); + if (!EmuChannels.empty()) + return EmuChannels; + } - return EmuChannels; + if (EmuChannels.empty()) + this->GetEmuChannelList(); + + if (Settings.UseGameHeaderCache && !EmuChannels.empty()) + SaveGameHeaderCache(EmuChannels); + + return EmuChannels; } -u8 * Channels::GetDol(const u64 &title, u8 *tmdBuffer) +u8 *Channels::GetDol(const u64 &title, u8 *tmdBuffer) { - static const u8 dolsign[6] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; - static u8 dolhead[32] ATTRIBUTE_ALIGN(32); - u8 *buffer = NULL; - u32 filesize = 0; - u32 bootcontent = 0xDEADBEAF; - u32 high = TITLE_UPPER(title); - u32 low = TITLE_LOWER(title); + static const u8 dolsign[6] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00}; + static u8 dolhead[32] ATTRIBUTE_ALIGN(32); + u8 *buffer = NULL; + u32 filesize = 0; + u32 bootcontent = 0xDEADBEAF; + u32 high = TITLE_UPPER(title); + u32 low = TITLE_LOWER(title); - char *filepath = (char *) memalign(32, ISFS_MAXPATH); - if(!filepath) - return NULL; + char *filepath = (char *)memalign(32, ISFS_MAXPATH); + if (!filepath) + return NULL; - _tmd * tmd_file = (_tmd *) SIGNATURE_PAYLOAD((u32 *)tmdBuffer); + _tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)tmdBuffer); - if(!Settings.UseChanLauncher) - { - for(u32 i = 0; i < tmd_file->num_contents; ++i) - { - if(tmd_file->contents[i].index == tmd_file->boot_index) - continue; // Skip loader + if (!Settings.UseChanLauncher) + { + for (u32 i = 0; i < tmd_file->num_contents; ++i) + { + if (tmd_file->contents[i].index == tmd_file->boot_index) + continue; // Skip loader - snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", (unsigned int)high, (unsigned int)low, (unsigned int)tmd_file->contents[i].cid); + snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", (unsigned int)high, (unsigned int)low, (unsigned int)tmd_file->contents[i].cid); - s32 fd = ISFS_Open(filepath, ISFS_OPEN_READ); - if(fd < 0) - continue; + s32 fd = ISFS_Open(filepath, ISFS_OPEN_READ); + if (fd < 0) + continue; - s32 ret = ISFS_Read(fd, dolhead, 32); - ISFS_Close(fd); + s32 ret = ISFS_Read(fd, dolhead, 32); + ISFS_Close(fd); - if(ret != 32) - continue; + if (ret != 32) + continue; - if(memcmp(dolhead, dolsign, sizeof(dolsign)) == 0) - { - bootcontent = tmd_file->contents[i].cid; - break; - } - } - } + if (memcmp(dolhead, dolsign, sizeof(dolsign)) == 0) + { + bootcontent = tmd_file->contents[i].cid; + break; + } + } + } - //! Fall back to boot content if dol is not found - if(bootcontent == 0xDEADBEAF) - { - bootcontent = tmd_file->contents[tmd_file->boot_index].cid; - if(!Settings.UseChanLauncher) gprintf("Main dol not found -> "); - gprintf("Loading boot content index\n"); - } + //! Fall back to boot content if dol is not found + if (bootcontent == 0xDEADBEAF) + { + bootcontent = tmd_file->contents[tmd_file->boot_index].cid; + if (!Settings.UseChanLauncher) + gprintf("Main dol not found -> "); + gprintf("Loading boot content index\n"); + } - snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", (unsigned int)high, (unsigned int)low, (unsigned int)bootcontent); - gprintf("Loading Channel DOL: %s\n", filepath); + snprintf(filepath, ISFS_MAXPATH, "/title/%08x/%08x/content/%08x.app", (unsigned int)high, (unsigned int)low, (unsigned int)bootcontent); + gprintf("Loading Channel DOL: %s\n", filepath); - if (NandTitle::LoadFileFromNand(filepath, &buffer, &filesize) < 0) - { - gprintf("Failed loading DOL file\n"); - free(filepath); - return NULL; - } + if (NandTitle::LoadFileFromNand(filepath, &buffer, &filesize) < 0) + { + gprintf("Failed loading DOL file\n"); + free(filepath); + return NULL; + } - free(filepath); + free(filepath); - if (isLZ77compressed(buffer)) - { - u8 *decompressed = NULL; - u32 size = 0; - if (decompressLZ77content(buffer, filesize, &decompressed, &size) < 0) - { - gprintf("Decompression failed\n"); - free(buffer); - return NULL; - } - free(buffer); - buffer = decompressed; - filesize = size; - } + if (isLZ77compressed(buffer)) + { + u8 *decompressed = NULL; + u32 size = 0; + if (decompressLZ77content(buffer, filesize, &decompressed, &size) < 0) + { + gprintf("Decompression failed\n"); + free(buffer); + return NULL; + } + free(buffer); + buffer = decompressed; + filesize = size; + } - // move dol to mem2 - u8 *outBuf = (u8 *) MEM2_alloc(filesize); - if(!outBuf) - return buffer; + // move dol to mem2 + u8 *outBuf = (u8 *)MEM2_alloc(filesize); + if (!outBuf) + return buffer; - memcpy(outBuf, buffer, filesize); - free(buffer); + memcpy(outBuf, buffer, filesize); + free(buffer); - return outBuf; + return outBuf; } u8 Channels::GetRequestedIOS(const u64 &title) { - u8 IOS = 0; + u8 IOS = 0; - u32 tmdSize = 0; - u8 *titleTMD = GetTMD(title, &tmdSize, ""); - if (!titleTMD) - return 0; + u32 tmdSize = 0; + u8 *titleTMD = GetTMD(title, &tmdSize, ""); + if (!titleTMD) + return 0; - if(tmdSize > 0x18B) - IOS = titleTMD[0x18B]; + if (tmdSize > 0x18B) + IOS = titleTMD[0x18B]; - free(titleTMD); + free(titleTMD); - return IOS; + return IOS; } u8 *Channels::GetTMD(const u64 &tid, u32 *size, const char *prefix) { - char *filepath = (char *) memalign(32, ISFS_MAXPATH); - if(!filepath) - return NULL; + char *filepath = (char *)memalign(32, ISFS_MAXPATH); + if (!filepath) + return NULL; - if(!prefix) - prefix = ""; + if (!prefix) + prefix = ""; - snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/title.tmd", prefix, (unsigned int)TITLE_UPPER(tid), (unsigned int)TITLE_LOWER(tid)); + snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/title.tmd", prefix, (unsigned int)TITLE_UPPER(tid), (unsigned int)TITLE_LOWER(tid)); - u8 *tmdBuffer = NULL; - u32 tmdSize = 0; + u8 *tmdBuffer = NULL; + u32 tmdSize = 0; - int ret; + int ret; - if(*prefix != '\0') - ret = LoadFileToMem(filepath, &tmdBuffer, &tmdSize); - else - ret = NandTitle::LoadFileFromNand(filepath, &tmdBuffer, &tmdSize); + if (*prefix != '\0') + ret = LoadFileToMem(filepath, &tmdBuffer, &tmdSize); + else + ret = NandTitle::LoadFileFromNand(filepath, &tmdBuffer, &tmdSize); - free(filepath); + free(filepath); - if (ret < 0) - { - gprintf("Reading TMD...Failed!\n"); - if(tmdBuffer) - free(tmdBuffer); - return NULL; - } + if (ret < 0) + { + gprintf("Reading TMD...Failed!\n"); + if (tmdBuffer) + free(tmdBuffer); + return NULL; + } - if(size) - *size = tmdSize; + if (size) + *size = tmdSize; - return tmdBuffer; + return tmdBuffer; } u32 Channels::LoadChannel(const u64 &chantitle) { - ISFS_Initialize(); + ISFS_Initialize(); - u32 ios = 0; - u32 tmdSize = 0; - u8 *tmdBuffer = GetTMD(chantitle, &tmdSize, ""); - if(!tmdBuffer) - { - ISFS_Deinitialize(); - return 0; - } + u32 ios = 0; + u32 tmdSize = 0; + u8 *tmdBuffer = GetTMD(chantitle, &tmdSize, ""); + if (!tmdBuffer) + { + ISFS_Deinitialize(); + return 0; + } - u8 *chanDOL = GetDol(chantitle, tmdBuffer); - if(!chanDOL) - { - ISFS_Deinitialize(); - free(tmdBuffer); - return 0; - } + u8 *chanDOL = GetDol(chantitle, tmdBuffer); + if (!chanDOL) + { + ISFS_Deinitialize(); + free(tmdBuffer); + return 0; + } - if(tmdSize > 0x18B) - ios = tmdBuffer[0x18B]; + if (tmdSize > 0x18B) + ios = tmdBuffer[0x18B]; - Identify(chantitle, tmdBuffer, tmdSize); + Identify(chantitle, tmdBuffer, tmdSize); - free(tmdBuffer); + free(tmdBuffer); - dolheader *dolfile = (dolheader *)chanDOL; + dolheader *dolfile = (dolheader *)chanDOL; - if(dolfile->bss_start) - { - dolfile->bss_start |= 0x80000000; + if (dolfile->bss_start) + { + dolfile->bss_start |= 0x80000000; - if(dolfile->bss_start < 0x81800000) - { - // For homebrews...not all have it clean. - if(dolfile->bss_start + dolfile->bss_size >= 0x81800000) - dolfile->bss_size = 0x81800000 - dolfile->bss_start; + if (dolfile->bss_start < 0x81800000) + { + // For homebrews...not all have it clean. + if (dolfile->bss_start + dolfile->bss_size >= 0x81800000) + dolfile->bss_size = 0x81800000 - dolfile->bss_start; - memset((void *)dolfile->bss_start, 0, dolfile->bss_size); - DCFlushRange((void *)dolfile->bss_start, dolfile->bss_size); - ICInvalidateRange((void *)dolfile->bss_start, dolfile->bss_size); - } - } + memset((void *)dolfile->bss_start, 0, dolfile->bss_size); + DCFlushRange((void *)dolfile->bss_start, dolfile->bss_size); + ICInvalidateRange((void *)dolfile->bss_start, dolfile->bss_size); + } + } - int i; - for(i = 0; i < 18; i++) - { - if (!dolfile->section_size[i]) continue; - if (dolfile->section_pos[i] < sizeof(dolheader)) continue; - if(!(dolfile->section_start[i] & 0x80000000)) - dolfile->section_start[i] |= 0x80000000; + int i; + for (i = 0; i < 18; i++) + { + if (!dolfile->section_size[i]) + continue; + if (dolfile->section_pos[i] < sizeof(dolheader)) + continue; + if (!(dolfile->section_start[i] & 0x80000000)) + dolfile->section_start[i] |= 0x80000000; - u8 *dolChunkOffset = (u8 *)dolfile->section_start[i]; - u32 dolChunkSize = dolfile->section_size[i]; + u8 *dolChunkOffset = (u8 *)dolfile->section_start[i]; + u32 dolChunkSize = dolfile->section_size[i]; - memmove (dolChunkOffset, chanDOL + dolfile->section_pos[i], dolChunkSize); - DCFlushRange(dolChunkOffset, dolChunkSize); - ICInvalidateRange(dolChunkOffset, dolChunkSize); + memmove(dolChunkOffset, chanDOL + dolfile->section_pos[i], dolChunkSize); + DCFlushRange(dolChunkOffset, dolChunkSize); + ICInvalidateRange(dolChunkOffset, dolChunkSize); - RegisterDOL(dolChunkOffset, dolChunkSize); - } + RegisterDOL(dolChunkOffset, dolChunkSize); + } - u32 chanEntryPoint = dolfile->entry_point; + u32 chanEntryPoint = dolfile->entry_point; - free(dolfile); + free(dolfile); - // Preparations - memset((void *)Disc_ID, 0, 6); - *Disc_ID = TITLE_LOWER(chantitle); // Game ID - *Arena_H = 0; // Arena High, the apploader does this too - *BI2 = 0x817FE000; // BI2, the apploader does this too - *Bus_Speed = 0x0E7BE2C0; // bus speed - *CPU_Speed = 0x2B73A840; // cpu speed - *GameID_Address = 0x81000000; // Game id address, while there's all 0s at 0x81000000 when using the apploader... - memcpy((void *)Online_Check, (void *)Disc_ID, 4);// online check + // Preparations + memset((void *)Disc_ID, 0, 6); + *Disc_ID = TITLE_LOWER(chantitle); // Game ID + *Arena_H = 0; // Arena High, the apploader does this too + *BI2 = 0x817FE000; // BI2, the apploader does this too + *Bus_Speed = 0x0E7BE2C0; // bus speed + *CPU_Speed = 0x2B73A840; // cpu speed + *GameID_Address = 0x81000000; // Game id address, while there's all 0s at 0x81000000 when using the apploader... + memcpy((void *)Online_Check, (void *)Disc_ID, 4); // online check - memset((void *)0x817FE000, 0, 0x2000); // Clearing BI2 - DCFlushRange((void*)0x817FE000, 0x2000); + memset((void *)0x817FE000, 0, 0x2000); // Clearing BI2 + DCFlushRange((void *)0x817FE000, 0x2000); - // IOS Version Check - *(vu32*)0x80003140 = ((ios << 16)) | 0xFFFF; - *(vu32*)0x80003188 = ((ios << 16)) | 0xFFFF; + // IOS Version Check + *(vu32 *)0x80003140 = ((ios << 16)) | 0xFFFF; + *(vu32 *)0x80003188 = ((ios << 16)) | 0xFFFF; - ISFS_Deinitialize(); + ISFS_Deinitialize(); - return chanEntryPoint; + return chanEntryPoint; } static bool Identify_GenerateTik(signed_blob **outbuf, u32 *outlen) { - signed_blob *buffer = (signed_blob *)memalign(32, STD_SIGNED_TIK_SIZE); - if (!buffer) return false; - memset(buffer, 0, STD_SIGNED_TIK_SIZE); + signed_blob *buffer = (signed_blob *)memalign(32, STD_SIGNED_TIK_SIZE); + if (!buffer) + return false; + memset(buffer, 0, STD_SIGNED_TIK_SIZE); - sig_rsa2048 *signature = (sig_rsa2048 *)buffer; - signature->type = ES_SIG_RSA2048; + sig_rsa2048 *signature = (sig_rsa2048 *)buffer; + signature->type = ES_SIG_RSA2048; - tik *tik_data = (tik *)SIGNATURE_PAYLOAD(buffer); - strcpy(tik_data->issuer, "Root-CA00000001-XS00000003"); - memset(tik_data->cidx_mask, 0xFF, 32); + tik *tik_data = (tik *)SIGNATURE_PAYLOAD(buffer); + strcpy(tik_data->issuer, "Root-CA00000001-XS00000003"); + memset(tik_data->cidx_mask, 0xFF, 32); - *outbuf = buffer; - *outlen = STD_SIGNED_TIK_SIZE; + *outbuf = buffer; + *outlen = STD_SIGNED_TIK_SIZE; - return true; + return true; } bool Channels::Identify(const u64 &titleid, u8 *tmdBuffer, u32 tmdSize) { - char *filepath = (char *) memalign(32, ISFS_MAXPATH); - if(!filepath) - return false; + char *filepath = (char *)memalign(32, ISFS_MAXPATH); + if (!filepath) + return false; - u32 tikSize; - signed_blob *tikBuffer = NULL; + u32 tikSize; + signed_blob *tikBuffer = NULL; - if(!Identify_GenerateTik(&tikBuffer,&tikSize)) - { - free(filepath); - gprintf("Generating fake ticket...Failed!"); - return false; - } + if (!Identify_GenerateTik(&tikBuffer, &tikSize)) + { + free(filepath); + gprintf("Generating fake ticket...Failed!"); + return false; + } - strlcpy(filepath, "/sys/cert.sys", ISFS_MAXPATH); - u8 *certBuffer = NULL; - u32 certSize = 0; - if (NandTitle::LoadFileFromNand(filepath, &certBuffer, &certSize) < 0) - { - gprintf("Reading certs...Failed!\n"); - free(tikBuffer); - free(filepath); - return false; - } - s32 ret = ES_Identify((signed_blob*)certBuffer, certSize, (signed_blob*)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL); - if (ret < 0) - { - switch(ret) - { - case ES_EINVAL: - gprintf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret); - break; - case ES_EALIGN: - gprintf("Error! ES_Identify (ret = %d;) Data not aligned!\n", ret); - break; - case ES_ENOTINIT: - gprintf("Error! ES_Identify (ret = %d;) ES not initialized!\n", ret); - break; - case ES_ENOMEM: - gprintf("Error! ES_Identify (ret = %d;) No memory!\n", ret); - break; - default: - gprintf("Error! ES_Identify (ret = %d)\n", ret); - break; - } - } + strlcpy(filepath, "/sys/cert.sys", ISFS_MAXPATH); + u8 *certBuffer = NULL; + u32 certSize = 0; + if (NandTitle::LoadFileFromNand(filepath, &certBuffer, &certSize) < 0) + { + gprintf("Reading certs...Failed!\n"); + free(tikBuffer); + free(filepath); + return false; + } + s32 ret = ES_Identify((signed_blob *)certBuffer, certSize, (signed_blob *)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL); + if (ret < 0) + { + switch (ret) + { + case ES_EINVAL: + gprintf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret); + break; + case ES_EALIGN: + gprintf("Error! ES_Identify (ret = %d;) Data not aligned!\n", ret); + break; + case ES_ENOTINIT: + gprintf("Error! ES_Identify (ret = %d;) ES not initialized!\n", ret); + break; + case ES_ENOMEM: + gprintf("Error! ES_Identify (ret = %d;) No memory!\n", ret); + break; + default: + gprintf("Error! ES_Identify (ret = %d)\n", ret); + break; + } + } - free(tikBuffer); - free(filepath); - free(certBuffer); + free(tikBuffer); + free(filepath); + free(certBuffer); - return ret < 0 ? false : true; + return ret < 0 ? false : true; } bool Channels::emuExists(char *tmdpath) { - u8 *buffer = NULL; - u32 size = 0; + u8 *buffer = NULL; + u32 size = 0; - if(LoadFileToMem(tmdpath, &buffer, &size) < 0) - return false; + if (LoadFileToMem(tmdpath, &buffer, &size) < 0) + return false; - signed_blob *s_tmd = (signed_blob *) buffer; + signed_blob *s_tmd = (signed_blob *)buffer; - u32 i; - tmd *titleTmd = (tmd *) SIGNATURE_PAYLOAD(s_tmd); + u32 i; + tmd *titleTmd = (tmd *)SIGNATURE_PAYLOAD(s_tmd); - for (i = 0; i < titleTmd->num_contents; i++) - if (!titleTmd->contents[i].index) - break; + for (i = 0; i < titleTmd->num_contents; i++) + if (!titleTmd->contents[i].index) + break; - if(i == titleTmd->num_contents) - { - free(buffer); - return false; - } + if (i == titleTmd->num_contents) + { + free(buffer); + return false; + } - u32 cid = titleTmd->contents[i].cid; - - free(buffer); + u32 cid = titleTmd->contents[i].cid; - char *ptr = strrchr(tmdpath, '/'); - if(!ptr) - return false; + free(buffer); - //! tmdpath has length of 1024 - snprintf(ptr+1, 1024-(ptr+1-tmdpath), "%08x.app", (unsigned int)cid); + char *ptr = strrchr(tmdpath, '/'); + if (!ptr) + return false; - FILE *f = fopen(tmdpath, "rb"); - if(!f) - return false; + //! tmdpath has length of 1024 + snprintf(ptr + 1, 1024 - (ptr + 1 - tmdpath), "%08x.app", (unsigned int)cid); - fclose(f); - - return true; + FILE *f = fopen(tmdpath, "rb"); + if (!f) + return false; + + fclose(f); + + return true; } bool Channels::ParseTitleDir(char *path, int language) { - if(!path) - return false; + if (!path) + return false; - const char *tidPtr = strrchr(path, '/'); - if(!tidPtr) - return false; - else - tidPtr++; + const char *tidPtr = strrchr(path, '/'); + if (!tidPtr) + return false; + else + tidPtr++; - struct dirent *dirent = NULL; - DIR *dir = opendir(path); - if(!dir) - return false; + struct dirent *dirent = NULL; + DIR *dir = opendir(path); + if (!dir) + return false; - char *pathEndPtr = path + strlen(path); + char *pathEndPtr = path + strlen(path); - u32 tidHigh = strtoul(tidPtr, NULL, 16); - struct stat st; + u32 tidHigh = strtoul(tidPtr, NULL, 16); + struct stat st; - while ((dirent = readdir(dir)) != 0) - { - if(!dirent->d_name) - continue; + while ((dirent = readdir(dir)) != 0) + { + if (!dirent->d_name) + continue; - //these can't be booted anyways - if(*dirent->d_name == '.' || strcmp(dirent->d_name, "48414141") == 0 || strcmp(dirent->d_name, "48414641") == 0) - { - continue; - } + //these can't be booted anyways + if (*dirent->d_name == '.' || strcmp(dirent->d_name, "48414141") == 0 || strcmp(dirent->d_name, "48414641") == 0) + { + continue; + } - snprintf(pathEndPtr, 1024-(pathEndPtr-path), "/%s/content/title.tmd", dirent->d_name); + snprintf(pathEndPtr, 1024 - (pathEndPtr - path), "/%s/content/title.tmd", dirent->d_name); - if(stat(path, &st) != 0) - continue; + if (stat(path, &st) != 0) + continue; - // check if content in tmd exists - if(!emuExists(path)) - continue; - - u32 tidLow = strtoul(dirent->d_name, NULL, 16); - char id[5]; - memset(id, 0, sizeof(id)); - memcpy(id, &tidLow, 4); + // check if content in tmd exists + if (!emuExists(path)) + continue; - u64 tid = ((u64)tidHigh << 32) | ((u64) tidLow); + u32 tidLow = strtoul(dirent->d_name, NULL, 16); + char id[5]; + memset(id, 0, sizeof(id)); + memcpy(id, &tidLow, 4); - // Force old and new format to be "JODI" which is known by GameTDB - if(tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) - strcpy(id, "JODI"); + u64 tid = ((u64)tidHigh << 32) | ((u64)tidLow); - std::string TitleName; + // Force old and new format to be "JODI" which is known by GameTDB + if (tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) + strcpy(id, "JODI"); - const char *title = GameTitles.GetTitle(id); - if(title && *title != '\0') - { - TitleName = title; - } - else if(GetEmuChanTitle(path, language, TitleName)) - { - GameTitles.SetGameTitle(id, TitleName.c_str()); - } - else - { - TitleName = id; - } + std::string TitleName; - int s = EmuChannels.size(); - EmuChannels.resize(s + 1); - memset(&EmuChannels[s], 0, sizeof(struct discHdr)); - memcpy(EmuChannels[s].id, id, 4); - EmuChannels[s].tid = tid; - EmuChannels[s].type = TYPE_GAME_EMUNANDCHAN; - strncpy(EmuChannels[s].title, TitleName.c_str(), sizeof(EmuChannels[s].title)-1); - } + const char *title = GameTitles.GetTitle(id); + if (title && *title != '\0') + { + TitleName = title; + } + else if (GetEmuChanTitle(path, language, TitleName)) + { + GameTitles.SetGameTitle(id, TitleName.c_str()); + } + else + { + TitleName = id; + } - closedir(dir); + int s = EmuChannels.size(); + EmuChannels.resize(s + 1); + memset(&EmuChannels[s], 0, sizeof(struct discHdr)); + memcpy(EmuChannels[s].id, id, 4); + EmuChannels[s].tid = tid; + EmuChannels[s].type = TYPE_GAME_EMUNANDCHAN; + strncpy(EmuChannels[s].title, TitleName.c_str(), sizeof(EmuChannels[s].title) - 1); + } - return true; + closedir(dir); + + return true; } bool Channels::GetEmuChanTitle(char *tmdpath, int language, std::string &Title) { - u8 *buffer = NULL; - u32 size = 0; + u8 *buffer = NULL; + u32 size = 0; - if(LoadFileToMem(tmdpath, &buffer, &size) < 0) - return false; + if (LoadFileToMem(tmdpath, &buffer, &size) < 0) + return false; - signed_blob *s_tmd = (signed_blob *) buffer; + signed_blob *s_tmd = (signed_blob *)buffer; - u32 i; - tmd *titleTmd = (tmd *) SIGNATURE_PAYLOAD(s_tmd); + u32 i; + tmd *titleTmd = (tmd *)SIGNATURE_PAYLOAD(s_tmd); - for (i = 0; i < titleTmd->num_contents; i++) - if (!titleTmd->contents[i].index) - break; + for (i = 0; i < titleTmd->num_contents; i++) + if (!titleTmd->contents[i].index) + break; - if(i == titleTmd->num_contents) - { - free(buffer); - return false; - } + if (i == titleTmd->num_contents) + { + free(buffer); + return false; + } - u32 cid = titleTmd->contents[i].cid; + u32 cid = titleTmd->contents[i].cid; - free(buffer); + free(buffer); - char *ptr = strrchr(tmdpath, '/'); - if(!ptr) - return false; + char *ptr = strrchr(tmdpath, '/'); + if (!ptr) + return false; - //! tmdpath has length of 1024 - snprintf(ptr+1, 1024-(ptr+1-tmdpath), "%08x.app", (unsigned int)cid); + //! tmdpath has length of 1024 + snprintf(ptr + 1, 1024 - (ptr + 1 - tmdpath), "%08x.app", (unsigned int)cid); - FILE *f = fopen(tmdpath, "rb"); - if(!f) - return false; + FILE *f = fopen(tmdpath, "rb"); + if (!f) + return false; - if(fseek(f, IMET_OFFSET, SEEK_SET) != 0) - { - fclose(f); - return false; - } + if (fseek(f, IMET_OFFSET, SEEK_SET) != 0) + { + fclose(f); + return false; + } - IMET *imet = (IMET*) malloc(sizeof(IMET)); - if(!imet) - { - fclose(f); - return false; - } + IMET *imet = (IMET *)malloc(sizeof(IMET)); + if (!imet) + { + fclose(f); + return false; + } - if(fread(imet, 1, sizeof(IMET), f) != sizeof(IMET)) - { - free(imet); - fclose(f); - return false; - } + if (fread(imet, 1, sizeof(IMET), f) != sizeof(IMET)) + { + free(imet); + fclose(f); + return false; + } - fclose(f); + fclose(f); - if (imet->sig != IMET_SIGNATURE) - { - free(imet); - return false; - } + if (imet->sig != IMET_SIGNATURE) + { + free(imet); + return false; + } - // names not available - if (imet->name_japanese[language * IMET_MAX_NAME_LEN] == 0) - { - if(imet->name_english[0] != 0) - language = CONF_LANG_ENGLISH; - else - { - free(imet); - return false; - } - } + // names not available + if (imet->name_japanese[language * IMET_MAX_NAME_LEN] == 0) + { + if (imet->name_english[0] != 0) + language = CONF_LANG_ENGLISH; + else + { + free(imet); + return false; + } + } - wchar_t wName[IMET_MAX_NAME_LEN]; + wchar_t wName[IMET_MAX_NAME_LEN]; - // retrieve channel name in system language or on english - for (int i = 0; i < IMET_MAX_NAME_LEN; i++) - wName[i] = imet->name_japanese[i + (language * IMET_MAX_NAME_LEN)]; + // retrieve channel name in system language or on english + for (int i = 0; i < IMET_MAX_NAME_LEN; i++) + wName[i] = imet->name_japanese[i + (language * IMET_MAX_NAME_LEN)]; - wString wsname(wName); - Title = wsname.toUTF8(); + wString wsname(wName); + Title = wsname.toUTF8(); - free(imet); + free(imet); - return true; + return true; } -u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPrefix) +u8 *Channels::GetOpeningBnr(const u64 &title, u32 *outsize, const char *pathPrefix) { - u8 *banner = NULL; - u32 high = TITLE_UPPER(title); - u32 low = TITLE_LOWER(title); + u8 *banner = NULL; + u32 high = TITLE_UPPER(title); + u32 low = TITLE_LOWER(title); - char *filepath = (char *) memalign(32, ISFS_MAXPATH + strlen(pathPrefix)); - if(!filepath) - return NULL; + char *filepath = (char *)memalign(32, ISFS_MAXPATH + strlen(pathPrefix)); + if (!filepath) + return NULL; - do - { - snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/title.tmd", pathPrefix, (unsigned int)high, (unsigned int)low); + do + { + snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/title.tmd", pathPrefix, (unsigned int)high, (unsigned int)low); - u8 *buffer = NULL; - u32 filesize = 0; + u8 *buffer = NULL; + u32 filesize = 0; - int ret = 0; + int ret = 0; - if(pathPrefix && *pathPrefix != 0) - ret = LoadFileToMem(filepath, &buffer, &filesize); - else - ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); + if (pathPrefix && *pathPrefix != 0) + ret = LoadFileToMem(filepath, &buffer, &filesize); + else + ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); - if (ret < 0) - break; + if (ret < 0) + break; - _tmd * tmd_file = (_tmd *) SIGNATURE_PAYLOAD((u32 *)buffer); - bool found = false; - u32 bootcontent = 0; - for(u32 i = 0; i < tmd_file->num_contents; ++i) - { - if(tmd_file->contents[i].index == 0) - { - bootcontent = tmd_file->contents[i].cid; - found = true; - break; - } - } + _tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)buffer); + bool found = false; + u32 bootcontent = 0; + for (u32 i = 0; i < tmd_file->num_contents; ++i) + { + if (tmd_file->contents[i].index == 0) + { + bootcontent = tmd_file->contents[i].cid; + found = true; + break; + } + } - free(buffer); - buffer = NULL; - filesize = 0; + free(buffer); + buffer = NULL; + filesize = 0; - if(!found) - break; + if (!found) + break; - snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/%08x.app", pathPrefix, (unsigned int)high, (unsigned int)low, (unsigned int)bootcontent); + snprintf(filepath, ISFS_MAXPATH, "%s/title/%08x/%08x/content/%08x.app", pathPrefix, (unsigned int)high, (unsigned int)low, (unsigned int)bootcontent); - if(pathPrefix && *pathPrefix != 0) - ret = LoadFileToMem(filepath, &buffer, &filesize); - else - ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); + if (pathPrefix && *pathPrefix != 0) + ret = LoadFileToMem(filepath, &buffer, &filesize); + else + ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); - if (ret < 0) - break; + if (ret < 0) + break; - IMET *imet = (IMET *) (buffer + IMET_OFFSET); - if(imet->sig != 'IMET') - { - free(buffer); - break; - } + IMET *imet = (IMET *)(buffer + IMET_OFFSET); + if (imet->sig != 'IMET') + { + free(buffer); + break; + } - // move IMET_OFFSET bytes back - filesize -= IMET_OFFSET; + // move IMET_OFFSET bytes back + filesize -= IMET_OFFSET; - banner = (u8 *) memalign(32, filesize); - if(!banner) - { - free(buffer); - break; - } + banner = (u8 *)memalign(32, filesize); + if (!banner) + { + free(buffer); + break; + } - memcpy(banner, buffer + IMET_OFFSET, filesize); + memcpy(banner, buffer + IMET_OFFSET, filesize); - free(buffer); + free(buffer); - if(outsize) - *outsize = filesize; - } - while(0); + if (outsize) + *outsize = filesize; + } while (0); - free(filepath); + free(filepath); - return banner; + return banner; } diff --git a/source/GameCube/GCGames.cpp b/source/GameCube/GCGames.cpp index d15bfa02..23e42671 100644 --- a/source/GameCube/GCGames.cpp +++ b/source/GameCube/GCGames.cpp @@ -17,6 +17,7 @@ #include #include #include + #include "GCGames.h" #include "FileOperations/fileops.h" #include "settings/GameTitles.h" @@ -30,13 +31,14 @@ #include "system/IosLoader.h" #include "menu.h" #include "gecko.h" +#include "cache/cache.hpp" GCGames *GCGames::instance = NULL; inline bool isGameID(const u8 *id) { for (int i = 0; i < 6; i++) - if (!isalnum((int) id[i])) + if (!isalnum((int)id[i])) return false; return true; @@ -44,12 +46,12 @@ inline bool isGameID(const u8 *id) const char *GCGames::GetPath(const char *gameID) const { - if(!gameID) + if (!gameID) return ""; - for(u32 i = 0; i < HeaderList.size(); i++) + for (u32 i = 0; i < HeaderList.size(); i++) { - if(strncasecmp((const char *) HeaderList[i].id, gameID, 6) == 0) + if (strncasecmp((const char *)HeaderList[i].id, gameID, 6) == 0) return PathList[i].c_str(); } @@ -68,15 +70,17 @@ void GCGames::LoadGameList(const string &path, vector &headerLis struct dirent *dirent; dir_iter = opendir(path.c_str()); - if (!dir_iter) return; + if (!dir_iter) + return; while ((dirent = readdir(dir_iter)) != 0) { const char *dirname = dirent->d_name; - if(!dirname) + if (!dirname) continue; - if (dirname[0] == '.') continue; + if (dirname[0] == '.') + continue; // reset id and title memset(id, 0, sizeof(id)); @@ -87,7 +91,7 @@ void GCGames::LoadGameList(const string &path, vector &headerLis int len = strlen(dirname); if (len >= 8) { - if (Wbfs_Fat::CheckLayoutB((char *) dirname, len, id, fname_title)) + if (Wbfs_Fat::CheckLayoutB((char *)dirname, len, id, fname_title)) { // path/TITLE[GAMEID]/game.iso lay_b = true; @@ -97,42 +101,43 @@ void GCGames::LoadGameList(const string &path, vector &headerLis // path/GAMEID_TITLE/game.iso memcpy(id, dirname, 6); - if(isGameID(id)) + if (isGameID(id)) { lay_a = true; snprintf(fname_title, sizeof(fname_title), "%s", &dirname[7]); } } } - else if(len == 6 && isGameID((u8*)dirname)) { + else if (len == 6 && isGameID((u8 *)dirname)) + { memcpy(id, dirname, 6); lay_a = true; } - if(!lay_a && !lay_b) + if (!lay_a && !lay_b) memset(id, 0, sizeof(id)); bool found = false; bool extracted = false; - for(int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { char name[50]; - snprintf(name, sizeof(name), "%.6s.%s", (i % 2) == 0 ? "game" : (char *) id, i >= 2 ? "gcm" : "iso"); + snprintf(name, sizeof(name), "%.6s.%s", (i % 2) == 0 ? "game" : (char *)id, i >= 2 ? "gcm" : "iso"); snprintf(fpath, sizeof(fpath), "%s%s/%s", path.c_str(), dirname, name); - if((found = (stat(fpath, &st) == 0)) == true) + if ((found = (stat(fpath, &st) == 0)) == true) break; } // Check if only disc2.iso is present - if(!found) + if (!found) { - for(int i = 0; i < 2; i++) + for (int i = 0; i < 2; i++) { char name[50]; snprintf(name, sizeof(name), "disc2.%s", (i % 2) == 0 ? "gcm" : "iso"); // allow gcm, though DM(L) require "disc2.iso" filename snprintf(fpath, sizeof(fpath), "%s%s/%s", path.c_str(), dirname, name); - if((found = (stat(fpath, &st) == 0)) == true) + if ((found = (stat(fpath, &st) == 0)) == true) { disc_number = 1; break; @@ -140,17 +145,18 @@ void GCGames::LoadGameList(const string &path, vector &headerLis } } - if(!found) + if (!found) { snprintf(fpath, sizeof(fpath), "%s%s/sys/boot.bin", path.c_str(), dirname); - if(stat(fpath, &st) != 0) + if (stat(fpath, &st) != 0) continue; // this game is extracted extracted = true; } //! GAMEID was not found - if(!lay_a && !lay_b) { + if (!lay_a && !lay_b) + { // read game ID and title from disc header // iso file FILE *fp = fopen(fpath, "rb"); @@ -180,7 +186,7 @@ void GCGames::LoadGameList(const string &path, vector &headerLis string gamePath = string(path) + dirname + (extracted ? "/" : strrchr(fpath, '/')); memset(&tmpHdr, 0, sizeof(tmpHdr)); memcpy(tmpHdr.id, id, 6); - strncpy(tmpHdr.title, title, sizeof(tmpHdr.title)-1); + strncpy(tmpHdr.title, title, sizeof(tmpHdr.title) - 1); tmpHdr.magic = GCGames::MAGIC; tmpHdr.type = extracted ? TYPE_GAME_GC_EXTRACTED : TYPE_GAME_GC_IMG; tmpHdr.disc_no = disc_number; @@ -217,30 +223,38 @@ void GCGames::LoadGameList(const string &path, vector &headerLis u32 GCGames::LoadAllGames(void) { + if (Settings.UseGameHeaderCache && isCacheFile(GAMECUBE_HEADER_CACHE_FILE)) + { + if (HeaderList.empty() && PathList.empty()) + LoadGameHeaderCache(HeaderList, PathList); + if (!HeaderList.empty()) + return (int)HeaderList.size(); + } + PathList.clear(); HeaderList.clear(); sdGCList.clear(); sdGCPathList.clear(); - if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0 || Settings.GameCubeSource != GC_SOURCE_SD) + if (strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0 || Settings.GameCubeSource != GC_SOURCE_SD) LoadGameList(Settings.GameCubePath, HeaderList, PathList); - if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0 && (Settings.GameCubeSource != GC_SOURCE_MAIN)) + if (strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) != 0 && (Settings.GameCubeSource != GC_SOURCE_MAIN)) { LoadGameList(Settings.GameCubeSDPath, sdGCList, sdGCPathList); - for(u32 i = 0; i < sdGCList.size(); ++i) + for (u32 i = 0; i < sdGCList.size(); ++i) { - if(Settings.GameCubeSource != GC_SOURCE_SD) + if (Settings.GameCubeSource != GC_SOURCE_SD) { u32 n; - for(n = 0; n < HeaderList.size(); ++n) + for (n = 0; n < HeaderList.size(); ++n) { //! Display only one game if it is present on both SD and USB. - if(memcmp(HeaderList[n].id, sdGCList[i].id, 6) == 0) + if (memcmp(HeaderList[n].id, sdGCList[i].id, 6) == 0) { - if((Settings.GameCubeSource == GC_SOURCE_MAIN_SD) || - (Settings.GameCubeSource == GC_SOURCE_AUTO && (IosLoader::GetMIOSInfo() == DIOS_MIOS || IosLoader::GetMIOSInfo() == QUADFORCE_USB))) // DIOS MIOS - Show the game on USB in priority + if ((Settings.GameCubeSource == GC_SOURCE_MAIN_SD) || + (Settings.GameCubeSource == GC_SOURCE_AUTO && (IosLoader::GetMIOSInfo() == DIOS_MIOS || IosLoader::GetMIOSInfo() == QUADFORCE_USB))) // DIOS MIOS - Show the game on USB in priority { break; } @@ -254,43 +268,47 @@ u32 GCGames::LoadAllGames(void) } // Not available in the main GC path - if(n == HeaderList.size()) { + if (n == HeaderList.size()) + { HeaderList.push_back(sdGCList[i]); PathList.push_back(sdGCPathList[i]); } } else // GC_SOURCE_SD { - HeaderList.push_back(sdGCList[i]); - PathList.push_back(sdGCPathList[i]); - } + HeaderList.push_back(sdGCList[i]); + PathList.push_back(sdGCPathList[i]); + } } } + if (Settings.UseGameHeaderCache && !HeaderList.empty() && !PathList.empty()) + SaveGameHeaderCache(HeaderList, PathList); + return HeaderList.size(); } bool GCGames::RemoveGame(const char *gameID) { const char *path = GetPath(gameID); - if(*path == 0) + if (*path == 0) return false; RemoveSDGame(gameID); - if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0) + if (strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0) return true; struct discHdr *header = NULL; - for(u32 i = 0; i < HeaderList.size(); ++i) + for (u32 i = 0; i < HeaderList.size(); ++i) { - if(strncmp(gameID, (char*)HeaderList[i].id, 6) == 0) + if (strncmp(gameID, (char *)HeaderList[i].id, 6) == 0) { header = &HeaderList[i]; break; } } - if(!header) + if (!header) return false; char filepath[512]; @@ -300,24 +318,25 @@ bool GCGames::RemoveGame(const char *gameID) char cIsoPath[256]; snprintf(cIsoPath, sizeof(cIsoPath), "%s", path + strlen(Settings.GameCubeSDPath)); - if(header->type == TYPE_GAME_GC_IMG) + if (header->type == TYPE_GAME_GC_IMG) { // Remove game iso snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath); - if(!RemoveFile(filepath)) + if (!RemoveFile(filepath)) result = -1; // Remove path char *pathPtr = strrchr(filepath, '/'); - if(pathPtr) *pathPtr = 0; - if(!RemoveFile(filepath)) + if (pathPtr) + *pathPtr = 0; + if (!RemoveFile(filepath)) result = -1; } - else if(header->type == TYPE_GAME_GC_EXTRACTED) + else if (header->type == TYPE_GAME_GC_EXTRACTED) { //! remove extracted gamecube game snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath); - if(!RemoveDirectory(path)) + if (!RemoveDirectory(path)) result = -1; } @@ -327,45 +346,46 @@ bool GCGames::RemoveGame(const char *gameID) bool GCGames::RemoveSDGame(const char *gameID) { const char *path = GetPath(gameID); - if(*path == 0) + if (*path == 0) return false; struct discHdr *header = NULL; - for(u32 i = 0; i < HeaderList.size(); ++i) + for (u32 i = 0; i < HeaderList.size(); ++i) { - if(strncmp(gameID, (char*)HeaderList[i].id, 6) == 0) + if (strncmp(gameID, (char *)HeaderList[i].id, 6) == 0) { header = &HeaderList[i]; break; } } - if(!header) + if (!header) return false; char filepath[512]; int result = 0; int ret; - if(header->type == TYPE_GAME_GC_IMG) + if (header->type == TYPE_GAME_GC_IMG) { // Remove game iso snprintf(filepath, sizeof(filepath), "%s", path); ret = RemoveFile(filepath); - if(ret != 0) + if (ret != 0) result = -1; // Remove path char *pathPtr = strrchr(filepath, '/'); - if(pathPtr) *pathPtr = 0; + if (pathPtr) + *pathPtr = 0; ret = RemoveFile(filepath); - if(ret != 0) + if (ret != 0) result = -1; } - else if(header->type == TYPE_GAME_GC_EXTRACTED) + else if (header->type == TYPE_GAME_GC_EXTRACTED) { //! remove extracted gamecube game ret = RemoveDirectory(path); - if(ret < 0) + if (ret < 0) result = -1; } @@ -375,39 +395,39 @@ bool GCGames::RemoveSDGame(const char *gameID) float GCGames::GetGameSize(const char *gameID) { const char *path = GetPath(gameID); - if(*path == 0) + if (*path == 0) return 0.0f; struct stat st; - if(stat(path, &st) != 0) + if (stat(path, &st) != 0) return 0.0f; - return ((float) st.st_size / GB_SIZE); + return ((float)st.st_size / GB_SIZE); } bool GCGames::IsInstalled(const char *gameID, u8 disc_number) const { - for(u32 n = 0; n < HeaderList.size(); n++) + for (u32 n = 0; n < HeaderList.size(); n++) { - if(memcmp(HeaderList[n].id, gameID, 6) == 0) + if (memcmp(HeaderList[n].id, gameID, 6) == 0) { - if(HeaderList[n].type == TYPE_GAME_GC_EXTRACTED || Settings.GCInstallCompressed) + if (HeaderList[n].type == TYPE_GAME_GC_EXTRACTED || Settings.GCInstallCompressed) return true; // Multi-disc games in extracted form are currently unsupported by DML, no need to check further. - - if(HeaderList[n].disc_no == disc_number) // Disc number already in headerList. If Disc2 is loaded in headerList, then Disc1 is not installed yet + + if (HeaderList[n].disc_no == disc_number) // Disc number already in headerList. If Disc2 is loaded in headerList, then Disc1 is not installed yet { return true; } - else if(disc_number == 1) // Check if the second Game Disc exists in the same folder than Disc1. + else if (disc_number == 1) // Check if the second Game Disc exists in the same folder than Disc1. { char filepath[512]; int n = snprintf(filepath, sizeof(filepath), "%s", GetPath(gameID)); char *pathPtr = strrchr(filepath, '/'); - if(pathPtr) *pathPtr = 0; + if (pathPtr) + *pathPtr = 0; snprintf(filepath + n, sizeof(filepath) - n, "/disc2.iso"); - - if(CheckFile(filepath)) + if (CheckFile(filepath)) return true; } } @@ -417,18 +437,18 @@ bool GCGames::IsInstalled(const char *gameID, u8 disc_number) const bool GCGames::CopyUSB2SD(const struct discHdr *header) { - const char *path = GetPath((char*)header->id); + const char *path = GetPath((char *)header->id); int oldGameCubeSource = Settings.GameCubeSource; - if(*path == 0) + if (*path == 0) return false; int choice = WindowPrompt(tr("The game is on USB."), tr("Do you want to copy the game to SD or delete a game on SD?"), tr("Copy"), tr("Show SD"), tr("Cancel")); - if(choice == 0) + if (choice == 0) return false; const char *cpTitle = GameTitles.GetTitle(header); - - if(choice == 2) + + if (choice == 2) { // Load Games from SD card only Settings.GameCubeSource = GC_SOURCE_SD; @@ -443,7 +463,8 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header) gcDeleteMenu.Show(); gcDeleteMenu.SetEffect(EFFECT_FADE, -20); - while(gcDeleteMenu.GetEffect() > 0) usleep(1000); + while (gcDeleteMenu.GetEffect() > 0) + usleep(1000); mainWindow->Remove(&gcDeleteMenu); mainWindow->SetState(STATE_DEFAULT); @@ -452,12 +473,12 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header) Settings.GameCubeSource = oldGameCubeSource; GCGames::Instance()->LoadAllGames(); - if(!WindowPrompt(tr("Do you want to copy now?"), cpTitle, tr("Yes"), tr("Cancel"))) + if (!WindowPrompt(tr("Do you want to copy now?"), cpTitle, tr("Yes"), tr("Cancel"))) return false; } struct statvfs sd_vfs; - if(statvfs(Settings.GameCubeSDPath, &sd_vfs) != 0) + if (statvfs(Settings.GameCubeSDPath, &sd_vfs) != 0) { WindowPrompt(tr("Error:"), tr("SD Card could not be accessed."), tr("OK")); return false; @@ -465,20 +486,22 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header) u64 filesize = 0; - if(header->type == TYPE_GAME_GC_IMG) { + if (header->type == TYPE_GAME_GC_IMG) + { filesize = FileSize(path); } - else if(header->type == TYPE_GAME_GC_EXTRACTED) { + else if (header->type == TYPE_GAME_GC_EXTRACTED) + { StartProgress(tr("Getting game folder size..."), tr("Please wait"), 0, true, true); ShowProgress(0, 1); filesize = FileSize(path); ProgressStop(); } - while(((u64)sd_vfs.f_frsize * (u64)sd_vfs.f_bfree) < filesize) + while (((u64)sd_vfs.f_frsize * (u64)sd_vfs.f_bfree) < filesize) { choice = WindowPrompt(tr("Error: Not enough space on SD."), tr("Do you want to delete a game on SD?"), tr("Yes"), tr("Cancel")); - if(choice == 0) + if (choice == 0) return false; GCDeleteMenu gcDeleteMenu; @@ -490,7 +513,8 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header) gcDeleteMenu.Show(); gcDeleteMenu.SetEffect(EFFECT_FADE, -20); - while(gcDeleteMenu.GetEffect() > 0) usleep(1000); + while (gcDeleteMenu.GetEffect() > 0) + usleep(1000); mainWindow->Remove(&gcDeleteMenu); mainWindow->SetState(STATE_DEFAULT); @@ -504,13 +528,14 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header) int res = -1; - if(header->type == TYPE_GAME_GC_IMG) + if (header->type == TYPE_GAME_GC_IMG) { ProgressCancelEnable(true); StartProgress(tr("Copying GC game..."), cpTitle, 0, true, true); char *ptr = strrchr(destPath, '/'); - if(ptr) *ptr = 0; + if (ptr) + *ptr = 0; CreateSubfolder(destPath); @@ -518,7 +543,7 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header) res = CopyFile(path, destPath); } - else if(header->type == TYPE_GAME_GC_EXTRACTED) + else if (header->type == TYPE_GAME_GC_EXTRACTED) { res = CopyDirectory(path, destPath); } @@ -529,28 +554,30 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header) ProgressStop(); ProgressCancelEnable(false); - if(res == PROGRESS_CANCELED) + if (res == PROGRESS_CANCELED) { - if(header->type == TYPE_GAME_GC_IMG) + if (header->type == TYPE_GAME_GC_IMG) { // remove file and path RemoveFile(destPath); char *ptr = strrchr(destPath, '/'); - if(ptr) *ptr = 0; + if (ptr) + *ptr = 0; RemoveFile(destPath); } WindowPrompt(tr("Copying Canceled"), 0, tr("OK")); return false; } - else if(res < 0) + else if (res < 0) { - if(header->type == TYPE_GAME_GC_IMG) + if (header->type == TYPE_GAME_GC_IMG) { // remove file and path RemoveFile(destPath); char *ptr = strrchr(destPath, '/'); - if(ptr) *ptr = 0; + if (ptr) + *ptr = 0; RemoveFile(destPath); } @@ -568,53 +595,53 @@ int nintendontBuildDate(const char *NIN_loader_path, char *NINBuildDate) char NIN_loader[100]; snprintf(NIN_loader, sizeof(NIN_loader), "%sboot.dol", NIN_loader_path); - if(!CheckFile(NIN_loader)) + if (!CheckFile(NIN_loader)) snprintf(NIN_loader, sizeof(NIN_loader), "%sloader.dol", NIN_loader_path); - if(CheckFile(NIN_loader)) + if (CheckFile(NIN_loader)) { u8 *buffer = NULL; u32 filesize = 0; - const char* str = "Nintendont Loader"; + const char *str = "Nintendont Loader"; bool found = false; - if(LoadFileToMem(NIN_loader, &buffer, &filesize)) + if (LoadFileToMem(NIN_loader, &buffer, &filesize)) { - for(u32 i = 0; i < filesize-100; ++i) + for (u32 i = 0; i < filesize - 100; ++i) { - if( memcmp(buffer+i, str, strlen(str)) == 0) + if (memcmp(buffer + i, str, strlen(str)) == 0) { // Write buffer in NINheader char NINHeader[100]; - for(u8 j = 0 ; j < 99 ; j++) - NINHeader[j] = *(u8*)(buffer+i+j) == 0 ? ' ' : *(u8*)(buffer+i+j); // replace \0 with a space. + for (u8 j = 0; j < 99; j++) + NINHeader[j] = *(u8 *)(buffer + i + j) == 0 ? ' ' : *(u8 *)(buffer + i + j); // replace \0 with a space. NINHeader[99] = '\0'; // Search month string start position in header char *dateStart = NULL; const char *month[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jui ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "}; - for(u8 m = 0 ; m < 12 ; m++) + for (u8 m = 0; m < 12; m++) { dateStart = strstr(NINHeader, month[m]); - if(dateStart != NULL) + if (dateStart != NULL) break; } - if(dateStart == NULL) + if (dateStart == NULL) break; - + dateStart[20] = '\0'; - + sprintf(NINBuildDate, "%.20s", dateStart); gprintf("Nintendont Build date : %.20s \n", dateStart); - + found = true; break; } } free(buffer); } - if(found) + if (found) return 1; } - + return 0; } @@ -623,28 +650,28 @@ int nintendontVersion(const char *NIN_loader_path, char *NINVersion, int len) char NIN_loader[100]; u32 NINRev = 0; snprintf(NIN_loader, sizeof(NIN_loader), "%sboot.dol", NIN_loader_path); - if(!CheckFile(NIN_loader)) + if (!CheckFile(NIN_loader)) snprintf(NIN_loader, sizeof(NIN_loader), "%sloader.dol", NIN_loader_path); - if(CheckFile(NIN_loader)) + if (CheckFile(NIN_loader)) { u8 *buffer = NULL; u32 filesize = 0; - const char* str = "$$Version:"; - if(LoadFileToMem(NIN_loader, &buffer, &filesize)) + const char *str = "$$Version:"; + if (LoadFileToMem(NIN_loader, &buffer, &filesize)) { - for(u32 i = 0; i < filesize; i += 32) + for (u32 i = 0; i < filesize; i += 32) { - if(memcmp( buffer+i, str, strlen(str)) == 0) + if (memcmp(buffer + i, str, strlen(str)) == 0) { // Write buffer in NINVersion - snprintf(NINVersion, len, "%s", buffer+i+strlen(str)); - NINRev = atoi(strchr(NINVersion, '.')+1); + snprintf(NINVersion, len, "%s", buffer + i + strlen(str)); + NINRev = atoi(strchr(NINVersion, '.') + 1); break; } } free(buffer); } } - + return NINRev; } diff --git a/source/cache/cache.cpp b/source/cache/cache.cpp new file mode 100644 index 00000000..12ad497a --- /dev/null +++ b/source/cache/cache.cpp @@ -0,0 +1,338 @@ +/* + Code by Oddx @ GBAtemp.net + Loosely based on emuNAND caching by geoGolem. +*/ +#include +#include + +#include "cache.hpp" +#include "usbloader/disc.h" +#include "settings/CSettings.h" +#include "FileOperations/fileops.h" +#include "memory/memory.h" +#include "Channels/channels.h" +#include "usbloader/GameList.h" +#include "GameCube/GCGames.h" + +void ResetGameHeaderCache() +{ + RemoveDirectory(Settings.GameHeaderCachePath); + return; +} + +// emuNAND +void SaveGameHeaderCache(vector &list) +{ + string path = string(Settings.GameHeaderCachePath) + EMUNAND_HEADER_CACHE_FILE; + + if (!CheckFile(Settings.GameHeaderCachePath)) + CreateSubfolder(Settings.GameHeaderCachePath); + + FILE *cache = fopen(path.c_str(), "wb"); + + if (!cache) + return; + + fwrite((void *)&list[0], 1, list.size() * sizeof(struct discHdr), cache); + + fclose(cache); +} + +void LoadGameHeaderCache(vector &list) +{ + string path = string(Settings.GameHeaderCachePath) + EMUNAND_HEADER_CACHE_FILE; + + FILE *cache = fopen(path.c_str(), "rb"); + + if (!cache) + return; + + struct discHdr tmp; + fseek(cache, 0, SEEK_END); + u64 fileSize = ftell(cache); + fseek(cache, 0, SEEK_SET); + + u32 count = (u32)(fileSize / sizeof(struct discHdr)); + + list.reserve(count + list.size()); + for (u32 i = 0; i < count; i++) + { + fseek(cache, i * sizeof(struct discHdr), SEEK_SET); + fread((void *)&tmp, 1, sizeof(struct discHdr), cache); + list.push_back(tmp); + } + + fclose(cache); +} + +// Wii +void SaveGameHeaderCache(vector &list, vector &plist) +{ + vector wiictmp; + struct wiiCache gtmp; + + for (u32 i = 0; i < list.size(); ++i) + { + memset(>mp, 0, sizeof(struct wiiCache)); + gtmp.header = list[i]; + gtmp.part = plist[i]; + wiictmp.push_back(gtmp); + } + + string path = string(Settings.GameHeaderCachePath) + WII_HEADER_CACHE_FILE; + + if (!CheckFile(Settings.GameHeaderCachePath)) + CreateSubfolder(Settings.GameHeaderCachePath); + + FILE *cache = fopen(path.c_str(), "wb"); + + if (!cache) + return; + + fwrite((void *)&wiictmp[0], 1, wiictmp.size() * sizeof(struct wiiCache), cache); + + fclose(cache); +} + +void LoadGameHeaderCache(vector &list, vector &plist) +{ + string path = string(Settings.GameHeaderCachePath) + WII_HEADER_CACHE_FILE; + + FILE *cache = fopen(path.c_str(), "rb"); + + if (!cache) + return; + + struct wiiCache wiictmp; + fseek(cache, 0, SEEK_END); + u64 fileSize = ftell(cache); + fseek(cache, 0, SEEK_SET); + + u32 count = (u32)(fileSize / sizeof(struct wiiCache)); + + list.reserve(count + list.size()); + plist.reserve(count + plist.size()); + for (u32 i = 0; i < count; i++) + { + fseek(cache, i * sizeof(struct wiiCache), SEEK_SET); + fread((void *)&wiictmp, 1, sizeof(struct wiiCache), cache); + list.push_back(wiictmp.header); + plist.push_back(wiictmp.part); + } + + fclose(cache); +} + +// GameCube +void SaveGameHeaderCache(vector &list, vector &plist) +{ + vector gcctmp; + struct gcCache gtmp; + + for (u32 i = 0; i < list.size(); ++i) + { + memset(>mp, 0, sizeof(gcCache)); + gtmp.header = list[i]; + + strcpy((char *)gtmp.path, plist[i].c_str()); + + gcctmp.push_back(gtmp); + } + + string path = string(Settings.GameHeaderCachePath) + GAMECUBE_HEADER_CACHE_FILE; + + if (!CheckFile(Settings.GameHeaderCachePath)) + CreateSubfolder(Settings.GameHeaderCachePath); + + FILE *cache = fopen(path.c_str(), "wb"); + + if (!cache) + return; + + fwrite((void *)&gcctmp[0], 1, gcctmp.size() * sizeof(struct gcCache), cache); + + fclose(cache); +} + +void LoadGameHeaderCache(vector &list, vector &plist) +{ + string path = string(Settings.GameHeaderCachePath) + GAMECUBE_HEADER_CACHE_FILE; + + FILE *cache = fopen(path.c_str(), "rb"); + + if (!cache) + return; + + struct gcCache gcctmp; + fseek(cache, 0, SEEK_END); + u64 fileSize = ftell(cache); + fseek(cache, 0, SEEK_SET); + + u32 count = (u32)(fileSize / sizeof(struct gcCache)); + + list.reserve(count + list.size()); + plist.reserve(count + plist.size()); + for (u32 i = 0; i < count; i++) + { + fseek(cache, i * sizeof(struct gcCache), SEEK_SET); + fread((void *)&gcctmp, 1, sizeof(struct gcCache), cache); + list.push_back(gcctmp.header); + + string tmp((char *)gcctmp.path); + plist.push_back(tmp); + } + fclose(cache); +} + +void SaveFilteredListCache(vector &list, const wchar_t *gameFilter) +{ + string path = string(Settings.GameHeaderCachePath) + FilteredListCacheFileName(gameFilter); + + if (!CheckFile(Settings.GameHeaderCachePath)) + CreateSubfolder(Settings.GameHeaderCachePath); + + FILE *cache = fopen(path.c_str(), "wb"); + + if (!cache) + return; + + vector tmplist; + struct gameHdr tmp; + + for (u32 i = 0; i < list.size(); ++i) + { + memcpy(tmp.id, list[i]->id, 6); + tmplist.push_back(tmp); + } + + fwrite((void *)&tmplist[0], 1, tmplist.size() * sizeof(struct gameHdr), cache); + fclose(cache); +} + +void LoadFilteredListCache(vector &list, const wchar_t *gameFilter) +{ + string path = string(Settings.GameHeaderCachePath) + FilteredListCacheFileName(gameFilter); + + if (!CheckFile(Settings.GameHeaderCachePath)) + CreateSubfolder(Settings.GameHeaderCachePath); + + FILE *cache = fopen(path.c_str(), "rb"); + + if (!cache) + return; + + struct gameHdr tmp; + + fseek(cache, 0, SEEK_END); + u64 fileSize = ftell(cache); + fseek(cache, 0, SEEK_SET); + + u32 count = (u32)(fileSize / sizeof(struct gameHdr)); + + list.reserve(count + list.size()); + for (u32 i = 0; i < count; i++) + { + bool found = false; + fseek(cache, i * sizeof(struct gameHdr), SEEK_SET); + fread((void *)&tmp, 1, sizeof(struct gameHdr), cache); + + if (!found) + { + vector &tmplist = gameList.GetFullGameList(); + for (u32 c = 0; c < tmplist.size(); ++c) + { + struct discHdr *header = &tmplist[c]; + if (strncasecmp((const char *)tmp.id, (const char *)header->id, 6) == 0) + { + list.push_back(header); + found = true; + break; + } + } + } + + if (!found) + { + vector &tmplist = GCGames::Instance()->GetHeaders(); + for (u32 c = 0; c < tmplist.size(); ++c) + { + struct discHdr *header = &tmplist[c]; + if (strncasecmp((const char *)tmp.id, (const char *)header->id, 6) == 0) + { + list.push_back(header); + found = true; + break; + } + } + } + + if (!found) + { + vector &tmplist = Channels::Instance()->GetNandHeaders(); + for (u32 c = 0; c < tmplist.size(); ++c) + { + struct discHdr *header = &tmplist[c]; + if (strncasecmp((const char *)tmp.id, (const char *)header->id, 6) == 0) + { + list.push_back(header); + found = true; + break; + } + } + } + + if (!found) + { + vector &tmplist = Channels::Instance()->GetEmuHeaders(); + for (u32 c = 0; c < tmplist.size(); ++c) + { + struct discHdr *header = &tmplist[c]; + if (strncasecmp((const char *)tmp.id, (const char *)header->id, 6) == 0) + { + list.push_back(header); + found = true; + break; + } + } + } + } + + fclose(cache); +} + +string FilteredListCacheFileName(const wchar_t *gameFilter) +{ + string tmp; + tmp = "FL"; + tmp += "_" + to_string(Settings.LoaderMode); + tmp += "_" + to_string(Settings.GameSort); + if (gameFilter) + { + wstring ws(gameFilter); + string gf(ws.begin(), ws.end()); + if ((gf.length()) > 0) + tmp += "_" + gf; + } + tmp += ".cache"; + return tmp; +} + +string FilteredListCacheFileName() +{ + string tmp; + tmp = "FL"; + tmp += "_" + to_string(Settings.LoaderMode); + tmp += "_" + to_string(Settings.GameSort); + tmp += ".cache"; + return tmp; +} + +bool isCacheFile(string filename) +{ + string path = string(Settings.GameHeaderCachePath) + filename; + + if (CheckFile(path.c_str())) + return true; + + return false; +} diff --git a/source/cache/cache.hpp b/source/cache/cache.hpp new file mode 100644 index 00000000..394ab64e --- /dev/null +++ b/source/cache/cache.hpp @@ -0,0 +1,54 @@ +/* + Code by Oddx @ GBAtemp.net + Loosely based on emuNAND caching by geoGolem. +*/ +#include "usbloader/disc.h" +#include "settings/CSettings.h" + +#define WII_HEADER_CACHE_FILE "WII.cache" +#define GAMECUBE_HEADER_CACHE_FILE "GAMECUBE.cache" +#define EMUNAND_HEADER_CACHE_FILE "EMUNAND.cache" + +using namespace std; + +struct gameHdr +{ + /* Game ID */ + u8 id[6]; + + /* Padding */ + u8 unused3[2]; +}; + +struct wiiCache +{ + struct discHdr header; + int part; +}; + +struct gcCache +{ + struct discHdr header; + u8 path[200]; +}; + +// emuNAND +void SaveGameHeaderCache(vector &list); +void LoadGameHeaderCache(vector &list); + +// Wii +void SaveGameHeaderCache(vector &list, vector &plist); +void LoadGameHeaderCache(vector &list, vector &plist); + +// GameCube +void SaveGameHeaderCache(vector &list, vector &plist); +void LoadGameHeaderCache(vector &list, vector &plist); + +void ResetGameHeaderCache(); + +void SaveFilteredListCache(vector &list, const wchar_t *gameFilter); +void LoadFilteredListCache(vector &list, const wchar_t *gameFilter); + +string FilteredListCacheFileName(const wchar_t *gameFilter); +string FilteredListCacheFileName(); +bool isCacheFile(string filename); diff --git a/source/menu/menu_install.cpp b/source/menu/menu_install.cpp index 26ccd29b..a7a97615 100644 --- a/source/menu/menu_install.cpp +++ b/source/menu/menu_install.cpp @@ -11,6 +11,7 @@ #include "themes/CTheme.h" #include "utils/tools.h" #include "system/IosLoader.h" +#include "cache/cache.hpp" #define WII_MAGIC 0x5D1C9EA3 @@ -287,6 +288,7 @@ int MenuInstall() else { ShowProgress(tr("Install finished"), headerdisc.title, tr("Reloading game list now, please wait..."), gamesize, gamesize, true, true); + ResetGameHeaderCache(); gameList.ReadGameList(); //get the entries again gameList.FilterList(); bgMusic->Pause(); diff --git a/source/settings/CSettings.cpp b/source/settings/CSettings.cpp index 336c8e55..0f34d0e4 100644 --- a/source/settings/CSettings.cpp +++ b/source/settings/CSettings.cpp @@ -63,6 +63,7 @@ void CSettings::SetDefault() snprintf(languagefiles_path, sizeof(languagefiles_path), "%slanguage/", ConfigPath); snprintf(update_path, sizeof(update_path), "%s/apps/usbloader_gx/", BootDevice); snprintf(BNRCachePath, sizeof(BNRCachePath), "%s/apps/usbloader_gx/cache_bnr/", BootDevice); + snprintf(GameHeaderCachePath, sizeof(GameHeaderCachePath), "%s/apps/usbloader_gx/cache/", BootDevice); snprintf(homebrewapps_path, sizeof(homebrewapps_path), "%s/apps/", BootDevice); snprintf(Cheatcodespath, sizeof(Cheatcodespath), "%s/codes/", BootDevice); snprintf(TxtCheatcodespath, sizeof(TxtCheatcodespath), "%s/txtcodes/", BootDevice); @@ -135,6 +136,7 @@ void CSettings::SetDefault() musicloopmode = ON; marknewtitles = ON; ShowFreeSpace = ON; + UseGameHeaderCache = OFF; PlaylogUpdate = OFF; ParentalBlocks = BLOCK_ALL; InstallToDir = INSTALL_TO_NAME_GAMEID; @@ -359,6 +361,7 @@ bool CSettings::Save() fprintf(file, "update_path = %s\n", update_path); fprintf(file, "homebrewapps_path = %s\n", homebrewapps_path); fprintf(file, "BNRCachePath = %s\n", BNRCachePath); + fprintf(file, "GameHeaderCachePath = %s\n", GameHeaderCachePath); fprintf(file, "Cheatcodespath = %s\n", Cheatcodespath); fprintf(file, "BcaCodepath = %s\n", BcaCodepath); fprintf(file, "WipCodepath = %s\n", WipCodepath); @@ -374,6 +377,7 @@ bool CSettings::Save() fprintf(file, "partition = %d\n", partition); fprintf(file, "marknewtitles = %d\n", marknewtitles); fprintf(file, "ShowFreeSpace = %d\n", ShowFreeSpace); + fprintf(file, "UseGameHeaderCache = %d\n", UseGameHeaderCache); fprintf(file, "InstallToDir = %d\n", InstallToDir); fprintf(file, "GameSplit = %d\n", GameSplit); fprintf(file, "InstallPartitions = %08X\n", (unsigned int)InstallPartitions); @@ -724,6 +728,11 @@ bool CSettings::SetSetting(char *name, char *value) ShowFreeSpace = atoi(value); return true; } + else if (strcmp(name, "UseGameHeaderCache") == 0) + { + UseGameHeaderCache = atoi(value); + return true; + } else if (strcmp(name, "HomeMenu") == 0) { HomeMenu = atoi(value); @@ -1238,6 +1247,11 @@ bool CSettings::SetSetting(char *name, char *value) strlcpy(BNRCachePath, value, sizeof(BNRCachePath)); return true; } + else if (strcmp(name, "GameHeaderCachePath") == 0) + { + strlcpy(GameHeaderCachePath, value, sizeof(GameHeaderCachePath)); + return true; + } else if (strcmp(name, "Cheatcodespath") == 0) { strlcpy(Cheatcodespath, value, sizeof(Cheatcodespath)); diff --git a/source/settings/CSettings.h b/source/settings/CSettings.h index 147dcf81..ff3f4474 100644 --- a/source/settings/CSettings.h +++ b/source/settings/CSettings.h @@ -85,6 +85,7 @@ class CSettings char NandEmuPath[50]; char NandEmuChanPath[50]; char BNRCachePath[50]; + char GameHeaderCachePath[50]; char GameCubePath[100]; char GameCubeSDPath[100]; char DEVOLoaderPath[100]; @@ -142,6 +143,7 @@ class CSettings short GameSplit; short PlaylogUpdate; short ShowFreeSpace; + short UseGameHeaderCache; short HomeMenu; short MultiplePartitions; short USBPort; diff --git a/source/settings/menus/CustomPathsSM.cpp b/source/settings/menus/CustomPathsSM.cpp index cd76f992..c1b8a6c4 100644 --- a/source/settings/menus/CustomPathsSM.cpp +++ b/source/settings/menus/CustomPathsSM.cpp @@ -65,6 +65,7 @@ CustomPathsSM::CustomPathsSM() Options->SetName(Idx++, tr("Devolution Loader Path")); Options->SetName(Idx++, tr("Nintendont Loader Path")); Options->SetName(Idx++, tr("Cache BNR Files Path")); + Options->SetName(Idx++, tr("Game Header Cache Files Path")); SetOptionValues(); } @@ -141,6 +142,9 @@ void CustomPathsSM::SetOptionValues() //! Settings: Cache BNR Files Path Options->SetValue(Idx++, Settings.BNRCachePath); + + //! Settings: Game Header Cache Files Path + Options->SetValue(Idx++, Settings.GameHeaderCachePath); } int CustomPathsSM::GetMenuInternal() @@ -368,6 +372,13 @@ int CustomPathsSM::GetMenuInternal() ChangePath(Settings.BNRCachePath, sizeof(Settings.BNRCachePath)); } + //! Settings: Game Header Cache Files Path + else if (ret == ++Idx) + { + titleTxt->SetText(tr( "Game Header Cache Files Path" )); + ChangePath(Settings.GameHeaderCachePath, sizeof(Settings.GameHeaderCachePath)); + } + //! Global set back of the titleTxt after a change titleTxt->SetText(tr( "Custom Paths" )); SetOptionValues(); diff --git a/source/settings/menus/FeatureSettingsMenu.cpp b/source/settings/menus/FeatureSettingsMenu.cpp index 88143018..2123ce98 100644 --- a/source/settings/menus/FeatureSettingsMenu.cpp +++ b/source/settings/menus/FeatureSettingsMenu.cpp @@ -24,6 +24,7 @@ #include #include #include + #include "FeatureSettingsMenu.hpp" #include "Channels/channels.h" #include "settings/CGameCategories.hpp" @@ -44,6 +45,7 @@ #include "wad/nandtitle.h" #include "wad/wad.h" #include "sys.h" +#include "cache/cache.hpp" static const char * OnOffText[] = { @@ -64,6 +66,7 @@ FeatureSettingsMenu::FeatureSettingsMenu() int Idx = 0; Options->SetName(Idx++, "%s", tr( "Titles from GameTDB" )); Options->SetName(Idx++, "%s", tr( "Cache Titles" )); + Options->SetName(Idx++, "%s", tr( "Use Game Header Cache" )); Options->SetName(Idx++, "%s", tr( "Force Titles from Disc" )); Options->SetName(Idx++, "%s", tr( "Wiilight" )); Options->SetName(Idx++, "%s", tr( "Rumble" )); @@ -80,6 +83,7 @@ FeatureSettingsMenu::FeatureSettingsMenu() // Options->SetName(Idx++, "%s", tr( "Update Nintendont" )); Options->SetName(Idx++, "%s", tr( "WiiU Widescreen" )); Options->SetName(Idx++, "%s", tr( "Boot Neek System Menu" )); + Options->SetName(Idx++, "%s", tr( "Reset Game Header Cache" )); OldTitlesOverride = Settings.titlesOverride; OldCacheTitles = Settings.CacheTitles; @@ -121,6 +125,9 @@ void FeatureSettingsMenu::SetOptionValues() //! Settings: Cache Titles Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.CacheTitles] )); + //! Settings: Use Game Header Cache + Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.UseGameHeaderCache] )); + //! Settings: Force Titles from Disc Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.ForceDiscTitles] )); @@ -193,6 +200,12 @@ int FeatureSettingsMenu::GetMenuInternal() if (++Settings.CacheTitles >= MAX_ON_OFF) Settings.CacheTitles = 0; } + //! Settings: Use Game Header Cache + else if (ret == ++Idx) + { + if (++Settings.UseGameHeaderCache >= MAX_ON_OFF) Settings.UseGameHeaderCache = 0; + } + //! Settings: Force Titles from Disc else if (ret == ++Idx) { @@ -506,7 +519,7 @@ int FeatureSettingsMenu::GetMenuInternal() char wadpath[150]; snprintf(wadpath, sizeof(wadpath), "%s/wad/", Settings.BootDevice); - + int choice = WindowPrompt(tr("EmuNAND Wad Manager"), tr("Which mode do you want to use?"), tr("File"), tr("Folder"), tr("Cancel")); if(choice == 1) // File mode { @@ -530,8 +543,9 @@ int FeatureSettingsMenu::GetMenuInternal() Wad wadFile(wadpath); wadFile.UnInstall(Settings.NandEmuChanPath); } - + // Refresh new EmuNAND content + ResetGameHeaderCache(); Channels::Instance()->GetEmuChannelList(); GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); } @@ -618,10 +632,11 @@ int FeatureSettingsMenu::GetMenuInternal() else WindowPrompt(tr( "EmuNAND Wad Manager" ), tr("Error writing the data."), tr( "OK" )); } - } + } } - + // Refresh new EmuNAND content + ResetGameHeaderCache(); Channels::Instance()->GetEmuChannelList(); GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); } @@ -629,7 +644,7 @@ int FeatureSettingsMenu::GetMenuInternal() { WindowPrompt(tr( "EmuNAND Wad Manager" ), tr("No wad file found in this folder."), tr( "OK" )); } - + delete wadList; } } @@ -646,7 +661,7 @@ int FeatureSettingsMenu::GetMenuInternal() snprintf(NINUpdatePath, sizeof(NINUpdatePath), "%sboot.dol", Settings.NINLoaderPath); char NINUpdatePathBak[100]; snprintf(NINUpdatePathBak, sizeof(NINUpdatePathBak), "%sboot.bak", Settings.NINLoaderPath); - + int choice = WindowPrompt(tr( "Do you want to update this file?" ), NINUpdatePath, tr( "Yes" ), tr( "Cancel" )); if (choice == 1) { @@ -659,7 +674,7 @@ int FeatureSettingsMenu::GetMenuInternal() // Rename existing boot.dol file to boot.bak if(CheckFile(NINUpdatePath)) RenameFile(NINUpdatePath, NINUpdatePathBak); - + // Download latest loader.dol as boot.dol bool success = false; struct download file = {}; @@ -677,10 +692,10 @@ int FeatureSettingsMenu::GetMenuInternal() } else WindowPrompt(tr( "Update failed" ), 0, tr( "OK" )); - + MEM2_free(file.data); } - + if(success) { //remove existing loader.dol file if found as it has priority over boot.dol, and boot.bak @@ -737,13 +752,24 @@ int FeatureSettingsMenu::GetMenuInternal() ExitApp(); NEEK_CFG *neek_config = (NEEK_CFG *) NEEK_CONFIG_ADDRESS; neek2oSetBootSettings(neek_config, 0 /* TitleID */ , 0 /* Magic */, 0 /* Returnto TitleID */, Settings.NandEmuChanPath /* Full EmuNAND path */); - + if(neekBoot() == -1) Sys_BackToLoader(); return MENU_NONE; } } } + + //! Reset Game Header Cache + else if(ret == ++Idx) + { + int choice = WindowPrompt(tr( "Are you sure you want to reset?" ), 0, tr( "Yes" ), tr( "Cancel" )); + if (choice == 1) + { + ResetGameHeaderCache(); + gameList.ReadGameList(); + } + } SetOptionValues(); return MENU_NONE; diff --git a/source/settings/menus/UninstallSM.cpp b/source/settings/menus/UninstallSM.cpp index bd0a325d..5bb43161 100644 --- a/source/settings/menus/UninstallSM.cpp +++ b/source/settings/menus/UninstallSM.cpp @@ -22,6 +22,7 @@ * distribution. ***************************************************************************/ #include + #include "UninstallSM.hpp" #include "FileOperations/fileops.h" #include "GameCube/GCGames.h" @@ -35,6 +36,7 @@ #include "usbloader/wbfs.h" #include "usbloader/GameList.h" #include "wstring.hpp" +#include "cache/cache.hpp" UninstallSM::UninstallSM(struct discHdr * header) : SettingsMenu(tr("Uninstall Menu"), &GuiOptions, MENU_NONE) @@ -127,6 +129,7 @@ int UninstallSM::GetMenuInternal() if(ret >= 0) { wString oldFilter(gameList.GetCurrentFilter()); + ResetGameHeaderCache(); gameList.ReadGameList(); gameList.FilterList(oldFilter.c_str()); } @@ -134,6 +137,7 @@ int UninstallSM::GetMenuInternal() else if(DiscHeader->type == TYPE_GAME_GC_IMG) { GCGames::Instance()->RemoveGame(GameID); + ResetGameHeaderCache(); // Reload list GCGames::Instance()->LoadAllGames(); } @@ -147,6 +151,7 @@ int UninstallSM::GetMenuInternal() snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/", Settings.NandEmuChanPath, (unsigned int) (DiscHeader->tid >> 32), (unsigned int) DiscHeader->tid); RemoveDirectory(filepath); + ResetGameHeaderCache(); Channels::Instance()->GetEmuChannelList(); } diff --git a/source/usbloader/GameList.cpp b/source/usbloader/GameList.cpp index ff720c0d..a8531cee 100644 --- a/source/usbloader/GameList.cpp +++ b/source/usbloader/GameList.cpp @@ -24,6 +24,7 @@ #include #include #include + #include "GUI/gui_searchbar.h" #include "usbloader/wbfs.h" #include "GameCube/GCGames.h" @@ -37,8 +38,14 @@ #include "GameList.h" #include "memory/memory.h" #include "Channels/channels.h" +#include "cache/cache.hpp" -enum { DISABLED, ENABLED, HIDEFORBIDDEN }; +enum +{ + DISABLED, + ENABLED, + HIDEFORBIDDEN +}; GameList gameList; @@ -54,13 +61,14 @@ void GameList::clear() std::vector().swap(GamePartitionList); } -struct discHdr * GameList::GetDiscHeader(const char * gameID) const +struct discHdr *GameList::GetDiscHeader(const char *gameID) const { - if(!gameID) return NULL; + if (!gameID) + return NULL; for (u32 i = 0; i < FilteredList.size(); ++i) { - if(strncasecmp(gameID, (const char *) FilteredList[i]->id, 6) == 0) + if (strncasecmp(gameID, (const char *)FilteredList[i]->id, 6) == 0) return FilteredList[i]; } @@ -69,11 +77,12 @@ struct discHdr * GameList::GetDiscHeader(const char * gameID) const int GameList::GetPartitionNumber(const u8 *gameID) const { - if(!gameID) return -1; + if (!gameID) + return -1; for (u32 i = 0; i < FullGameList.size(); ++i) { - if(strncasecmp((const char *) gameID, (const char *) FullGameList[i].id, 6) == 0) + if (strncasecmp((const char *)gameID, (const char *)FullGameList[i].id, 6) == 0) return GamePartitionList[i]; } @@ -82,17 +91,17 @@ int GameList::GetPartitionNumber(const u8 *gameID) const void GameList::RemovePartition(int part) { - for(u32 i = 0; i < GamePartitionList.size(); ++i) + for (u32 i = 0; i < GamePartitionList.size(); ++i) { - if(GamePartitionList[i] == part) + if (GamePartitionList[i] == part) { - FullGameList.erase(FullGameList.begin()+i); - GamePartitionList.erase(GamePartitionList.begin()+i); + FullGameList.erase(FullGameList.begin() + i); + GamePartitionList.erase(GamePartitionList.begin() + i); --i; } } - if(FullGameList.size() > 0) + if (FullGameList.size() > 0) FilterList(); } @@ -102,18 +111,20 @@ int GameList::InternalReadList(int part) u32 cnt = 0; int ret = WBFS_GetCount(part, &cnt); - if (ret < 0) return -1; + if (ret < 0) + return -1; // We are done here if no games are there - if(cnt == 0) + if (cnt == 0) return 0; /* Buffer length */ u32 len = sizeof(struct discHdr) * cnt; /* Allocate memory */ - struct discHdr *buffer = (struct discHdr *) allocate_memory( len ); - if (!buffer) return -1; + struct discHdr *buffer = (struct discHdr *)allocate_memory(len); + if (!buffer) + return -1; /* Clear buffer */ memset(buffer, 0, len); @@ -133,22 +144,22 @@ int GameList::InternalReadList(int part) for (u32 i = 0; i < PartGameList.size(); i++) { - for(u32 j = 0; j < FullGameList.size(); j++) + for (u32 j = 0; j < FullGameList.size(); j++) { - if(strncasecmp((const char *) PartGameList[i].id, (const char *) FullGameList[j].id, 6) == 0) + if (strncasecmp((const char *)PartGameList[i].id, (const char *)FullGameList[j].id, 6) == 0) { - PartGameList.erase(PartGameList.begin()+i); + PartGameList.erase(PartGameList.begin() + i); --i; break; } } } - FullGameList.resize(oldSize+PartGameList.size()); - memcpy(&FullGameList[oldSize], &PartGameList[0], PartGameList.size()*sizeof(struct discHdr)); + FullGameList.resize(oldSize + PartGameList.size()); + memcpy(&FullGameList[oldSize], &PartGameList[0], PartGameList.size() * sizeof(struct discHdr)); - GamePartitionList.resize(oldSize+PartGameList.size()); + GamePartitionList.resize(oldSize + PartGameList.size()); - for(u32 i = oldSize; i < GamePartitionList.size(); ++i) + for (u32 i = oldSize; i < GamePartitionList.size(); ++i) GamePartitionList[i] = part; return PartGameList.size(); @@ -156,6 +167,13 @@ int GameList::InternalReadList(int part) int GameList::ReadGameList() { + if (Settings.UseGameHeaderCache && isCacheFile(WII_HEADER_CACHE_FILE)) + { + if (FullGameList.empty() && GamePartitionList.empty()) + LoadGameHeaderCache(FullGameList, GamePartitionList); + if (!FullGameList.empty()) + return (int)FullGameList.size(); + } // Clear list FullGameList.clear(); GamePartitionList.clear(); @@ -165,7 +183,7 @@ int GameList::ReadGameList() int cnt = 0; - if(!Settings.MultiplePartitions) + if (!Settings.MultiplePartitions) { cnt = InternalReadList(Settings.partition); } @@ -173,13 +191,17 @@ int GameList::ReadGameList() { int partitions = DeviceHandler::GetUSBPartitionCount(); - for(int part = 0; part < partitions; ++part) + for (int part = 0; part < partitions; ++part) { int ret = InternalReadList(part); - if(ret > 0) cnt += ret; + if (ret > 0) + cnt += ret; } } + if (Settings.UseGameHeaderCache && !FullGameList.empty() && !GamePartitionList.empty()) + SaveGameHeaderCache(FullGameList, GamePartitionList); + return cnt; } @@ -195,23 +217,25 @@ void GameList::InternalFilterList(std::vector &FullList) /* Filters */ if (Settings.GameSort & SORT_FAVORITE) { - GameStatus * GameStats = GameStatistics.GetGameStatus(header->id); + GameStatus *GameStats = GameStatistics.GetGameStatus(header->id); if (Settings.marknewtitles) { bool isNew = NewTitles::Instance()->IsNew(header->id); - if (!isNew && (!GameStats || GameStats->FavoriteRank == 0)) continue; + if (!isNew && (!GameStats || GameStats->FavoriteRank == 0)) + continue; } else { - if (!GameStats || GameStats->FavoriteRank == 0) continue; + if (!GameStats || GameStats->FavoriteRank == 0) + continue; } } //ignore uLoader cfg "iso". i was told it is "__CFG_" but not confirmed - if (strncasecmp((char*) header->id, "__CFG_", 6) == 0) + if (strncasecmp((char *)header->id, "__CFG_", 6) == 0) continue; - GameCFG * GameConfig = GameSettings.GetGameCFG(header); + GameCFG *GameConfig = GameSettings.GetGameCFG(header); /* Rating based parental control method */ if (Settings.parentalcontrol != PARENTAL_LVL_ADULT && !Settings.godmode) @@ -220,89 +244,89 @@ void GameList::InternalFilterList(std::vector &FullList) continue; // Check game rating in GameTDB, since the default Wii parental control setting is enabled - int rating = GameTitles.GetParentalRating((char *) header->id); + int rating = GameTitles.GetParentalRating((char *)header->id); if (rating > Settings.parentalcontrol) continue; } //! Per game lock method - if(!Settings.godmode && GameConfig && GameConfig->Locked) + if (!Settings.godmode && GameConfig && GameConfig->Locked) continue; //! Category filter u32 n; int allType = DISABLED; // verify the display mode for category "All" - for(n = 0; n < Settings.EnabledCategories.size(); ++n) + for (n = 0; n < Settings.EnabledCategories.size(); ++n) { - if(Settings.EnabledCategories[n] == 0) + if (Settings.EnabledCategories[n] == 0) { allType = ENABLED; // All = Enabled break; } } - for(n = 0; n < Settings.ForbiddenCategories.size(); ++n) + for (n = 0; n < Settings.ForbiddenCategories.size(); ++n) { - if(Settings.ForbiddenCategories[n] == 0) + if (Settings.ForbiddenCategories[n] == 0) { allType = HIDEFORBIDDEN; // All = Enabled but hide Forbidden categories break; } } - - if(allType == DISABLED) + + if (allType == DISABLED) { // Remove TitleID if it contains a forbidden categories - for(n = 0; n < Settings.ForbiddenCategories.size(); ++n) + for (n = 0; n < Settings.ForbiddenCategories.size(); ++n) { - if(GameCategories.isInCategory((char *) header->id, Settings.ForbiddenCategories[n])) + if (GameCategories.isInCategory((char *)header->id, Settings.ForbiddenCategories[n])) break; } - if(n < Settings.ForbiddenCategories.size()) + if (n < Settings.ForbiddenCategories.size()) continue; - + // Remove TitleID is it doesn't contain a required categories - for(n = 0; n < Settings.RequiredCategories.size(); ++n) + for (n = 0; n < Settings.RequiredCategories.size(); ++n) { - if(!GameCategories.isInCategory((char *) header->id, Settings.RequiredCategories[n])) + if (!GameCategories.isInCategory((char *)header->id, Settings.RequiredCategories[n])) break; } - if(n < Settings.RequiredCategories.size()) + if (n < Settings.RequiredCategories.size()) continue; - + // If there's no required categories, verify if the TitleID should be kept or removed - if(Settings.RequiredCategories.size() == 0) + if (Settings.RequiredCategories.size() == 0) { - for(n = 0; n < Settings.EnabledCategories.size(); ++n) + for (n = 0; n < Settings.EnabledCategories.size(); ++n) { - if(GameCategories.isInCategory((char *) header->id, Settings.EnabledCategories[n])) + if (GameCategories.isInCategory((char *)header->id, Settings.EnabledCategories[n])) break; } - if(n == Settings.EnabledCategories.size()) + if (n == Settings.EnabledCategories.size()) continue; } } - - if(allType == HIDEFORBIDDEN) + + if (allType == HIDEFORBIDDEN) { // Remove TitleID if it contains a forbidden categories - for(n = 0; n < Settings.ForbiddenCategories.size(); ++n) + for (n = 0; n < Settings.ForbiddenCategories.size(); ++n) { - if(GameCategories.isInCategory((char *) header->id, Settings.ForbiddenCategories[n])) - if(Settings.ForbiddenCategories[n] >0) + if (GameCategories.isInCategory((char *)header->id, Settings.ForbiddenCategories[n])) + if (Settings.ForbiddenCategories[n] > 0) break; } - if(n < Settings.ForbiddenCategories.size()) + if (n < Settings.ForbiddenCategories.size()) continue; - } - + } + FilteredList.push_back(header); } } -int GameList::FilterList(const wchar_t * gameFilter) +int GameList::FilterList(const wchar_t *gameFilter) { - if((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0)) + if ((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0)) ReadGameList(); if (gameFilter) @@ -310,20 +334,28 @@ int GameList::FilterList(const wchar_t * gameFilter) FilteredList.clear(); + if (Settings.UseGameHeaderCache && isCacheFile(FilteredListCacheFileName(gameFilter))) + { + LoadFilteredListCache(FilteredList, GameFilter.c_str()); + GuiSearchBar::FilterList(FilteredList, GameFilter); + if (!FilteredList.empty()) + return FilteredList.size(); + } + // Filter current game list if selected - if(Settings.LoaderMode & MODE_WIIGAMES) + if (Settings.LoaderMode & MODE_WIIGAMES) InternalFilterList(FullGameList); // Filter gc game list if selected - if(Settings.LoaderMode & MODE_GCGAMES) + if (Settings.LoaderMode & MODE_GCGAMES) InternalFilterList(GCGames::Instance()->GetHeaders()); // Filter nand channel list if selected - if(Settings.LoaderMode & MODE_NANDCHANNELS) + if (Settings.LoaderMode & MODE_NANDCHANNELS) InternalFilterList(Channels::Instance()->GetNandHeaders()); // Filter emu nand channel list if selected - if(Settings.LoaderMode & MODE_EMUCHANNELS) + if (Settings.LoaderMode & MODE_EMUCHANNELS) InternalFilterList(Channels::Instance()->GetEmuHeaders()); NewTitles::Instance()->Save(); @@ -331,6 +363,9 @@ int GameList::FilterList(const wchar_t * gameFilter) SortList(); + if (Settings.UseGameHeaderCache && !FilteredList.empty() && (Settings.GameSort & SORT_RANKING) == 0 && (Settings.GameSort & SORT_PLAYCOUNT) == 0 && (Settings.GameSort & SORT_FAVORITE) == 0) + SaveFilteredListCache(FilteredList, GameFilter.c_str()); + return FilteredList.size(); } @@ -349,26 +384,34 @@ void GameList::InternalLoadUnfiltered(std::vector &FullList) int GameList::LoadUnfiltered() { - if((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0)) + if ((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0)) ReadGameList(); GameFilter.clear(); FilteredList.clear(); + if (Settings.UseGameHeaderCache && isCacheFile(FilteredListCacheFileName())) + { + LoadFilteredListCache(FilteredList, GameFilter.c_str()); + GuiSearchBar::FilterList(FilteredList, GameFilter); + if (!FilteredList.empty()) + return FilteredList.size(); + } + // Filter current game list if selected - if(Settings.LoaderMode & MODE_WIIGAMES) + if (Settings.LoaderMode & MODE_WIIGAMES) InternalLoadUnfiltered(FullGameList); // Filter gc game list if selected - if(Settings.LoaderMode & MODE_GCGAMES) + if (Settings.LoaderMode & MODE_GCGAMES) InternalLoadUnfiltered(GCGames::Instance()->GetHeaders()); // Filter nand channel list if selected - if(Settings.LoaderMode & MODE_NANDCHANNELS) + if (Settings.LoaderMode & MODE_NANDCHANNELS) InternalLoadUnfiltered(Channels::Instance()->GetNandHeaders()); // Filter emu nand channel list if selected - if(Settings.LoaderMode & MODE_EMUCHANNELS) + if (Settings.LoaderMode & MODE_EMUCHANNELS) InternalLoadUnfiltered(Channels::Instance()->GetEmuHeaders()); NewTitles::Instance()->Save(); @@ -376,22 +419,26 @@ int GameList::LoadUnfiltered() SortList(); + if (Settings.UseGameHeaderCache && !FilteredList.empty() && (Settings.GameSort & SORT_RANKING) == 0 && (Settings.GameSort & SORT_PLAYCOUNT) == 0 && (Settings.GameSort & SORT_FAVORITE) == 0) + SaveFilteredListCache(FilteredList, GameFilter.c_str()); + return FilteredList.size(); } void GameList::SortList() { - if (FilteredList.size() < 2) return; + if (FilteredList.size() < 2) + return; if (Settings.GameSort & SORT_PLAYCOUNT) { std::sort(FilteredList.begin(), FilteredList.end(), PlaycountSortCallback); } - else if(Settings.GameSort & SORT_RANKING) + else if (Settings.GameSort & SORT_RANKING) { std::sort(FilteredList.begin(), FilteredList.end(), RankingSortCallback); } - else if(Settings.GameSort & SORT_PLAYERS) + else if (Settings.GameSort & SORT_PLAYERS) { std::sort(FilteredList.begin(), FilteredList.end(), PlayersSortCallback); } @@ -403,7 +450,7 @@ void GameList::SortList() bool GameList::NameSortCallback(const struct discHdr *a, const struct discHdr *b) { - return (strcasecmp(GameTitles.GetTitle((struct discHdr *) a), GameTitles.GetTitle((struct discHdr *) b)) < 0); + return (strcasecmp(GameTitles.GetTitle((struct discHdr *)a), GameTitles.GetTitle((struct discHdr *)b)) < 0); } bool GameList::PlaycountSortCallback(const struct discHdr *a, const struct discHdr *b) @@ -411,7 +458,8 @@ bool GameList::PlaycountSortCallback(const struct discHdr *a, const struct discH int count1 = GameStatistics.GetPlayCount(a->id); int count2 = GameStatistics.GetPlayCount(b->id); - if (count1 == count2) return NameSortCallback(a, b); + if (count1 == count2) + return NameSortCallback(a, b); return (count1 > count2); } @@ -421,17 +469,19 @@ bool GameList::RankingSortCallback(const struct discHdr *a, const struct discHdr int fav1 = GameStatistics.GetFavoriteRank(a->id); int fav2 = GameStatistics.GetFavoriteRank(b->id); - if (fav1 == fav2) return NameSortCallback(a, b); + if (fav1 == fav2) + return NameSortCallback(a, b); return (fav1 > fav2); } bool GameList::PlayersSortCallback(const struct discHdr *a, const struct discHdr *b) { - int count1 = GameTitles.GetPlayersCount((const char *) a->id); - int count2 = GameTitles.GetPlayersCount((const char *) b->id); + int count1 = GameTitles.GetPlayersCount((const char *)a->id); + int count2 = GameTitles.GetPlayersCount((const char *)b->id); - if (count1 == count2) return NameSortCallback(a, b); + if (count1 == count2) + return NameSortCallback(a, b); return (count1 > count2); }