Added extra caching options

Thanks to Oddx & geoGolem
This commit is contained in:
wiidev 2020-12-12 21:33:31 +00:00
parent 0114bc2da4
commit c6d2efd765
35 changed files with 1473 additions and 720 deletions

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID hry" msgstr "ID hry"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Obnovit hudbu na pozadí" msgstr "Obnovit hudbu na pozadí"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Vynulovat cítac spuštení" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Odinstalace" msgstr "Odinstalace"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Spil-ID" msgstr "Spil-ID"
@ -1824,6 +1827,9 @@ msgstr "Nulstil"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Nulstil BG-musik" msgstr "Nulstil BG-musik"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Nulstil spiltæller" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Afinstaller" msgstr "Afinstaller"

View File

@ -1101,6 +1101,9 @@ msgstr "GameCube Spel Verwijderen"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "GameCube Installatie Menu" msgstr "GameCube Installatie Menu"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Spel ID" msgstr "Spel ID"
@ -1824,6 +1827,9 @@ msgstr "Resetten"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Reset achtergrond muziek" msgstr "Reset achtergrond muziek"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Speeltellers resetten" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Verwijderen" msgstr "Verwijderen"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "" msgstr ""
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "" msgstr ""
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "" msgstr ""
@ -2253,6 +2259,9 @@ msgstr ""
msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "" msgstr ""

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Peli ID" msgstr "Peli ID"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "" msgstr ""
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Resetoi pelauksen määrä" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Poista" msgstr "Poista"

View File

@ -1101,6 +1101,9 @@ msgstr "Menu de suppression GameCube"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "Menu d'installation GameCube" msgstr "Menu d'installation GameCube"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID du jeu" msgstr "ID du jeu"
@ -1824,6 +1827,9 @@ msgstr "Réinitialisation"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Fond sonore par defaut" msgstr "Fond sonore par defaut"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Remise à zéro du compteur d'utilisations" 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." 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." 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" msgid "Uninstall"
msgstr "Désinstaller" msgstr "Désinstaller"

View File

@ -1101,6 +1101,9 @@ msgstr "GameCube Spiele Löschen"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "GameCube Installationsmenü" msgstr "GameCube Installationsmenü"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Spiel ID" msgstr "Spiel ID"
@ -1824,6 +1827,9 @@ msgstr "Zurücksetzen"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Musik zurücksetzen" msgstr "Musik zurücksetzen"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Spielzähler zurücksetzen" 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." 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." 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" msgid "Uninstall"
msgstr "Deinstallieren" msgstr "Deinstallieren"

View File

@ -1101,6 +1101,9 @@ msgstr "Διαγραφή παιχνιδιών GameCube"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "menu εγκατάστασης παιχνιδιών GameCube" msgstr "menu εγκατάστασης παιχνιδιών GameCube"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID παιχνιδιού" msgstr "ID παιχνιδιού"
@ -1824,6 +1827,9 @@ msgstr "Επανεκκίνηση"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Επαναφορά μουσικής υπόκρουσης." msgstr "Επαναφορά μουσικής υπόκρουσης."
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Επαναφορά του 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Απεγκατάσταση" msgstr "Απεγκατάσταση"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Játék ID" msgstr "Játék ID"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "" msgstr ""
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Elindítások nullázása" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Törlés" msgstr "Törlés"

View File

@ -1101,6 +1101,9 @@ msgstr "Menu disinstallazioni GC"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "Menu installazioni GC" msgstr "Menu installazioni GC"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID gioco" msgstr "ID gioco"
@ -1824,6 +1827,9 @@ msgstr "Riavvia"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Ripristina musica sottofondo" msgstr "Ripristina musica sottofondo"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Azzera contatore" 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." 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" 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" msgid "Uninstall"
msgstr "Disinstalla" msgstr "Disinstalla"

View File

@ -1101,6 +1101,9 @@ msgstr "GCゲームの削除"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "GCインストールメニュー" msgstr "GCインストールメニュー"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "IDのみ" msgstr "IDのみ"
@ -1824,6 +1827,9 @@ msgstr "リセット"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "BGMをリセット" msgstr "BGMをリセット"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "プレイ回数をリセット" msgstr "プレイ回数をリセット"
@ -2253,6 +2259,9 @@ msgstr ""
msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "アンインストール" msgstr "アンインストール"

View File

@ -1095,12 +1095,15 @@ msgstr ""
msgid "GXFlush" msgid "GXFlush"
msgstr "" msgstr ""
msgid "Game Cube Games Delete" msgid "GameCube Games Delete"
msgstr "게임큐브 게임 삭제" msgstr "게임큐브 게임 삭제"
msgid "Game Cube Install Menu" msgid "GameCube Install Menu"
msgstr "게임큐브 설치 메뉴" msgstr "게임큐브 설치 메뉴"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "게임 ID" msgstr "게임 ID"
@ -1824,6 +1827,9 @@ msgstr "리셋"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "배경 음악 리셋" msgstr "배경 음악 리셋"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "USBloaderGX r1218은 닌텐돈트 알파 v0.1에 필요합니다. 닌텐돈트 boot.dol 버전을 업데이트하십시오." msgstr "USBloaderGX r1218은 닌텐돈트 알파 v0.1에 필요합니다. 닌텐돈트 boot.dol 버전을 업데이트하십시오."
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "제거" msgstr "제거"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Spill ID" msgstr "Spill ID"
@ -1824,6 +1827,9 @@ msgstr "Tilbakestill"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Tilbakestill BG musikk" msgstr "Tilbakestill BG musikk"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Nullstill teller" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "" msgstr ""

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID gry" msgstr "ID gry"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "" msgstr ""
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Zrestartuj licznik" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Odinstaluj" msgstr "Odinstaluj"

View File

@ -1101,6 +1101,9 @@ msgstr "Desinstalar Jogos GameCube"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "Instalar Jogos GameCube" msgstr "Instalar Jogos GameCube"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID do Jogo" msgstr "ID do Jogo"
@ -1824,6 +1827,9 @@ msgstr "Reiniciar"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Música padrão" msgstr "Música padrão"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Limpar Contagem" 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." 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" 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" msgid "Uninstall"
msgstr "Desinstalar" msgstr "Desinstalar"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID do Jogo" msgstr "ID do Jogo"
@ -1824,6 +1827,9 @@ msgstr "Reinicializar"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Reinicializar Música de Fundo" msgstr "Reinicializar Música de Fundo"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Limpar Contagem" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "" msgstr ""

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID игры" msgstr "ID игры"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "" msgstr ""
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Сбросить счетчик запусков" msgstr "Сбросить счетчик запусков"
@ -2253,6 +2259,9 @@ msgstr ""
msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Деинсталлировать" msgstr "Деинсталлировать"

View File

@ -1101,6 +1101,9 @@ msgstr "GameCube 游戏删除"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "GameCube 安装菜单" msgstr "GameCube 安装菜单"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "游戏 ID" msgstr "游戏 ID"
@ -1824,6 +1827,9 @@ msgstr "重启"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "重置背景音乐" msgstr "重置背景音乐"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "重置游戏计数" 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." 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版本。" msgstr "USBloaderGX r1218之针对nintendont Alpha v0.1请更新你的Nintendont boot。dol版本。"
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "删除" msgstr "删除"

View File

@ -1101,6 +1101,9 @@ msgstr "Borrar Juego de GameCube"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "Menu de instalación GameCube" msgstr "Menu de instalación GameCube"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "ID del Juego" msgstr "ID del Juego"
@ -1824,6 +1827,9 @@ msgstr "Reiniciar"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "Reiniciar Música de Fondo" msgstr "Reiniciar Música de Fondo"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Reiniciar Partidas" 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." 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." 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" msgid "Uninstall"
msgstr "Desinstalar" msgstr "Desinstalar"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Spel-ID" msgstr "Spel-ID"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "återställ BG musik" msgstr "återställ BG musik"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Återställ spelat-räknaren" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Avinstallera" msgstr "Avinstallera"

View File

@ -1101,6 +1101,9 @@ msgstr "GameCube 遊戲刪除"
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "GameCube 安裝畫面" msgstr "GameCube 安裝畫面"
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "遊戲 ID" msgstr "遊戲 ID"
@ -1824,6 +1827,9 @@ msgstr "重新啟動"
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "重設背景音樂" msgstr "重設背景音樂"
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "重設執行次數" msgstr "重設執行次數"
@ -2253,6 +2259,9 @@ msgstr ""
msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "移除" msgstr "移除"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "เกมส์ ID" msgstr "เกมส์ ID"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "" msgstr ""
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "เคลียร์การนับจำนวนที่เล่น" msgstr "เคลียร์การนับจำนวนที่เล่น"
@ -2253,6 +2259,9 @@ msgstr ""
msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "ถอนการติดตั้ง" msgstr "ถอนการติดตั้ง"

View File

@ -1101,6 +1101,9 @@ msgstr ""
msgid "GameCube Install Menu" msgid "GameCube Install Menu"
msgstr "" msgstr ""
msgid "Game Header Cache Files Path"
msgstr ""
msgid "Game ID" msgid "Game ID"
msgstr "Oyun ID" msgstr "Oyun ID"
@ -1824,6 +1827,9 @@ msgstr ""
msgid "Reset BG Music" msgid "Reset BG Music"
msgstr "" msgstr ""
msgid "Reset Game Header Cache"
msgstr ""
msgid "Reset Playcounter" msgid "Reset Playcounter"
msgstr "Sayacı sıfırla" 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." msgid "USBloaderGX r1218 is required for Nintendont Alpha v0.1. Please update your Nintendont boot.dol version."
msgstr "" msgstr ""
msgid "Use Game Header Cache"
msgstr ""
msgid "Uninstall" msgid "Uninstall"
msgstr "Kaldır" msgstr "Kaldır"

View File

@ -47,7 +47,8 @@ SOURCES := source \
source/SystemMenu \ source/SystemMenu \
source/utils \ source/utils \
source/utils/minizip \ source/utils/minizip \
source/usbloader/wbfs source/usbloader/wbfs \
source/cache
DATA := data \ DATA := data \
data/images \ data/images \
data/fonts \ data/fonts \

View File

@ -26,6 +26,7 @@
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <sys/dirent.h> #include <sys/dirent.h>
#include "FileOperations/fileops.h" #include "FileOperations/fileops.h"
#include "Controls/DeviceHandler.hpp" #include "Controls/DeviceHandler.hpp"
#include "settings/CSettings.h" #include "settings/CSettings.h"
@ -35,10 +36,11 @@
#include "memory/memory.h" #include "memory/memory.h"
#include "utils/lz77.h" #include "utils/lz77.h"
#include "gecko.h" #include "gecko.h"
#include "cache/cache.hpp"
#include "channels.h" #include "channels.h"
typedef struct _dolheader{ typedef struct _dolheader
{
u32 section_pos[18]; u32 section_pos[18];
u32 section_start[18]; u32 section_start[18];
u32 section_size[18]; u32 section_size[18];
@ -89,7 +91,7 @@ void Channels::InternalGetNandChannelList(u32 type)
break; break;
//these can't be booted anyways //these can't be booted anyways
if (TITLE_LOWER( tid ) == 0x48414741 || TITLE_LOWER( tid ) == 0x48414141 || TITLE_LOWER( tid ) == 0x48414641) if (TITLE_LOWER(tid) == 0x48414741 || TITLE_LOWER(tid) == 0x48414141 || TITLE_LOWER(tid) == 0x48414641)
continue; continue;
//these aren't installed on the nand //these aren't installed on the nand
@ -100,17 +102,17 @@ void Channels::InternalGetNandChannelList(u32 type)
NandTitles.AsciiTID(tid, id); NandTitles.AsciiTID(tid, id);
// Force old and new format to be "JODI" which is known by GameTDB // Force old and new format to be "JODI" which is known by GameTDB
if(tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) if (tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL)
strcpy(id, "JODI"); strcpy(id, "JODI");
const char *name = GameTitles.GetTitle(id); const char *name = GameTitles.GetTitle(id);
std::string TitleName; std::string TitleName;
if(!name || *name == '\0') if (!name || *name == '\0')
{ {
name = NandTitles.NameOf(tid); name = NandTitles.NameOf(tid);
// Set title for caching // Set title for caching
if(name) if (name)
GameTitles.SetGameTitle(id, name); GameTitles.SetGameTitle(id, name);
} }
@ -120,27 +122,38 @@ void Channels::InternalGetNandChannelList(u32 type)
memcpy(NandChannels[s].id, id, 4); memcpy(NandChannels[s].id, id, 4);
NandChannels[s].tid = tid; NandChannels[s].tid = tid;
NandChannels[s].type = TYPE_GAME_NANDCHAN; NandChannels[s].type = TYPE_GAME_NANDCHAN;
strncpy(NandChannels[s].title, name ? name : "", sizeof(NandChannels[s].title)-1); strncpy(NandChannels[s].title, name ? name : "", sizeof(NandChannels[s].title) - 1);
} }
} }
vector<struct discHdr> & Channels::GetNandHeaders(void) vector<struct discHdr> &Channels::GetNandHeaders(void)
{ {
if(NandChannels.empty()) if (NandChannels.empty())
this->GetChannelList(); this->GetChannelList();
return NandChannels; return NandChannels;
} }
vector<struct discHdr> & Channels::GetEmuHeaders(void) vector<struct discHdr> &Channels::GetEmuHeaders(void)
{ {
if(EmuChannels.empty()) if (Settings.UseGameHeaderCache && isCacheFile(EMUNAND_HEADER_CACHE_FILE))
{
if (EmuChannels.empty())
LoadGameHeaderCache(EmuChannels);
if (!EmuChannels.empty())
return EmuChannels;
}
if (EmuChannels.empty())
this->GetEmuChannelList(); this->GetEmuChannelList();
if (Settings.UseGameHeaderCache && !EmuChannels.empty())
SaveGameHeaderCache(EmuChannels);
return 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 const u8 dolsign[6] = {0x00, 0x00, 0x01, 0x00, 0x00, 0x00};
static u8 dolhead[32] ATTRIBUTE_ALIGN(32); static u8 dolhead[32] ATTRIBUTE_ALIGN(32);
@ -150,32 +163,32 @@ u8 * Channels::GetDol(const u64 &title, u8 *tmdBuffer)
u32 high = TITLE_UPPER(title); u32 high = TITLE_UPPER(title);
u32 low = TITLE_LOWER(title); u32 low = TITLE_LOWER(title);
char *filepath = (char *) memalign(32, ISFS_MAXPATH); char *filepath = (char *)memalign(32, ISFS_MAXPATH);
if(!filepath) if (!filepath)
return NULL; return NULL;
_tmd * tmd_file = (_tmd *) SIGNATURE_PAYLOAD((u32 *)tmdBuffer); _tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)tmdBuffer);
if(!Settings.UseChanLauncher) if (!Settings.UseChanLauncher)
{ {
for(u32 i = 0; i < tmd_file->num_contents; ++i) for (u32 i = 0; i < tmd_file->num_contents; ++i)
{ {
if(tmd_file->contents[i].index == tmd_file->boot_index) if (tmd_file->contents[i].index == tmd_file->boot_index)
continue; // Skip loader 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); s32 fd = ISFS_Open(filepath, ISFS_OPEN_READ);
if(fd < 0) if (fd < 0)
continue; continue;
s32 ret = ISFS_Read(fd, dolhead, 32); s32 ret = ISFS_Read(fd, dolhead, 32);
ISFS_Close(fd); ISFS_Close(fd);
if(ret != 32) if (ret != 32)
continue; continue;
if(memcmp(dolhead, dolsign, sizeof(dolsign)) == 0) if (memcmp(dolhead, dolsign, sizeof(dolsign)) == 0)
{ {
bootcontent = tmd_file->contents[i].cid; bootcontent = tmd_file->contents[i].cid;
break; break;
@ -184,10 +197,11 @@ u8 * Channels::GetDol(const u64 &title, u8 *tmdBuffer)
} }
//! Fall back to boot content if dol is not found //! Fall back to boot content if dol is not found
if(bootcontent == 0xDEADBEAF) if (bootcontent == 0xDEADBEAF)
{ {
bootcontent = tmd_file->contents[tmd_file->boot_index].cid; bootcontent = tmd_file->contents[tmd_file->boot_index].cid;
if(!Settings.UseChanLauncher) gprintf("Main dol not found -> "); if (!Settings.UseChanLauncher)
gprintf("Main dol not found -> ");
gprintf("Loading boot content index\n"); gprintf("Loading boot content index\n");
} }
@ -219,8 +233,8 @@ u8 * Channels::GetDol(const u64 &title, u8 *tmdBuffer)
} }
// move dol to mem2 // move dol to mem2
u8 *outBuf = (u8 *) MEM2_alloc(filesize); u8 *outBuf = (u8 *)MEM2_alloc(filesize);
if(!outBuf) if (!outBuf)
return buffer; return buffer;
memcpy(outBuf, buffer, filesize); memcpy(outBuf, buffer, filesize);
@ -238,7 +252,7 @@ u8 Channels::GetRequestedIOS(const u64 &title)
if (!titleTMD) if (!titleTMD)
return 0; return 0;
if(tmdSize > 0x18B) if (tmdSize > 0x18B)
IOS = titleTMD[0x18B]; IOS = titleTMD[0x18B];
free(titleTMD); free(titleTMD);
@ -248,11 +262,11 @@ u8 Channels::GetRequestedIOS(const u64 &title)
u8 *Channels::GetTMD(const u64 &tid, u32 *size, const char *prefix) u8 *Channels::GetTMD(const u64 &tid, u32 *size, const char *prefix)
{ {
char *filepath = (char *) memalign(32, ISFS_MAXPATH); char *filepath = (char *)memalign(32, ISFS_MAXPATH);
if(!filepath) if (!filepath)
return NULL; return NULL;
if(!prefix) if (!prefix)
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));
@ -262,7 +276,7 @@ u8 *Channels::GetTMD(const u64 &tid, u32 *size, const char *prefix)
int ret; int ret;
if(*prefix != '\0') if (*prefix != '\0')
ret = LoadFileToMem(filepath, &tmdBuffer, &tmdSize); ret = LoadFileToMem(filepath, &tmdBuffer, &tmdSize);
else else
ret = NandTitle::LoadFileFromNand(filepath, &tmdBuffer, &tmdSize); ret = NandTitle::LoadFileFromNand(filepath, &tmdBuffer, &tmdSize);
@ -272,12 +286,12 @@ u8 *Channels::GetTMD(const u64 &tid, u32 *size, const char *prefix)
if (ret < 0) if (ret < 0)
{ {
gprintf("Reading TMD...Failed!\n"); gprintf("Reading TMD...Failed!\n");
if(tmdBuffer) if (tmdBuffer)
free(tmdBuffer); free(tmdBuffer);
return NULL; return NULL;
} }
if(size) if (size)
*size = tmdSize; *size = tmdSize;
return tmdBuffer; return tmdBuffer;
@ -290,21 +304,21 @@ u32 Channels::LoadChannel(const u64 &chantitle)
u32 ios = 0; u32 ios = 0;
u32 tmdSize = 0; u32 tmdSize = 0;
u8 *tmdBuffer = GetTMD(chantitle, &tmdSize, ""); u8 *tmdBuffer = GetTMD(chantitle, &tmdSize, "");
if(!tmdBuffer) if (!tmdBuffer)
{ {
ISFS_Deinitialize(); ISFS_Deinitialize();
return 0; return 0;
} }
u8 *chanDOL = GetDol(chantitle, tmdBuffer); u8 *chanDOL = GetDol(chantitle, tmdBuffer);
if(!chanDOL) if (!chanDOL)
{ {
ISFS_Deinitialize(); ISFS_Deinitialize();
free(tmdBuffer); free(tmdBuffer);
return 0; return 0;
} }
if(tmdSize > 0x18B) if (tmdSize > 0x18B)
ios = tmdBuffer[0x18B]; ios = tmdBuffer[0x18B];
Identify(chantitle, tmdBuffer, tmdSize); Identify(chantitle, tmdBuffer, tmdSize);
@ -313,14 +327,14 @@ u32 Channels::LoadChannel(const u64 &chantitle)
dolheader *dolfile = (dolheader *)chanDOL; dolheader *dolfile = (dolheader *)chanDOL;
if(dolfile->bss_start) if (dolfile->bss_start)
{ {
dolfile->bss_start |= 0x80000000; dolfile->bss_start |= 0x80000000;
if(dolfile->bss_start < 0x81800000) if (dolfile->bss_start < 0x81800000)
{ {
// For homebrews...not all have it clean. // For homebrews...not all have it clean.
if(dolfile->bss_start + dolfile->bss_size >= 0x81800000) if (dolfile->bss_start + dolfile->bss_size >= 0x81800000)
dolfile->bss_size = 0x81800000 - dolfile->bss_start; dolfile->bss_size = 0x81800000 - dolfile->bss_start;
memset((void *)dolfile->bss_start, 0, dolfile->bss_size); memset((void *)dolfile->bss_start, 0, dolfile->bss_size);
@ -330,17 +344,19 @@ u32 Channels::LoadChannel(const u64 &chantitle)
} }
int i; int i;
for(i = 0; i < 18; i++) for (i = 0; i < 18; i++)
{ {
if (!dolfile->section_size[i]) continue; if (!dolfile->section_size[i])
if (dolfile->section_pos[i] < sizeof(dolheader)) continue; continue;
if(!(dolfile->section_start[i] & 0x80000000)) if (dolfile->section_pos[i] < sizeof(dolheader))
continue;
if (!(dolfile->section_start[i] & 0x80000000))
dolfile->section_start[i] |= 0x80000000; dolfile->section_start[i] |= 0x80000000;
u8 *dolChunkOffset = (u8 *)dolfile->section_start[i]; u8 *dolChunkOffset = (u8 *)dolfile->section_start[i];
u32 dolChunkSize = dolfile->section_size[i]; u32 dolChunkSize = dolfile->section_size[i];
memmove (dolChunkOffset, chanDOL + dolfile->section_pos[i], dolChunkSize); memmove(dolChunkOffset, chanDOL + dolfile->section_pos[i], dolChunkSize);
DCFlushRange(dolChunkOffset, dolChunkSize); DCFlushRange(dolChunkOffset, dolChunkSize);
ICInvalidateRange(dolChunkOffset, dolChunkSize); ICInvalidateRange(dolChunkOffset, dolChunkSize);
@ -359,14 +375,14 @@ u32 Channels::LoadChannel(const u64 &chantitle)
*Bus_Speed = 0x0E7BE2C0; // bus speed *Bus_Speed = 0x0E7BE2C0; // bus speed
*CPU_Speed = 0x2B73A840; // cpu speed *CPU_Speed = 0x2B73A840; // cpu speed
*GameID_Address = 0x81000000; // Game id address, while there's all 0s at 0x81000000 when using the apploader... *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 memcpy((void *)Online_Check, (void *)Disc_ID, 4); // online check
memset((void *)0x817FE000, 0, 0x2000); // Clearing BI2 memset((void *)0x817FE000, 0, 0x2000); // Clearing BI2
DCFlushRange((void*)0x817FE000, 0x2000); DCFlushRange((void *)0x817FE000, 0x2000);
// IOS Version Check // IOS Version Check
*(vu32*)0x80003140 = ((ios << 16)) | 0xFFFF; *(vu32 *)0x80003140 = ((ios << 16)) | 0xFFFF;
*(vu32*)0x80003188 = ((ios << 16)) | 0xFFFF; *(vu32 *)0x80003188 = ((ios << 16)) | 0xFFFF;
ISFS_Deinitialize(); ISFS_Deinitialize();
@ -376,7 +392,8 @@ u32 Channels::LoadChannel(const u64 &chantitle)
static bool Identify_GenerateTik(signed_blob **outbuf, u32 *outlen) static bool Identify_GenerateTik(signed_blob **outbuf, u32 *outlen)
{ {
signed_blob *buffer = (signed_blob *)memalign(32, STD_SIGNED_TIK_SIZE); signed_blob *buffer = (signed_blob *)memalign(32, STD_SIGNED_TIK_SIZE);
if (!buffer) return false; if (!buffer)
return false;
memset(buffer, 0, STD_SIGNED_TIK_SIZE); memset(buffer, 0, STD_SIGNED_TIK_SIZE);
sig_rsa2048 *signature = (sig_rsa2048 *)buffer; sig_rsa2048 *signature = (sig_rsa2048 *)buffer;
@ -394,14 +411,14 @@ static bool Identify_GenerateTik(signed_blob **outbuf, u32 *outlen)
bool Channels::Identify(const u64 &titleid, u8 *tmdBuffer, u32 tmdSize) bool Channels::Identify(const u64 &titleid, u8 *tmdBuffer, u32 tmdSize)
{ {
char *filepath = (char *) memalign(32, ISFS_MAXPATH); char *filepath = (char *)memalign(32, ISFS_MAXPATH);
if(!filepath) if (!filepath)
return false; return false;
u32 tikSize; u32 tikSize;
signed_blob *tikBuffer = NULL; signed_blob *tikBuffer = NULL;
if(!Identify_GenerateTik(&tikBuffer,&tikSize)) if (!Identify_GenerateTik(&tikBuffer, &tikSize))
{ {
free(filepath); free(filepath);
gprintf("Generating fake ticket...Failed!"); gprintf("Generating fake ticket...Failed!");
@ -418,10 +435,10 @@ bool Channels::Identify(const u64 &titleid, u8 *tmdBuffer, u32 tmdSize)
free(filepath); free(filepath);
return false; return false;
} }
s32 ret = ES_Identify((signed_blob*)certBuffer, certSize, (signed_blob*)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL); s32 ret = ES_Identify((signed_blob *)certBuffer, certSize, (signed_blob *)tmdBuffer, tmdSize, tikBuffer, tikSize, NULL);
if (ret < 0) if (ret < 0)
{ {
switch(ret) switch (ret)
{ {
case ES_EINVAL: case ES_EINVAL:
gprintf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret); gprintf("Error! ES_Identify (ret = %d;) Data invalid!\n", ret);
@ -453,19 +470,19 @@ bool Channels::emuExists(char *tmdpath)
u8 *buffer = NULL; u8 *buffer = NULL;
u32 size = 0; u32 size = 0;
if(LoadFileToMem(tmdpath, &buffer, &size) < 0) if (LoadFileToMem(tmdpath, &buffer, &size) < 0)
return false; return false;
signed_blob *s_tmd = (signed_blob *) buffer; signed_blob *s_tmd = (signed_blob *)buffer;
u32 i; u32 i;
tmd *titleTmd = (tmd *) SIGNATURE_PAYLOAD(s_tmd); tmd *titleTmd = (tmd *)SIGNATURE_PAYLOAD(s_tmd);
for (i = 0; i < titleTmd->num_contents; i++) for (i = 0; i < titleTmd->num_contents; i++)
if (!titleTmd->contents[i].index) if (!titleTmd->contents[i].index)
break; break;
if(i == titleTmd->num_contents) if (i == titleTmd->num_contents)
{ {
free(buffer); free(buffer);
return false; return false;
@ -476,14 +493,14 @@ bool Channels::emuExists(char *tmdpath)
free(buffer); free(buffer);
char *ptr = strrchr(tmdpath, '/'); char *ptr = strrchr(tmdpath, '/');
if(!ptr) if (!ptr)
return false; return false;
//! tmdpath has length of 1024 //! tmdpath has length of 1024
snprintf(ptr+1, 1024-(ptr+1-tmdpath), "%08x.app", (unsigned int)cid); snprintf(ptr + 1, 1024 - (ptr + 1 - tmdpath), "%08x.app", (unsigned int)cid);
FILE *f = fopen(tmdpath, "rb"); FILE *f = fopen(tmdpath, "rb");
if(!f) if (!f)
return false; return false;
fclose(f); fclose(f);
@ -493,18 +510,18 @@ bool Channels::emuExists(char *tmdpath)
bool Channels::ParseTitleDir(char *path, int language) bool Channels::ParseTitleDir(char *path, int language)
{ {
if(!path) if (!path)
return false; return false;
const char *tidPtr = strrchr(path, '/'); const char *tidPtr = strrchr(path, '/');
if(!tidPtr) if (!tidPtr)
return false; return false;
else else
tidPtr++; tidPtr++;
struct dirent *dirent = NULL; struct dirent *dirent = NULL;
DIR *dir = opendir(path); DIR *dir = opendir(path);
if(!dir) if (!dir)
return false; return false;
char *pathEndPtr = path + strlen(path); char *pathEndPtr = path + strlen(path);
@ -514,22 +531,22 @@ bool Channels::ParseTitleDir(char *path, int language)
while ((dirent = readdir(dir)) != 0) while ((dirent = readdir(dir)) != 0)
{ {
if(!dirent->d_name) if (!dirent->d_name)
continue; continue;
//these can't be booted anyways //these can't be booted anyways
if(*dirent->d_name == '.' || strcmp(dirent->d_name, "48414141") == 0 || strcmp(dirent->d_name, "48414641") == 0) if (*dirent->d_name == '.' || strcmp(dirent->d_name, "48414141") == 0 || strcmp(dirent->d_name, "48414641") == 0)
{ {
continue; 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) if (stat(path, &st) != 0)
continue; continue;
// check if content in tmd exists // check if content in tmd exists
if(!emuExists(path)) if (!emuExists(path))
continue; continue;
u32 tidLow = strtoul(dirent->d_name, NULL, 16); u32 tidLow = strtoul(dirent->d_name, NULL, 16);
@ -537,20 +554,20 @@ bool Channels::ParseTitleDir(char *path, int language)
memset(id, 0, sizeof(id)); memset(id, 0, sizeof(id));
memcpy(id, &tidLow, 4); memcpy(id, &tidLow, 4);
u64 tid = ((u64)tidHigh << 32) | ((u64) tidLow); u64 tid = ((u64)tidHigh << 32) | ((u64)tidLow);
// Force old and new format to be "JODI" which is known by GameTDB // Force old and new format to be "JODI" which is known by GameTDB
if(tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL) if (tid == 0x000100014c554c5aLL || tid == 0x00010001AF1BF516LL || tid == 0x0001000148415858LL)
strcpy(id, "JODI"); strcpy(id, "JODI");
std::string TitleName; std::string TitleName;
const char *title = GameTitles.GetTitle(id); const char *title = GameTitles.GetTitle(id);
if(title && *title != '\0') if (title && *title != '\0')
{ {
TitleName = title; TitleName = title;
} }
else if(GetEmuChanTitle(path, language, TitleName)) else if (GetEmuChanTitle(path, language, TitleName))
{ {
GameTitles.SetGameTitle(id, TitleName.c_str()); GameTitles.SetGameTitle(id, TitleName.c_str());
} }
@ -565,7 +582,7 @@ bool Channels::ParseTitleDir(char *path, int language)
memcpy(EmuChannels[s].id, id, 4); memcpy(EmuChannels[s].id, id, 4);
EmuChannels[s].tid = tid; EmuChannels[s].tid = tid;
EmuChannels[s].type = TYPE_GAME_EMUNANDCHAN; EmuChannels[s].type = TYPE_GAME_EMUNANDCHAN;
strncpy(EmuChannels[s].title, TitleName.c_str(), sizeof(EmuChannels[s].title)-1); strncpy(EmuChannels[s].title, TitleName.c_str(), sizeof(EmuChannels[s].title) - 1);
} }
closedir(dir); closedir(dir);
@ -578,19 +595,19 @@ bool Channels::GetEmuChanTitle(char *tmdpath, int language, std::string &Title)
u8 *buffer = NULL; u8 *buffer = NULL;
u32 size = 0; u32 size = 0;
if(LoadFileToMem(tmdpath, &buffer, &size) < 0) if (LoadFileToMem(tmdpath, &buffer, &size) < 0)
return false; return false;
signed_blob *s_tmd = (signed_blob *) buffer; signed_blob *s_tmd = (signed_blob *)buffer;
u32 i; u32 i;
tmd *titleTmd = (tmd *) SIGNATURE_PAYLOAD(s_tmd); tmd *titleTmd = (tmd *)SIGNATURE_PAYLOAD(s_tmd);
for (i = 0; i < titleTmd->num_contents; i++) for (i = 0; i < titleTmd->num_contents; i++)
if (!titleTmd->contents[i].index) if (!titleTmd->contents[i].index)
break; break;
if(i == titleTmd->num_contents) if (i == titleTmd->num_contents)
{ {
free(buffer); free(buffer);
return false; return false;
@ -601,30 +618,30 @@ bool Channels::GetEmuChanTitle(char *tmdpath, int language, std::string &Title)
free(buffer); free(buffer);
char *ptr = strrchr(tmdpath, '/'); char *ptr = strrchr(tmdpath, '/');
if(!ptr) if (!ptr)
return false; return false;
//! tmdpath has length of 1024 //! tmdpath has length of 1024
snprintf(ptr+1, 1024-(ptr+1-tmdpath), "%08x.app", (unsigned int)cid); snprintf(ptr + 1, 1024 - (ptr + 1 - tmdpath), "%08x.app", (unsigned int)cid);
FILE *f = fopen(tmdpath, "rb"); FILE *f = fopen(tmdpath, "rb");
if(!f) if (!f)
return false; return false;
if(fseek(f, IMET_OFFSET, SEEK_SET) != 0) if (fseek(f, IMET_OFFSET, SEEK_SET) != 0)
{ {
fclose(f); fclose(f);
return false; return false;
} }
IMET *imet = (IMET*) malloc(sizeof(IMET)); IMET *imet = (IMET *)malloc(sizeof(IMET));
if(!imet) if (!imet)
{ {
fclose(f); fclose(f);
return false; return false;
} }
if(fread(imet, 1, sizeof(IMET), f) != sizeof(IMET)) if (fread(imet, 1, sizeof(IMET), f) != sizeof(IMET))
{ {
free(imet); free(imet);
fclose(f); fclose(f);
@ -642,7 +659,7 @@ bool Channels::GetEmuChanTitle(char *tmdpath, int language, std::string &Title)
// names not available // names not available
if (imet->name_japanese[language * IMET_MAX_NAME_LEN] == 0) if (imet->name_japanese[language * IMET_MAX_NAME_LEN] == 0)
{ {
if(imet->name_english[0] != 0) if (imet->name_english[0] != 0)
language = CONF_LANG_ENGLISH; language = CONF_LANG_ENGLISH;
else else
{ {
@ -665,14 +682,14 @@ bool Channels::GetEmuChanTitle(char *tmdpath, int language, std::string &Title)
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; u8 *banner = NULL;
u32 high = TITLE_UPPER(title); u32 high = TITLE_UPPER(title);
u32 low = TITLE_LOWER(title); u32 low = TITLE_LOWER(title);
char *filepath = (char *) memalign(32, ISFS_MAXPATH + strlen(pathPrefix)); char *filepath = (char *)memalign(32, ISFS_MAXPATH + strlen(pathPrefix));
if(!filepath) if (!filepath)
return NULL; return NULL;
do do
@ -684,7 +701,7 @@ u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPre
int ret = 0; int ret = 0;
if(pathPrefix && *pathPrefix != 0) if (pathPrefix && *pathPrefix != 0)
ret = LoadFileToMem(filepath, &buffer, &filesize); ret = LoadFileToMem(filepath, &buffer, &filesize);
else else
ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize);
@ -692,12 +709,12 @@ u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPre
if (ret < 0) if (ret < 0)
break; break;
_tmd * tmd_file = (_tmd *) SIGNATURE_PAYLOAD((u32 *)buffer); _tmd *tmd_file = (_tmd *)SIGNATURE_PAYLOAD((u32 *)buffer);
bool found = false; bool found = false;
u32 bootcontent = 0; u32 bootcontent = 0;
for(u32 i = 0; i < tmd_file->num_contents; ++i) for (u32 i = 0; i < tmd_file->num_contents; ++i)
{ {
if(tmd_file->contents[i].index == 0) if (tmd_file->contents[i].index == 0)
{ {
bootcontent = tmd_file->contents[i].cid; bootcontent = tmd_file->contents[i].cid;
found = true; found = true;
@ -709,12 +726,12 @@ u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPre
buffer = NULL; buffer = NULL;
filesize = 0; filesize = 0;
if(!found) if (!found)
break; 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) if (pathPrefix && *pathPrefix != 0)
ret = LoadFileToMem(filepath, &buffer, &filesize); ret = LoadFileToMem(filepath, &buffer, &filesize);
else else
ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize); ret = NandTitle::LoadFileFromNand(filepath, &buffer, &filesize);
@ -722,8 +739,8 @@ u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPre
if (ret < 0) if (ret < 0)
break; break;
IMET *imet = (IMET *) (buffer + IMET_OFFSET); IMET *imet = (IMET *)(buffer + IMET_OFFSET);
if(imet->sig != 'IMET') if (imet->sig != 'IMET')
{ {
free(buffer); free(buffer);
break; break;
@ -732,8 +749,8 @@ u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPre
// move IMET_OFFSET bytes back // move IMET_OFFSET bytes back
filesize -= IMET_OFFSET; filesize -= IMET_OFFSET;
banner = (u8 *) memalign(32, filesize); banner = (u8 *)memalign(32, filesize);
if(!banner) if (!banner)
{ {
free(buffer); free(buffer);
break; break;
@ -743,10 +760,9 @@ u8 *Channels::GetOpeningBnr(const u64 &title, u32 * outsize, const char *pathPre
free(buffer); free(buffer);
if(outsize) if (outsize)
*outsize = filesize; *outsize = filesize;
} } while (0);
while(0);
free(filepath); free(filepath);

View File

@ -17,6 +17,7 @@
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "GCGames.h" #include "GCGames.h"
#include "FileOperations/fileops.h" #include "FileOperations/fileops.h"
#include "settings/GameTitles.h" #include "settings/GameTitles.h"
@ -30,13 +31,14 @@
#include "system/IosLoader.h" #include "system/IosLoader.h"
#include "menu.h" #include "menu.h"
#include "gecko.h" #include "gecko.h"
#include "cache/cache.hpp"
GCGames *GCGames::instance = NULL; GCGames *GCGames::instance = NULL;
inline bool isGameID(const u8 *id) inline bool isGameID(const u8 *id)
{ {
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
if (!isalnum((int) id[i])) if (!isalnum((int)id[i]))
return false; return false;
return true; return true;
@ -44,12 +46,12 @@ inline bool isGameID(const u8 *id)
const char *GCGames::GetPath(const char *gameID) const const char *GCGames::GetPath(const char *gameID) const
{ {
if(!gameID) if (!gameID)
return ""; 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(); return PathList[i].c_str();
} }
@ -68,15 +70,17 @@ void GCGames::LoadGameList(const string &path, vector<struct discHdr> &headerLis
struct dirent *dirent; struct dirent *dirent;
dir_iter = opendir(path.c_str()); dir_iter = opendir(path.c_str());
if (!dir_iter) return; if (!dir_iter)
return;
while ((dirent = readdir(dir_iter)) != 0) while ((dirent = readdir(dir_iter)) != 0)
{ {
const char *dirname = dirent->d_name; const char *dirname = dirent->d_name;
if(!dirname) if (!dirname)
continue; continue;
if (dirname[0] == '.') continue; if (dirname[0] == '.')
continue;
// reset id and title // reset id and title
memset(id, 0, sizeof(id)); memset(id, 0, sizeof(id));
@ -87,7 +91,7 @@ void GCGames::LoadGameList(const string &path, vector<struct discHdr> &headerLis
int len = strlen(dirname); int len = strlen(dirname);
if (len >= 8) 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 // path/TITLE[GAMEID]/game.iso
lay_b = true; lay_b = true;
@ -97,42 +101,43 @@ void GCGames::LoadGameList(const string &path, vector<struct discHdr> &headerLis
// path/GAMEID_TITLE/game.iso // path/GAMEID_TITLE/game.iso
memcpy(id, dirname, 6); memcpy(id, dirname, 6);
if(isGameID(id)) if (isGameID(id))
{ {
lay_a = true; lay_a = true;
snprintf(fname_title, sizeof(fname_title), "%s", &dirname[7]); 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); memcpy(id, dirname, 6);
lay_a = true; lay_a = true;
} }
if(!lay_a && !lay_b) if (!lay_a && !lay_b)
memset(id, 0, sizeof(id)); memset(id, 0, sizeof(id));
bool found = false; bool found = false;
bool extracted = false; bool extracted = false;
for(int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
char name[50]; 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); 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; break;
} }
// Check if only disc2.iso is present // 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]; char name[50];
snprintf(name, sizeof(name), "disc2.%s", (i % 2) == 0 ? "gcm" : "iso"); // allow gcm, though DM(L) require "disc2.iso" filename 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); 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; disc_number = 1;
break; break;
@ -140,17 +145,18 @@ void GCGames::LoadGameList(const string &path, vector<struct discHdr> &headerLis
} }
} }
if(!found) if (!found)
{ {
snprintf(fpath, sizeof(fpath), "%s%s/sys/boot.bin", path.c_str(), dirname); snprintf(fpath, sizeof(fpath), "%s%s/sys/boot.bin", path.c_str(), dirname);
if(stat(fpath, &st) != 0) if (stat(fpath, &st) != 0)
continue; continue;
// this game is extracted // this game is extracted
extracted = true; extracted = true;
} }
//! GAMEID was not found //! GAMEID was not found
if(!lay_a && !lay_b) { if (!lay_a && !lay_b)
{
// read game ID and title from disc header // read game ID and title from disc header
// iso file // iso file
FILE *fp = fopen(fpath, "rb"); FILE *fp = fopen(fpath, "rb");
@ -180,7 +186,7 @@ void GCGames::LoadGameList(const string &path, vector<struct discHdr> &headerLis
string gamePath = string(path) + dirname + (extracted ? "/" : strrchr(fpath, '/')); string gamePath = string(path) + dirname + (extracted ? "/" : strrchr(fpath, '/'));
memset(&tmpHdr, 0, sizeof(tmpHdr)); memset(&tmpHdr, 0, sizeof(tmpHdr));
memcpy(tmpHdr.id, id, 6); 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.magic = GCGames::MAGIC;
tmpHdr.type = extracted ? TYPE_GAME_GC_EXTRACTED : TYPE_GAME_GC_IMG; tmpHdr.type = extracted ? TYPE_GAME_GC_EXTRACTED : TYPE_GAME_GC_IMG;
tmpHdr.disc_no = disc_number; tmpHdr.disc_no = disc_number;
@ -217,29 +223,37 @@ void GCGames::LoadGameList(const string &path, vector<struct discHdr> &headerLis
u32 GCGames::LoadAllGames(void) 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(); PathList.clear();
HeaderList.clear(); HeaderList.clear();
sdGCList.clear(); sdGCList.clear();
sdGCPathList.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); 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); 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; 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. //! 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) || 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 (Settings.GameCubeSource == GC_SOURCE_AUTO && (IosLoader::GetMIOSInfo() == DIOS_MIOS || IosLoader::GetMIOSInfo() == QUADFORCE_USB))) // DIOS MIOS - Show the game on USB in priority
{ {
break; break;
@ -254,7 +268,8 @@ u32 GCGames::LoadAllGames(void)
} }
// Not available in the main GC path // Not available in the main GC path
if(n == HeaderList.size()) { if (n == HeaderList.size())
{
HeaderList.push_back(sdGCList[i]); HeaderList.push_back(sdGCList[i]);
PathList.push_back(sdGCPathList[i]); PathList.push_back(sdGCPathList[i]);
} }
@ -267,30 +282,33 @@ u32 GCGames::LoadAllGames(void)
} }
} }
if (Settings.UseGameHeaderCache && !HeaderList.empty() && !PathList.empty())
SaveGameHeaderCache(HeaderList, PathList);
return HeaderList.size(); return HeaderList.size();
} }
bool GCGames::RemoveGame(const char *gameID) bool GCGames::RemoveGame(const char *gameID)
{ {
const char *path = GetPath(gameID); const char *path = GetPath(gameID);
if(*path == 0) if (*path == 0)
return false; return false;
RemoveSDGame(gameID); RemoveSDGame(gameID);
if(strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0) if (strcmp(Settings.GameCubePath, Settings.GameCubeSDPath) == 0)
return true; return true;
struct discHdr *header = NULL; 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]; header = &HeaderList[i];
break; break;
} }
} }
if(!header) if (!header)
return false; return false;
char filepath[512]; char filepath[512];
@ -300,24 +318,25 @@ bool GCGames::RemoveGame(const char *gameID)
char cIsoPath[256]; char cIsoPath[256];
snprintf(cIsoPath, sizeof(cIsoPath), "%s", path + strlen(Settings.GameCubeSDPath)); 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 // Remove game iso
snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath); snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath);
if(!RemoveFile(filepath)) if (!RemoveFile(filepath))
result = -1; result = -1;
// Remove path // Remove path
char *pathPtr = strrchr(filepath, '/'); char *pathPtr = strrchr(filepath, '/');
if(pathPtr) *pathPtr = 0; if (pathPtr)
if(!RemoveFile(filepath)) *pathPtr = 0;
if (!RemoveFile(filepath))
result = -1; result = -1;
} }
else if(header->type == TYPE_GAME_GC_EXTRACTED) else if (header->type == TYPE_GAME_GC_EXTRACTED)
{ {
//! remove extracted gamecube game //! remove extracted gamecube game
snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath); snprintf(filepath, sizeof(filepath), "%s%s", Settings.GameCubePath, cIsoPath);
if(!RemoveDirectory(path)) if (!RemoveDirectory(path))
result = -1; result = -1;
} }
@ -327,45 +346,46 @@ bool GCGames::RemoveGame(const char *gameID)
bool GCGames::RemoveSDGame(const char *gameID) bool GCGames::RemoveSDGame(const char *gameID)
{ {
const char *path = GetPath(gameID); const char *path = GetPath(gameID);
if(*path == 0) if (*path == 0)
return false; return false;
struct discHdr *header = NULL; 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]; header = &HeaderList[i];
break; break;
} }
} }
if(!header) if (!header)
return false; return false;
char filepath[512]; char filepath[512];
int result = 0; int result = 0;
int ret; int ret;
if(header->type == TYPE_GAME_GC_IMG) if (header->type == TYPE_GAME_GC_IMG)
{ {
// Remove game iso // Remove game iso
snprintf(filepath, sizeof(filepath), "%s", path); snprintf(filepath, sizeof(filepath), "%s", path);
ret = RemoveFile(filepath); ret = RemoveFile(filepath);
if(ret != 0) if (ret != 0)
result = -1; result = -1;
// Remove path // Remove path
char *pathPtr = strrchr(filepath, '/'); char *pathPtr = strrchr(filepath, '/');
if(pathPtr) *pathPtr = 0; if (pathPtr)
*pathPtr = 0;
ret = RemoveFile(filepath); ret = RemoveFile(filepath);
if(ret != 0) if (ret != 0)
result = -1; result = -1;
} }
else if(header->type == TYPE_GAME_GC_EXTRACTED) else if (header->type == TYPE_GAME_GC_EXTRACTED)
{ {
//! remove extracted gamecube game //! remove extracted gamecube game
ret = RemoveDirectory(path); ret = RemoveDirectory(path);
if(ret < 0) if (ret < 0)
result = -1; result = -1;
} }
@ -375,39 +395,39 @@ bool GCGames::RemoveSDGame(const char *gameID)
float GCGames::GetGameSize(const char *gameID) float GCGames::GetGameSize(const char *gameID)
{ {
const char *path = GetPath(gameID); const char *path = GetPath(gameID);
if(*path == 0) if (*path == 0)
return 0.0f; return 0.0f;
struct stat st; struct stat st;
if(stat(path, &st) != 0) if (stat(path, &st) != 0)
return 0.0f; 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 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. 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; 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]; char filepath[512];
int n = snprintf(filepath, sizeof(filepath), "%s", GetPath(gameID)); int n = snprintf(filepath, sizeof(filepath), "%s", GetPath(gameID));
char *pathPtr = strrchr(filepath, '/'); char *pathPtr = strrchr(filepath, '/');
if(pathPtr) *pathPtr = 0; if (pathPtr)
*pathPtr = 0;
snprintf(filepath + n, sizeof(filepath) - n, "/disc2.iso"); snprintf(filepath + n, sizeof(filepath) - n, "/disc2.iso");
if (CheckFile(filepath))
if(CheckFile(filepath))
return true; return true;
} }
} }
@ -417,18 +437,18 @@ bool GCGames::IsInstalled(const char *gameID, u8 disc_number) const
bool GCGames::CopyUSB2SD(const struct discHdr *header) 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; int oldGameCubeSource = Settings.GameCubeSource;
if(*path == 0) if (*path == 0)
return false; 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")); 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; return false;
const char *cpTitle = GameTitles.GetTitle(header); const char *cpTitle = GameTitles.GetTitle(header);
if(choice == 2) if (choice == 2)
{ {
// Load Games from SD card only // Load Games from SD card only
Settings.GameCubeSource = GC_SOURCE_SD; Settings.GameCubeSource = GC_SOURCE_SD;
@ -443,7 +463,8 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header)
gcDeleteMenu.Show(); gcDeleteMenu.Show();
gcDeleteMenu.SetEffect(EFFECT_FADE, -20); gcDeleteMenu.SetEffect(EFFECT_FADE, -20);
while(gcDeleteMenu.GetEffect() > 0) usleep(1000); while (gcDeleteMenu.GetEffect() > 0)
usleep(1000);
mainWindow->Remove(&gcDeleteMenu); mainWindow->Remove(&gcDeleteMenu);
mainWindow->SetState(STATE_DEFAULT); mainWindow->SetState(STATE_DEFAULT);
@ -452,12 +473,12 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header)
Settings.GameCubeSource = oldGameCubeSource; Settings.GameCubeSource = oldGameCubeSource;
GCGames::Instance()->LoadAllGames(); 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; return false;
} }
struct statvfs sd_vfs; 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")); WindowPrompt(tr("Error:"), tr("SD Card could not be accessed."), tr("OK"));
return false; return false;
@ -465,20 +486,22 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header)
u64 filesize = 0; u64 filesize = 0;
if(header->type == TYPE_GAME_GC_IMG) { if (header->type == TYPE_GAME_GC_IMG)
{
filesize = FileSize(path); 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); StartProgress(tr("Getting game folder size..."), tr("Please wait"), 0, true, true);
ShowProgress(0, 1); ShowProgress(0, 1);
filesize = FileSize(path); filesize = FileSize(path);
ProgressStop(); 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")); 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; return false;
GCDeleteMenu gcDeleteMenu; GCDeleteMenu gcDeleteMenu;
@ -490,7 +513,8 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header)
gcDeleteMenu.Show(); gcDeleteMenu.Show();
gcDeleteMenu.SetEffect(EFFECT_FADE, -20); gcDeleteMenu.SetEffect(EFFECT_FADE, -20);
while(gcDeleteMenu.GetEffect() > 0) usleep(1000); while (gcDeleteMenu.GetEffect() > 0)
usleep(1000);
mainWindow->Remove(&gcDeleteMenu); mainWindow->Remove(&gcDeleteMenu);
mainWindow->SetState(STATE_DEFAULT); mainWindow->SetState(STATE_DEFAULT);
@ -504,13 +528,14 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header)
int res = -1; int res = -1;
if(header->type == TYPE_GAME_GC_IMG) if (header->type == TYPE_GAME_GC_IMG)
{ {
ProgressCancelEnable(true); ProgressCancelEnable(true);
StartProgress(tr("Copying GC game..."), cpTitle, 0, true, true); StartProgress(tr("Copying GC game..."), cpTitle, 0, true, true);
char *ptr = strrchr(destPath, '/'); char *ptr = strrchr(destPath, '/');
if(ptr) *ptr = 0; if (ptr)
*ptr = 0;
CreateSubfolder(destPath); CreateSubfolder(destPath);
@ -518,7 +543,7 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header)
res = CopyFile(path, destPath); res = CopyFile(path, destPath);
} }
else if(header->type == TYPE_GAME_GC_EXTRACTED) else if (header->type == TYPE_GAME_GC_EXTRACTED)
{ {
res = CopyDirectory(path, destPath); res = CopyDirectory(path, destPath);
} }
@ -529,28 +554,30 @@ bool GCGames::CopyUSB2SD(const struct discHdr *header)
ProgressStop(); ProgressStop();
ProgressCancelEnable(false); 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 // remove file and path
RemoveFile(destPath); RemoveFile(destPath);
char *ptr = strrchr(destPath, '/'); char *ptr = strrchr(destPath, '/');
if(ptr) *ptr = 0; if (ptr)
*ptr = 0;
RemoveFile(destPath); RemoveFile(destPath);
} }
WindowPrompt(tr("Copying Canceled"), 0, tr("OK")); WindowPrompt(tr("Copying Canceled"), 0, tr("OK"));
return false; 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 // remove file and path
RemoveFile(destPath); RemoveFile(destPath);
char *ptr = strrchr(destPath, '/'); char *ptr = strrchr(destPath, '/');
if(ptr) *ptr = 0; if (ptr)
*ptr = 0;
RemoveFile(destPath); RemoveFile(destPath);
} }
@ -568,36 +595,36 @@ int nintendontBuildDate(const char *NIN_loader_path, char *NINBuildDate)
char NIN_loader[100]; char NIN_loader[100];
snprintf(NIN_loader, sizeof(NIN_loader), "%sboot.dol", NIN_loader_path); 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); snprintf(NIN_loader, sizeof(NIN_loader), "%sloader.dol", NIN_loader_path);
if(CheckFile(NIN_loader)) if (CheckFile(NIN_loader))
{ {
u8 *buffer = NULL; u8 *buffer = NULL;
u32 filesize = 0; u32 filesize = 0;
const char* str = "Nintendont Loader"; const char *str = "Nintendont Loader";
bool found = false; 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 // Write buffer in NINheader
char NINHeader[100]; char NINHeader[100];
for(u8 j = 0 ; j < 99 ; j++) for (u8 j = 0; j < 99; j++)
NINHeader[j] = *(u8*)(buffer+i+j) == 0 ? ' ' : *(u8*)(buffer+i+j); // replace \0 with a space. NINHeader[j] = *(u8 *)(buffer + i + j) == 0 ? ' ' : *(u8 *)(buffer + i + j); // replace \0 with a space.
NINHeader[99] = '\0'; NINHeader[99] = '\0';
// Search month string start position in header // Search month string start position in header
char *dateStart = NULL; char *dateStart = NULL;
const char *month[] = {"Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ", "Jui ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "}; 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]); dateStart = strstr(NINHeader, month[m]);
if(dateStart != NULL) if (dateStart != NULL)
break; break;
} }
if(dateStart == NULL) if (dateStart == NULL)
break; break;
dateStart[20] = '\0'; dateStart[20] = '\0';
@ -611,7 +638,7 @@ int nintendontBuildDate(const char *NIN_loader_path, char *NINBuildDate)
} }
free(buffer); free(buffer);
} }
if(found) if (found)
return 1; return 1;
} }
@ -623,22 +650,22 @@ int nintendontVersion(const char *NIN_loader_path, char *NINVersion, int len)
char NIN_loader[100]; char NIN_loader[100];
u32 NINRev = 0; u32 NINRev = 0;
snprintf(NIN_loader, sizeof(NIN_loader), "%sboot.dol", NIN_loader_path); 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); snprintf(NIN_loader, sizeof(NIN_loader), "%sloader.dol", NIN_loader_path);
if(CheckFile(NIN_loader)) if (CheckFile(NIN_loader))
{ {
u8 *buffer = NULL; u8 *buffer = NULL;
u32 filesize = 0; u32 filesize = 0;
const char* str = "$$Version:"; const char *str = "$$Version:";
if(LoadFileToMem(NIN_loader, &buffer, &filesize)) 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 // Write buffer in NINVersion
snprintf(NINVersion, len, "%s", buffer+i+strlen(str)); snprintf(NINVersion, len, "%s", buffer + i + strlen(str));
NINRev = atoi(strchr(NINVersion, '.')+1); NINRev = atoi(strchr(NINVersion, '.') + 1);
break; break;
} }
} }

338
source/cache/cache.cpp vendored Normal file
View File

@ -0,0 +1,338 @@
/*
Code by Oddx @ GBAtemp.net
Loosely based on emuNAND caching by geoGolem.
*/
#include <fstream>
#include <dirent.h>
#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<struct discHdr> &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<struct discHdr> &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<struct discHdr> &list, vector<int> &plist)
{
vector<struct wiiCache> wiictmp;
struct wiiCache gtmp;
for (u32 i = 0; i < list.size(); ++i)
{
memset(&gtmp, 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<struct discHdr> &list, vector<int> &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<struct discHdr> &list, vector<string> &plist)
{
vector<struct gcCache> gcctmp;
struct gcCache gtmp;
for (u32 i = 0; i < list.size(); ++i)
{
memset(&gtmp, 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<struct discHdr> &list, vector<string> &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<struct discHdr *> &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<struct gameHdr> 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<struct discHdr *> &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<struct discHdr> &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<struct discHdr> &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<struct discHdr> &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<struct discHdr> &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;
}

54
source/cache/cache.hpp vendored Normal file
View File

@ -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<struct discHdr> &list);
void LoadGameHeaderCache(vector<struct discHdr> &list);
// Wii
void SaveGameHeaderCache(vector<struct discHdr> &list, vector<int> &plist);
void LoadGameHeaderCache(vector<struct discHdr> &list, vector<int> &plist);
// GameCube
void SaveGameHeaderCache(vector<struct discHdr> &list, vector<string> &plist);
void LoadGameHeaderCache(vector<struct discHdr> &list, vector<string> &plist);
void ResetGameHeaderCache();
void SaveFilteredListCache(vector<struct discHdr *> &list, const wchar_t *gameFilter);
void LoadFilteredListCache(vector<struct discHdr *> &list, const wchar_t *gameFilter);
string FilteredListCacheFileName(const wchar_t *gameFilter);
string FilteredListCacheFileName();
bool isCacheFile(string filename);

View File

@ -11,6 +11,7 @@
#include "themes/CTheme.h" #include "themes/CTheme.h"
#include "utils/tools.h" #include "utils/tools.h"
#include "system/IosLoader.h" #include "system/IosLoader.h"
#include "cache/cache.hpp"
#define WII_MAGIC 0x5D1C9EA3 #define WII_MAGIC 0x5D1C9EA3
@ -287,6 +288,7 @@ int MenuInstall()
else else
{ {
ShowProgress(tr("Install finished"), headerdisc.title, tr("Reloading game list now, please wait..."), gamesize, gamesize, true, true); 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.ReadGameList(); //get the entries again
gameList.FilterList(); gameList.FilterList();
bgMusic->Pause(); bgMusic->Pause();

View File

@ -63,6 +63,7 @@ void CSettings::SetDefault()
snprintf(languagefiles_path, sizeof(languagefiles_path), "%slanguage/", ConfigPath); snprintf(languagefiles_path, sizeof(languagefiles_path), "%slanguage/", ConfigPath);
snprintf(update_path, sizeof(update_path), "%s/apps/usbloader_gx/", BootDevice); snprintf(update_path, sizeof(update_path), "%s/apps/usbloader_gx/", BootDevice);
snprintf(BNRCachePath, sizeof(BNRCachePath), "%s/apps/usbloader_gx/cache_bnr/", 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(homebrewapps_path, sizeof(homebrewapps_path), "%s/apps/", BootDevice);
snprintf(Cheatcodespath, sizeof(Cheatcodespath), "%s/codes/", BootDevice); snprintf(Cheatcodespath, sizeof(Cheatcodespath), "%s/codes/", BootDevice);
snprintf(TxtCheatcodespath, sizeof(TxtCheatcodespath), "%s/txtcodes/", BootDevice); snprintf(TxtCheatcodespath, sizeof(TxtCheatcodespath), "%s/txtcodes/", BootDevice);
@ -135,6 +136,7 @@ void CSettings::SetDefault()
musicloopmode = ON; musicloopmode = ON;
marknewtitles = ON; marknewtitles = ON;
ShowFreeSpace = ON; ShowFreeSpace = ON;
UseGameHeaderCache = OFF;
PlaylogUpdate = OFF; PlaylogUpdate = OFF;
ParentalBlocks = BLOCK_ALL; ParentalBlocks = BLOCK_ALL;
InstallToDir = INSTALL_TO_NAME_GAMEID; InstallToDir = INSTALL_TO_NAME_GAMEID;
@ -359,6 +361,7 @@ bool CSettings::Save()
fprintf(file, "update_path = %s\n", update_path); fprintf(file, "update_path = %s\n", update_path);
fprintf(file, "homebrewapps_path = %s\n", homebrewapps_path); fprintf(file, "homebrewapps_path = %s\n", homebrewapps_path);
fprintf(file, "BNRCachePath = %s\n", BNRCachePath); fprintf(file, "BNRCachePath = %s\n", BNRCachePath);
fprintf(file, "GameHeaderCachePath = %s\n", GameHeaderCachePath);
fprintf(file, "Cheatcodespath = %s\n", Cheatcodespath); fprintf(file, "Cheatcodespath = %s\n", Cheatcodespath);
fprintf(file, "BcaCodepath = %s\n", BcaCodepath); fprintf(file, "BcaCodepath = %s\n", BcaCodepath);
fprintf(file, "WipCodepath = %s\n", WipCodepath); fprintf(file, "WipCodepath = %s\n", WipCodepath);
@ -374,6 +377,7 @@ bool CSettings::Save()
fprintf(file, "partition = %d\n", partition); fprintf(file, "partition = %d\n", partition);
fprintf(file, "marknewtitles = %d\n", marknewtitles); fprintf(file, "marknewtitles = %d\n", marknewtitles);
fprintf(file, "ShowFreeSpace = %d\n", ShowFreeSpace); fprintf(file, "ShowFreeSpace = %d\n", ShowFreeSpace);
fprintf(file, "UseGameHeaderCache = %d\n", UseGameHeaderCache);
fprintf(file, "InstallToDir = %d\n", InstallToDir); fprintf(file, "InstallToDir = %d\n", InstallToDir);
fprintf(file, "GameSplit = %d\n", GameSplit); fprintf(file, "GameSplit = %d\n", GameSplit);
fprintf(file, "InstallPartitions = %08X\n", (unsigned int)InstallPartitions); fprintf(file, "InstallPartitions = %08X\n", (unsigned int)InstallPartitions);
@ -724,6 +728,11 @@ bool CSettings::SetSetting(char *name, char *value)
ShowFreeSpace = atoi(value); ShowFreeSpace = atoi(value);
return true; return true;
} }
else if (strcmp(name, "UseGameHeaderCache") == 0)
{
UseGameHeaderCache = atoi(value);
return true;
}
else if (strcmp(name, "HomeMenu") == 0) else if (strcmp(name, "HomeMenu") == 0)
{ {
HomeMenu = atoi(value); HomeMenu = atoi(value);
@ -1238,6 +1247,11 @@ bool CSettings::SetSetting(char *name, char *value)
strlcpy(BNRCachePath, value, sizeof(BNRCachePath)); strlcpy(BNRCachePath, value, sizeof(BNRCachePath));
return true; return true;
} }
else if (strcmp(name, "GameHeaderCachePath") == 0)
{
strlcpy(GameHeaderCachePath, value, sizeof(GameHeaderCachePath));
return true;
}
else if (strcmp(name, "Cheatcodespath") == 0) else if (strcmp(name, "Cheatcodespath") == 0)
{ {
strlcpy(Cheatcodespath, value, sizeof(Cheatcodespath)); strlcpy(Cheatcodespath, value, sizeof(Cheatcodespath));

View File

@ -85,6 +85,7 @@ class CSettings
char NandEmuPath[50]; char NandEmuPath[50];
char NandEmuChanPath[50]; char NandEmuChanPath[50];
char BNRCachePath[50]; char BNRCachePath[50];
char GameHeaderCachePath[50];
char GameCubePath[100]; char GameCubePath[100];
char GameCubeSDPath[100]; char GameCubeSDPath[100];
char DEVOLoaderPath[100]; char DEVOLoaderPath[100];
@ -142,6 +143,7 @@ class CSettings
short GameSplit; short GameSplit;
short PlaylogUpdate; short PlaylogUpdate;
short ShowFreeSpace; short ShowFreeSpace;
short UseGameHeaderCache;
short HomeMenu; short HomeMenu;
short MultiplePartitions; short MultiplePartitions;
short USBPort; short USBPort;

View File

@ -65,6 +65,7 @@ CustomPathsSM::CustomPathsSM()
Options->SetName(Idx++, tr("Devolution Loader Path")); Options->SetName(Idx++, tr("Devolution Loader Path"));
Options->SetName(Idx++, tr("Nintendont Loader Path")); Options->SetName(Idx++, tr("Nintendont Loader Path"));
Options->SetName(Idx++, tr("Cache BNR Files Path")); Options->SetName(Idx++, tr("Cache BNR Files Path"));
Options->SetName(Idx++, tr("Game Header Cache Files Path"));
SetOptionValues(); SetOptionValues();
} }
@ -141,6 +142,9 @@ void CustomPathsSM::SetOptionValues()
//! Settings: Cache BNR Files Path //! Settings: Cache BNR Files Path
Options->SetValue(Idx++, Settings.BNRCachePath); Options->SetValue(Idx++, Settings.BNRCachePath);
//! Settings: Game Header Cache Files Path
Options->SetValue(Idx++, Settings.GameHeaderCachePath);
} }
int CustomPathsSM::GetMenuInternal() int CustomPathsSM::GetMenuInternal()
@ -368,6 +372,13 @@ int CustomPathsSM::GetMenuInternal()
ChangePath(Settings.BNRCachePath, sizeof(Settings.BNRCachePath)); 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 //! Global set back of the titleTxt after a change
titleTxt->SetText(tr( "Custom Paths" )); titleTxt->SetText(tr( "Custom Paths" ));
SetOptionValues(); SetOptionValues();

View File

@ -24,6 +24,7 @@
#include <gccore.h> #include <gccore.h>
#include <ogc/machine/processor.h> #include <ogc/machine/processor.h>
#include <unistd.h> #include <unistd.h>
#include "FeatureSettingsMenu.hpp" #include "FeatureSettingsMenu.hpp"
#include "Channels/channels.h" #include "Channels/channels.h"
#include "settings/CGameCategories.hpp" #include "settings/CGameCategories.hpp"
@ -44,6 +45,7 @@
#include "wad/nandtitle.h" #include "wad/nandtitle.h"
#include "wad/wad.h" #include "wad/wad.h"
#include "sys.h" #include "sys.h"
#include "cache/cache.hpp"
static const char * OnOffText[] = static const char * OnOffText[] =
{ {
@ -64,6 +66,7 @@ FeatureSettingsMenu::FeatureSettingsMenu()
int Idx = 0; int Idx = 0;
Options->SetName(Idx++, "%s", tr( "Titles from GameTDB" )); Options->SetName(Idx++, "%s", tr( "Titles from GameTDB" ));
Options->SetName(Idx++, "%s", tr( "Cache Titles" )); 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( "Force Titles from Disc" ));
Options->SetName(Idx++, "%s", tr( "Wiilight" )); Options->SetName(Idx++, "%s", tr( "Wiilight" ));
Options->SetName(Idx++, "%s", tr( "Rumble" )); Options->SetName(Idx++, "%s", tr( "Rumble" ));
@ -80,6 +83,7 @@ FeatureSettingsMenu::FeatureSettingsMenu()
// Options->SetName(Idx++, "%s", tr( "Update Nintendont" )); // Options->SetName(Idx++, "%s", tr( "Update Nintendont" ));
Options->SetName(Idx++, "%s", tr( "WiiU Widescreen" )); Options->SetName(Idx++, "%s", tr( "WiiU Widescreen" ));
Options->SetName(Idx++, "%s", tr( "Boot Neek System Menu" )); Options->SetName(Idx++, "%s", tr( "Boot Neek System Menu" ));
Options->SetName(Idx++, "%s", tr( "Reset Game Header Cache" ));
OldTitlesOverride = Settings.titlesOverride; OldTitlesOverride = Settings.titlesOverride;
OldCacheTitles = Settings.CacheTitles; OldCacheTitles = Settings.CacheTitles;
@ -121,6 +125,9 @@ void FeatureSettingsMenu::SetOptionValues()
//! Settings: Cache Titles //! Settings: Cache Titles
Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.CacheTitles] )); 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 //! Settings: Force Titles from Disc
Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.ForceDiscTitles] )); Options->SetValue(Idx++, "%s", tr( OnOffText[Settings.ForceDiscTitles] ));
@ -193,6 +200,12 @@ int FeatureSettingsMenu::GetMenuInternal()
if (++Settings.CacheTitles >= MAX_ON_OFF) Settings.CacheTitles = 0; 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 //! Settings: Force Titles from Disc
else if (ret == ++Idx) else if (ret == ++Idx)
{ {
@ -532,6 +545,7 @@ int FeatureSettingsMenu::GetMenuInternal()
} }
// Refresh new EmuNAND content // Refresh new EmuNAND content
ResetGameHeaderCache();
Channels::Instance()->GetEmuChannelList(); Channels::Instance()->GetEmuChannelList();
GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path);
} }
@ -622,6 +636,7 @@ int FeatureSettingsMenu::GetMenuInternal()
} }
// Refresh new EmuNAND content // Refresh new EmuNAND content
ResetGameHeaderCache();
Channels::Instance()->GetEmuChannelList(); Channels::Instance()->GetEmuChannelList();
GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path); GameTitles.LoadTitlesFromGameTDB(Settings.titlestxt_path);
} }
@ -744,6 +759,17 @@ int FeatureSettingsMenu::GetMenuInternal()
} }
} }
} }
//! 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(); SetOptionValues();
return MENU_NONE; return MENU_NONE;

View File

@ -22,6 +22,7 @@
* distribution. * distribution.
***************************************************************************/ ***************************************************************************/
#include <unistd.h> #include <unistd.h>
#include "UninstallSM.hpp" #include "UninstallSM.hpp"
#include "FileOperations/fileops.h" #include "FileOperations/fileops.h"
#include "GameCube/GCGames.h" #include "GameCube/GCGames.h"
@ -35,6 +36,7 @@
#include "usbloader/wbfs.h" #include "usbloader/wbfs.h"
#include "usbloader/GameList.h" #include "usbloader/GameList.h"
#include "wstring.hpp" #include "wstring.hpp"
#include "cache/cache.hpp"
UninstallSM::UninstallSM(struct discHdr * header) UninstallSM::UninstallSM(struct discHdr * header)
: SettingsMenu(tr("Uninstall Menu"), &GuiOptions, MENU_NONE) : SettingsMenu(tr("Uninstall Menu"), &GuiOptions, MENU_NONE)
@ -127,6 +129,7 @@ int UninstallSM::GetMenuInternal()
if(ret >= 0) if(ret >= 0)
{ {
wString oldFilter(gameList.GetCurrentFilter()); wString oldFilter(gameList.GetCurrentFilter());
ResetGameHeaderCache();
gameList.ReadGameList(); gameList.ReadGameList();
gameList.FilterList(oldFilter.c_str()); gameList.FilterList(oldFilter.c_str());
} }
@ -134,6 +137,7 @@ int UninstallSM::GetMenuInternal()
else if(DiscHeader->type == TYPE_GAME_GC_IMG) else if(DiscHeader->type == TYPE_GAME_GC_IMG)
{ {
GCGames::Instance()->RemoveGame(GameID); GCGames::Instance()->RemoveGame(GameID);
ResetGameHeaderCache();
// Reload list // Reload list
GCGames::Instance()->LoadAllGames(); 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); snprintf(filepath, sizeof(filepath), "%s/title/%08x/%08x/", Settings.NandEmuChanPath, (unsigned int) (DiscHeader->tid >> 32), (unsigned int) DiscHeader->tid);
RemoveDirectory(filepath); RemoveDirectory(filepath);
ResetGameHeaderCache();
Channels::Instance()->GetEmuChannelList(); Channels::Instance()->GetEmuChannelList();
} }

View File

@ -24,6 +24,7 @@
#include <algorithm> #include <algorithm>
#include <string> #include <string>
#include <malloc.h> #include <malloc.h>
#include "GUI/gui_searchbar.h" #include "GUI/gui_searchbar.h"
#include "usbloader/wbfs.h" #include "usbloader/wbfs.h"
#include "GameCube/GCGames.h" #include "GameCube/GCGames.h"
@ -37,8 +38,14 @@
#include "GameList.h" #include "GameList.h"
#include "memory/memory.h" #include "memory/memory.h"
#include "Channels/channels.h" #include "Channels/channels.h"
#include "cache/cache.hpp"
enum { DISABLED, ENABLED, HIDEFORBIDDEN }; enum
{
DISABLED,
ENABLED,
HIDEFORBIDDEN
};
GameList gameList; GameList gameList;
@ -54,13 +61,14 @@ void GameList::clear()
std::vector<int>().swap(GamePartitionList); std::vector<int>().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) 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]; return FilteredList[i];
} }
@ -69,11 +77,12 @@ struct discHdr * GameList::GetDiscHeader(const char * gameID) const
int GameList::GetPartitionNumber(const u8 *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) 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]; return GamePartitionList[i];
} }
@ -82,17 +91,17 @@ int GameList::GetPartitionNumber(const u8 *gameID) const
void GameList::RemovePartition(int part) 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); FullGameList.erase(FullGameList.begin() + i);
GamePartitionList.erase(GamePartitionList.begin()+i); GamePartitionList.erase(GamePartitionList.begin() + i);
--i; --i;
} }
} }
if(FullGameList.size() > 0) if (FullGameList.size() > 0)
FilterList(); FilterList();
} }
@ -102,18 +111,20 @@ int GameList::InternalReadList(int part)
u32 cnt = 0; u32 cnt = 0;
int ret = WBFS_GetCount(part, &cnt); 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 // We are done here if no games are there
if(cnt == 0) if (cnt == 0)
return 0; return 0;
/* Buffer length */ /* Buffer length */
u32 len = sizeof(struct discHdr) * cnt; u32 len = sizeof(struct discHdr) * cnt;
/* Allocate memory */ /* Allocate memory */
struct discHdr *buffer = (struct discHdr *) allocate_memory( len ); struct discHdr *buffer = (struct discHdr *)allocate_memory(len);
if (!buffer) return -1; if (!buffer)
return -1;
/* Clear buffer */ /* Clear buffer */
memset(buffer, 0, len); memset(buffer, 0, len);
@ -133,22 +144,22 @@ int GameList::InternalReadList(int part)
for (u32 i = 0; i < PartGameList.size(); i++) 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; --i;
break; break;
} }
} }
} }
FullGameList.resize(oldSize+PartGameList.size()); FullGameList.resize(oldSize + PartGameList.size());
memcpy(&FullGameList[oldSize], &PartGameList[0], PartGameList.size()*sizeof(struct discHdr)); 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; GamePartitionList[i] = part;
return PartGameList.size(); return PartGameList.size();
@ -156,6 +167,13 @@ int GameList::InternalReadList(int part)
int GameList::ReadGameList() 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 // Clear list
FullGameList.clear(); FullGameList.clear();
GamePartitionList.clear(); GamePartitionList.clear();
@ -165,7 +183,7 @@ int GameList::ReadGameList()
int cnt = 0; int cnt = 0;
if(!Settings.MultiplePartitions) if (!Settings.MultiplePartitions)
{ {
cnt = InternalReadList(Settings.partition); cnt = InternalReadList(Settings.partition);
} }
@ -173,13 +191,17 @@ int GameList::ReadGameList()
{ {
int partitions = DeviceHandler::GetUSBPartitionCount(); int partitions = DeviceHandler::GetUSBPartitionCount();
for(int part = 0; part < partitions; ++part) for (int part = 0; part < partitions; ++part)
{ {
int ret = InternalReadList(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; return cnt;
} }
@ -195,23 +217,25 @@ void GameList::InternalFilterList(std::vector<struct discHdr> &FullList)
/* Filters */ /* Filters */
if (Settings.GameSort & SORT_FAVORITE) if (Settings.GameSort & SORT_FAVORITE)
{ {
GameStatus * GameStats = GameStatistics.GetGameStatus(header->id); GameStatus *GameStats = GameStatistics.GetGameStatus(header->id);
if (Settings.marknewtitles) if (Settings.marknewtitles)
{ {
bool isNew = NewTitles::Instance()->IsNew(header->id); bool isNew = NewTitles::Instance()->IsNew(header->id);
if (!isNew && (!GameStats || GameStats->FavoriteRank == 0)) continue; if (!isNew && (!GameStats || GameStats->FavoriteRank == 0))
continue;
} }
else 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 //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; continue;
GameCFG * GameConfig = GameSettings.GetGameCFG(header); GameCFG *GameConfig = GameSettings.GetGameCFG(header);
/* Rating based parental control method */ /* Rating based parental control method */
if (Settings.parentalcontrol != PARENTAL_LVL_ADULT && !Settings.godmode) if (Settings.parentalcontrol != PARENTAL_LVL_ADULT && !Settings.godmode)
@ -220,79 +244,79 @@ void GameList::InternalFilterList(std::vector<struct discHdr> &FullList)
continue; continue;
// Check game rating in GameTDB, since the default Wii parental control setting is enabled // 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) if (rating > Settings.parentalcontrol)
continue; continue;
} }
//! Per game lock method //! Per game lock method
if(!Settings.godmode && GameConfig && GameConfig->Locked) if (!Settings.godmode && GameConfig && GameConfig->Locked)
continue; continue;
//! Category filter //! Category filter
u32 n; u32 n;
int allType = DISABLED; int allType = DISABLED;
// verify the display mode for category "All" // 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 allType = ENABLED; // All = Enabled
break; 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 allType = HIDEFORBIDDEN; // All = Enabled but hide Forbidden categories
break; break;
} }
} }
if(allType == DISABLED) if (allType == DISABLED)
{ {
// Remove TitleID if it contains a forbidden categories // 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; break;
} }
if(n < Settings.ForbiddenCategories.size()) if (n < Settings.ForbiddenCategories.size())
continue; continue;
// Remove TitleID is it doesn't contain a required categories // 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; break;
} }
if(n < Settings.RequiredCategories.size()) if (n < Settings.RequiredCategories.size())
continue; continue;
// If there's no required categories, verify if the TitleID should be kept or removed // 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; break;
} }
if(n == Settings.EnabledCategories.size()) if (n == Settings.EnabledCategories.size())
continue; continue;
} }
} }
if(allType == HIDEFORBIDDEN) if (allType == HIDEFORBIDDEN)
{ {
// Remove TitleID if it contains a forbidden categories // 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]))
if(Settings.ForbiddenCategories[n] >0) if (Settings.ForbiddenCategories[n] > 0)
break; break;
} }
if(n < Settings.ForbiddenCategories.size()) if (n < Settings.ForbiddenCategories.size())
continue; continue;
} }
@ -300,9 +324,9 @@ void GameList::InternalFilterList(std::vector<struct discHdr> &FullList)
} }
} }
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(); ReadGameList();
if (gameFilter) if (gameFilter)
@ -310,20 +334,28 @@ int GameList::FilterList(const wchar_t * gameFilter)
FilteredList.clear(); 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 // Filter current game list if selected
if(Settings.LoaderMode & MODE_WIIGAMES) if (Settings.LoaderMode & MODE_WIIGAMES)
InternalFilterList(FullGameList); InternalFilterList(FullGameList);
// Filter gc game list if selected // Filter gc game list if selected
if(Settings.LoaderMode & MODE_GCGAMES) if (Settings.LoaderMode & MODE_GCGAMES)
InternalFilterList(GCGames::Instance()->GetHeaders()); InternalFilterList(GCGames::Instance()->GetHeaders());
// Filter nand channel list if selected // Filter nand channel list if selected
if(Settings.LoaderMode & MODE_NANDCHANNELS) if (Settings.LoaderMode & MODE_NANDCHANNELS)
InternalFilterList(Channels::Instance()->GetNandHeaders()); InternalFilterList(Channels::Instance()->GetNandHeaders());
// Filter emu nand channel list if selected // Filter emu nand channel list if selected
if(Settings.LoaderMode & MODE_EMUCHANNELS) if (Settings.LoaderMode & MODE_EMUCHANNELS)
InternalFilterList(Channels::Instance()->GetEmuHeaders()); InternalFilterList(Channels::Instance()->GetEmuHeaders());
NewTitles::Instance()->Save(); NewTitles::Instance()->Save();
@ -331,6 +363,9 @@ int GameList::FilterList(const wchar_t * gameFilter)
SortList(); 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(); return FilteredList.size();
} }
@ -349,26 +384,34 @@ void GameList::InternalLoadUnfiltered(std::vector<struct discHdr> &FullList)
int GameList::LoadUnfiltered() int GameList::LoadUnfiltered()
{ {
if((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0)) if ((Settings.LoaderMode & MODE_WIIGAMES) && (FullGameList.size() == 0))
ReadGameList(); ReadGameList();
GameFilter.clear(); GameFilter.clear();
FilteredList.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 // Filter current game list if selected
if(Settings.LoaderMode & MODE_WIIGAMES) if (Settings.LoaderMode & MODE_WIIGAMES)
InternalLoadUnfiltered(FullGameList); InternalLoadUnfiltered(FullGameList);
// Filter gc game list if selected // Filter gc game list if selected
if(Settings.LoaderMode & MODE_GCGAMES) if (Settings.LoaderMode & MODE_GCGAMES)
InternalLoadUnfiltered(GCGames::Instance()->GetHeaders()); InternalLoadUnfiltered(GCGames::Instance()->GetHeaders());
// Filter nand channel list if selected // Filter nand channel list if selected
if(Settings.LoaderMode & MODE_NANDCHANNELS) if (Settings.LoaderMode & MODE_NANDCHANNELS)
InternalLoadUnfiltered(Channels::Instance()->GetNandHeaders()); InternalLoadUnfiltered(Channels::Instance()->GetNandHeaders());
// Filter emu nand channel list if selected // Filter emu nand channel list if selected
if(Settings.LoaderMode & MODE_EMUCHANNELS) if (Settings.LoaderMode & MODE_EMUCHANNELS)
InternalLoadUnfiltered(Channels::Instance()->GetEmuHeaders()); InternalLoadUnfiltered(Channels::Instance()->GetEmuHeaders());
NewTitles::Instance()->Save(); NewTitles::Instance()->Save();
@ -376,22 +419,26 @@ int GameList::LoadUnfiltered()
SortList(); 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(); return FilteredList.size();
} }
void GameList::SortList() void GameList::SortList()
{ {
if (FilteredList.size() < 2) return; if (FilteredList.size() < 2)
return;
if (Settings.GameSort & SORT_PLAYCOUNT) if (Settings.GameSort & SORT_PLAYCOUNT)
{ {
std::sort(FilteredList.begin(), FilteredList.end(), PlaycountSortCallback); 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); 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); 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) 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) 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 count1 = GameStatistics.GetPlayCount(a->id);
int count2 = GameStatistics.GetPlayCount(b->id); int count2 = GameStatistics.GetPlayCount(b->id);
if (count1 == count2) return NameSortCallback(a, b); if (count1 == count2)
return NameSortCallback(a, b);
return (count1 > count2); return (count1 > count2);
} }
@ -421,17 +469,19 @@ bool GameList::RankingSortCallback(const struct discHdr *a, const struct discHdr
int fav1 = GameStatistics.GetFavoriteRank(a->id); int fav1 = GameStatistics.GetFavoriteRank(a->id);
int fav2 = GameStatistics.GetFavoriteRank(b->id); int fav2 = GameStatistics.GetFavoriteRank(b->id);
if (fav1 == fav2) return NameSortCallback(a, b); if (fav1 == fav2)
return NameSortCallback(a, b);
return (fav1 > fav2); return (fav1 > fav2);
} }
bool GameList::PlayersSortCallback(const struct discHdr *a, const struct discHdr *b) bool GameList::PlayersSortCallback(const struct discHdr *a, const struct discHdr *b)
{ {
int count1 = GameTitles.GetPlayersCount((const char *) a->id); int count1 = GameTitles.GetPlayersCount((const char *)a->id);
int count2 = GameTitles.GetPlayersCount((const char *) b->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); return (count1 > count2);
} }