summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt11
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt4
-rw-r--r--src/android/app/src/main/jni/native.cpp20
-rw-r--r--src/core/loader/nro.cpp13
-rw-r--r--src/core/loader/nro.h2
8 files changed, 51 insertions, 13 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index c11b6bc16..22af9e435 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -223,6 +223,8 @@ object NativeLibrary {
223 223
224 external fun getCompany(filename: String): String 224 external fun getCompany(filename: String): String
225 225
226 external fun isHomebrew(filename: String): Boolean
227
226 external fun setAppDirectory(directory: String) 228 external fun setAppDirectory(directory: String)
227 229
228 external fun initializeGpuDriver( 230 external fun initializeGpuDriver(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
index ebc0f164a..adbe3696b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
@@ -127,13 +127,7 @@ class SearchFragment : Fragment() {
127 } 127 }
128 } 128 }
129 129
130 R.id.chip_homebrew -> { 130 R.id.chip_homebrew -> baseList.filter { it.isHomebrew }
131 baseList.filter {
132 Log.error("Guh - ${it.path}")
133 FileUtil.hasExtension(it.path, "nro")
134 || FileUtil.hasExtension(it.path, "nso")
135 }
136 }
137 131
138 R.id.chip_retail -> baseList.filter { 132 R.id.chip_retail -> baseList.filter {
139 FileUtil.hasExtension(it.path, "xci") 133 FileUtil.hasExtension(it.path, "xci")
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
index 2a17653b2..3d6782c49 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
@@ -16,7 +16,8 @@ class Game(
16 val regions: String, 16 val regions: String,
17 val path: String, 17 val path: String,
18 val gameId: String, 18 val gameId: String,
19 val company: String 19 val company: String,
20 val isHomebrew: Boolean
20) : Parcelable { 21) : Parcelable {
21 val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime" 22 val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime"
22 val keyLastPlayedTime get() = "${gameId}_LastPlayed" 23 val keyLastPlayedTime get() = "${gameId}_LastPlayed"
@@ -31,6 +32,7 @@ class Game(
31 && path == other.path 32 && path == other.path
32 && gameId == other.gameId 33 && gameId == other.gameId
33 && company == other.company 34 && company == other.company
35 && isHomebrew == other.isHomebrew
34 } 36 }
35 37
36 companion object { 38 companion object {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
index 7059856f1..d9b301210 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
@@ -13,6 +13,8 @@ import androidx.preference.PreferenceManager
13import kotlinx.coroutines.Dispatchers 13import kotlinx.coroutines.Dispatchers
14import kotlinx.coroutines.launch 14import kotlinx.coroutines.launch
15import kotlinx.coroutines.withContext 15import kotlinx.coroutines.withContext
16import kotlinx.serialization.ExperimentalSerializationApi
17import kotlinx.serialization.MissingFieldException
16import kotlinx.serialization.decodeFromString 18import kotlinx.serialization.decodeFromString
17import kotlinx.serialization.json.Json 19import kotlinx.serialization.json.Json
18import org.yuzu.yuzu_emu.NativeLibrary 20import org.yuzu.yuzu_emu.NativeLibrary
@@ -20,6 +22,7 @@ import org.yuzu.yuzu_emu.YuzuApplication
20import org.yuzu.yuzu_emu.utils.GameHelper 22import org.yuzu.yuzu_emu.utils.GameHelper
21import java.util.Locale 23import java.util.Locale
22 24
25@OptIn(ExperimentalSerializationApi::class)
23class GamesViewModel : ViewModel() { 26class GamesViewModel : ViewModel() {
24 private val _games = MutableLiveData<List<Game>>(emptyList()) 27 private val _games = MutableLiveData<List<Game>>(emptyList())
25 val games: LiveData<List<Game>> get() = _games 28 val games: LiveData<List<Game>> get() = _games
@@ -49,7 +52,13 @@ class GamesViewModel : ViewModel() {
49 if (storedGames!!.isNotEmpty()) { 52 if (storedGames!!.isNotEmpty()) {
50 val deserializedGames = mutableSetOf<Game>() 53 val deserializedGames = mutableSetOf<Game>()
51 storedGames.forEach { 54 storedGames.forEach {
52 val game: Game = Json.decodeFromString(it) 55 val game: Game
56 try {
57 game = Json.decodeFromString(it)
58 } catch (e: MissingFieldException) {
59 return@forEach
60 }
61
53 val gameExists = 62 val gameExists =
54 DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path)) 63 DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path))
55 ?.exists() 64 ?.exists()
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
index ba6b5783e..42b207618 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils
6import android.content.SharedPreferences 6import android.content.SharedPreferences
7import android.net.Uri 7import android.net.Uri
8import androidx.preference.PreferenceManager 8import androidx.preference.PreferenceManager
9import kotlinx.serialization.decodeFromString
10import kotlinx.serialization.encodeToString 9import kotlinx.serialization.encodeToString
11import kotlinx.serialization.json.Json 10import kotlinx.serialization.json.Json
12import org.yuzu.yuzu_emu.NativeLibrary 11import org.yuzu.yuzu_emu.NativeLibrary
@@ -83,7 +82,8 @@ object GameHelper {
83 NativeLibrary.getRegions(filePath), 82 NativeLibrary.getRegions(filePath),
84 filePath, 83 filePath,
85 gameId, 84 gameId,
86 NativeLibrary.getCompany(filePath) 85 NativeLibrary.getCompany(filePath),
86 NativeLibrary.isHomebrew(filePath)
87 ) 87 )
88 88
89 val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L) 89 val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L)
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index b87e04b3d..03cb0b74b 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -13,6 +13,7 @@
13 13
14#include <android/api-level.h> 14#include <android/api-level.h>
15#include <android/native_window_jni.h> 15#include <android/native_window_jni.h>
16#include <core/loader/nro.h>
16 17
17#include "common/detached_tasks.h" 18#include "common/detached_tasks.h"
18#include "common/dynamic_library.h" 19#include "common/dynamic_library.h"
@@ -281,6 +282,10 @@ public:
281 return GetRomMetadata(path).icon; 282 return GetRomMetadata(path).icon;
282 } 283 }
283 284
285 bool GetIsHomebrew(const std::string& path) {
286 return GetRomMetadata(path).isHomebrew;
287 }
288
284 void ResetRomMetadata() { 289 void ResetRomMetadata() {
285 m_rom_metadata_cache.clear(); 290 m_rom_metadata_cache.clear();
286 } 291 }
@@ -348,6 +353,7 @@ private:
348 struct RomMetadata { 353 struct RomMetadata {
349 std::string title; 354 std::string title;
350 std::vector<u8> icon; 355 std::vector<u8> icon;
356 bool isHomebrew;
351 }; 357 };
352 358
353 RomMetadata GetRomMetadata(const std::string& path) { 359 RomMetadata GetRomMetadata(const std::string& path) {
@@ -360,11 +366,17 @@ private:
360 366
361 RomMetadata CacheRomMetadata(const std::string& path) { 367 RomMetadata CacheRomMetadata(const std::string& path) {
362 const auto file = Core::GetGameFileFromPath(m_vfs, path); 368 const auto file = Core::GetGameFileFromPath(m_vfs, path);
363 const auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); 369 auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
364 370
365 RomMetadata entry; 371 RomMetadata entry;
366 loader->ReadTitle(entry.title); 372 loader->ReadTitle(entry.title);
367 loader->ReadIcon(entry.icon); 373 loader->ReadIcon(entry.icon);
374 if (loader->GetFileType() == Loader::FileType::NRO) {
375 auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
376 entry.isHomebrew = loader_nro->IsHomebrew();
377 } else {
378 entry.isHomebrew = false;
379 }
368 380
369 m_rom_metadata_cache[path] = entry; 381 m_rom_metadata_cache[path] = entry;
370 382
@@ -662,6 +674,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv
662 return env->NewStringUTF(""); 674 return env->NewStringUTF("");
663} 675}
664 676
677jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env,
678 [[maybe_unused]] jclass clazz,
679 [[maybe_unused]] jstring j_filename) {
680 return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
681}
682
665void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation 683void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
666 [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) { 684 [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
667 // Create the default config.ini. 685 // Create the default config.ini.
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 73d04d7ee..7be6cf5f3 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -33,7 +33,8 @@ static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect s
33struct NroHeader { 33struct NroHeader {
34 INSERT_PADDING_BYTES(0x4); 34 INSERT_PADDING_BYTES(0x4);
35 u32_le module_header_offset; 35 u32_le module_header_offset;
36 INSERT_PADDING_BYTES(0x8); 36 u32 magic_ext1;
37 u32 magic_ext2;
37 u32_le magic; 38 u32_le magic;
38 INSERT_PADDING_BYTES(0x4); 39 INSERT_PADDING_BYTES(0x4);
39 u32_le file_size; 40 u32_le file_size;
@@ -124,6 +125,16 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
124 return FileType::Error; 125 return FileType::Error;
125} 126}
126 127
128bool AppLoader_NRO::IsHomebrew() {
129 // Read NSO header
130 NroHeader nro_header{};
131 if (sizeof(NroHeader) != file->ReadObject(&nro_header)) {
132 return false;
133 }
134 return nro_header.magic_ext1 == Common::MakeMagic('H', 'O', 'M', 'E') &&
135 nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
136}
137
127static constexpr u32 PageAlignSize(u32 size) { 138static constexpr u32 PageAlignSize(u32 size) {
128 return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK); 139 return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
129} 140}
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index ccb77b581..8de6eebc6 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -38,6 +38,8 @@ public:
38 */ 38 */
39 static FileType IdentifyType(const FileSys::VirtualFile& nro_file); 39 static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
40 40
41 bool IsHomebrew();
42
41 FileType GetFileType() const override { 43 FileType GetFileType() const override {
42 return IdentifyType(file); 44 return IdentifyType(file);
43 } 45 }