mirror of
https://github.com/azahar-emu/azahar
synced 2025-11-06 23:19:57 +01:00
Z3DS: Mark compressed files in UI and other minor fixes (#1249)
This commit is contained in:
parent
c95b942ec2
commit
25d7db7bbe
@ -343,8 +343,9 @@ class GameAdapter(private val activity: AppCompatActivity, private val inflater:
|
|||||||
bottomSheetView.findViewById<TextView>(R.id.about_game_title).text = game.title
|
bottomSheetView.findViewById<TextView>(R.id.about_game_title).text = game.title
|
||||||
bottomSheetView.findViewById<TextView>(R.id.about_game_company).text = game.company
|
bottomSheetView.findViewById<TextView>(R.id.about_game_company).text = game.company
|
||||||
bottomSheetView.findViewById<TextView>(R.id.about_game_region).text = game.regions
|
bottomSheetView.findViewById<TextView>(R.id.about_game_region).text = game.regions
|
||||||
bottomSheetView.findViewById<TextView>(R.id.about_game_id).text = "ID: " + String.format("%016X", game.titleId)
|
bottomSheetView.findViewById<TextView>(R.id.about_game_id).text = context.getString(R.string.game_context_id) + " " + String.format("%016X", game.titleId)
|
||||||
bottomSheetView.findViewById<TextView>(R.id.about_game_filename).text = "File: " + game.filename
|
bottomSheetView.findViewById<TextView>(R.id.about_game_filename).text = context.getString(R.string.game_context_file) + " " + game.filename
|
||||||
|
bottomSheetView.findViewById<TextView>(R.id.about_game_filetype).text = context.getString(R.string.game_context_type) + " " + game.fileType
|
||||||
GameIconUtils.loadGameIcon(activity, game, bottomSheetView.findViewById(R.id.game_icon))
|
GameIconUtils.loadGameIcon(activity, game, bottomSheetView.findViewById(R.id.game_icon))
|
||||||
|
|
||||||
bottomSheetView.findViewById<MaterialButton>(R.id.about_game_play).setOnClickListener {
|
bottomSheetView.findViewById<MaterialButton>(R.id.about_game_play).setOnClickListener {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
@ -26,7 +26,8 @@ class Game(
|
|||||||
val isSystemTitle: Boolean = false,
|
val isSystemTitle: Boolean = false,
|
||||||
val isVisibleSystemTitle: Boolean = false,
|
val isVisibleSystemTitle: Boolean = false,
|
||||||
val icon: IntArray? = null,
|
val icon: IntArray? = null,
|
||||||
val filename: String
|
val fileType: String = "",
|
||||||
|
val filename: String,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
val keyAddedToLibraryTime get() = "${filename}_AddedToLibraryTime"
|
val keyAddedToLibraryTime get() = "${filename}_AddedToLibraryTime"
|
||||||
val keyLastPlayedTime get() = "${filename}_LastPlayed"
|
val keyLastPlayedTime get() = "${filename}_LastPlayed"
|
||||||
|
|||||||
@ -13,25 +13,30 @@ class GameInfo(path: String) {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
pointer = initialize(path)
|
pointer = initialize(path)
|
||||||
if (pointer == 0L) {
|
|
||||||
throw IOException()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected external fun finalize()
|
protected external fun finalize()
|
||||||
|
|
||||||
external fun getTitle(): String
|
external fun getTitle(): String
|
||||||
|
|
||||||
|
external fun isValid(): Boolean
|
||||||
|
|
||||||
external fun isEncrypted(): Boolean
|
external fun isEncrypted(): Boolean
|
||||||
|
|
||||||
|
external fun getTitleID(): Long
|
||||||
|
|
||||||
external fun getRegions(): String
|
external fun getRegions(): String
|
||||||
|
|
||||||
external fun getCompany(): String
|
external fun getCompany(): String
|
||||||
|
|
||||||
external fun getIcon(): IntArray?
|
external fun getIcon(): IntArray?
|
||||||
|
|
||||||
|
external fun isSystemTitle(): Boolean
|
||||||
|
|
||||||
external fun getIsVisibleSystemTitle(): Boolean
|
external fun getIsVisibleSystemTitle(): Boolean
|
||||||
|
|
||||||
|
external fun getFileType(): String
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private external fun initialize(path: String): Long
|
private external fun initialize(path: String): Long
|
||||||
|
|||||||
@ -70,29 +70,26 @@ object GameHelper {
|
|||||||
|
|
||||||
fun getGame(uri: Uri, isInstalled: Boolean, addedToLibrary: Boolean): Game {
|
fun getGame(uri: Uri, isInstalled: Boolean, addedToLibrary: Boolean): Game {
|
||||||
val filePath = uri.toString()
|
val filePath = uri.toString()
|
||||||
var gameInfo: GameInfo? = try {
|
var gameInfo: GameInfo? = GameInfo(filePath)
|
||||||
GameInfo(filePath)
|
|
||||||
} catch (e: IOException) {
|
if (gameInfo?.isValid() == false) {
|
||||||
null
|
gameInfo = null
|
||||||
}
|
}
|
||||||
|
|
||||||
var isEncrypted = false
|
val isEncrypted = gameInfo?.isEncrypted() == true
|
||||||
if (gameInfo?.isEncrypted() == true) {
|
|
||||||
gameInfo = null
|
|
||||||
isEncrypted = true
|
|
||||||
}
|
|
||||||
|
|
||||||
val newGame = Game(
|
val newGame = Game(
|
||||||
(gameInfo?.getTitle() ?: FileUtil.getFilename(uri)).replace("[\\t\\n\\r]+".toRegex(), " "),
|
(gameInfo?.getTitle() ?: FileUtil.getFilename(uri)).replace("[\\t\\n\\r]+".toRegex(), " "),
|
||||||
filePath.replace("\n", " "),
|
filePath.replace("\n", " "),
|
||||||
filePath,
|
filePath,
|
||||||
NativeLibrary.getTitleId(filePath),
|
gameInfo?.getTitleID() ?: 0,
|
||||||
gameInfo?.getCompany() ?: "",
|
gameInfo?.getCompany() ?: "",
|
||||||
gameInfo?.getRegions() ?: (if (isEncrypted) { CitraApplication.appContext.getString(R.string.unsupported_encrypted) } else { CitraApplication.appContext.getString(R.string.invalid_region) }),
|
if (isEncrypted) { CitraApplication.appContext.getString(R.string.unsupported_encrypted) } else { gameInfo?.getRegions() ?: "" },
|
||||||
isInstalled,
|
isInstalled,
|
||||||
NativeLibrary.getIsSystemTitle(filePath),
|
gameInfo?.isSystemTitle() ?: false,
|
||||||
gameInfo?.getIsVisibleSystemTitle() ?: false,
|
gameInfo?.getIsVisibleSystemTitle() ?: false,
|
||||||
gameInfo?.getIcon(),
|
gameInfo?.getIcon(),
|
||||||
|
gameInfo?.getFileType() ?: "",
|
||||||
if (FileUtil.isNativePath(filePath)) {
|
if (FileUtil.isNativePath(filePath)) {
|
||||||
CitraApplication.documentsTree.getFilename(filePath)
|
CitraApplication.documentsTree.getFilename(filePath)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -17,28 +17,41 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::vector<u8> GetSMDHData(const std::string& path, bool& is_encrypted) {
|
static constexpr u64 UPDATE_TID_HIGH = 0x0004000e00000000;
|
||||||
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(path);
|
|
||||||
if (!loader) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
struct GameInfoData {
|
||||||
|
Loader::SMDH smdh;
|
||||||
|
u64 title_id = 0;
|
||||||
|
bool loaded = false;
|
||||||
|
bool is_encrypted = false;
|
||||||
|
std::string file_type = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
GameInfoData* GetNewGameInfoData(const std::string& path) {
|
||||||
|
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(path);
|
||||||
u64 program_id = 0;
|
u64 program_id = 0;
|
||||||
loader->ReadProgramId(program_id);
|
bool is_encrypted = false;
|
||||||
|
|
||||||
|
if (!loader || loader->ReadProgramId(program_id) != Loader::ResultStatus::Success) {
|
||||||
|
GameInfoData* gid = new GameInfoData();
|
||||||
|
memset(&gid->smdh, 0, sizeof(Loader::SMDH));
|
||||||
|
return gid;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<u8> smdh = [program_id, &loader, &is_encrypted]() -> std::vector<u8> {
|
std::vector<u8> smdh = [program_id, &loader, &is_encrypted]() -> std::vector<u8> {
|
||||||
std::vector<u8> original_smdh;
|
std::vector<u8> original_smdh;
|
||||||
auto result = loader->ReadIcon(original_smdh);
|
auto result = loader->ReadIcon(original_smdh);
|
||||||
if (result == Loader::ResultStatus::ErrorEncrypted) {
|
if (result != Loader::ResultStatus::Success) {
|
||||||
is_encrypted = true;
|
is_encrypted = result == Loader::ResultStatus::ErrorEncrypted;
|
||||||
return original_smdh;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (program_id < 0x00040000'00000000 || program_id > 0x00040000'FFFFFFFF)
|
if (program_id < 0x00040000'00000000 || program_id > 0x00040000'FFFFFFFF)
|
||||||
return original_smdh;
|
return original_smdh;
|
||||||
|
|
||||||
std::string update_path = Service::AM::GetTitleContentPath(
|
u64 update_tid = (program_id & 0xFFFFFFFFULL) | UPDATE_TID_HIGH;
|
||||||
Service::FS::MediaType::SDMC, program_id + 0x0000000E'00000000);
|
std::string update_path =
|
||||||
|
Service::AM::GetTitleContentPath(Service::FS::MediaType::SDMC, update_tid);
|
||||||
|
|
||||||
if (!FileUtil::Exists(update_path))
|
if (!FileUtil::Exists(update_path))
|
||||||
return original_smdh;
|
return original_smdh;
|
||||||
@ -49,41 +62,50 @@ std::vector<u8> GetSMDHData(const std::string& path, bool& is_encrypted) {
|
|||||||
return original_smdh;
|
return original_smdh;
|
||||||
|
|
||||||
std::vector<u8> update_smdh;
|
std::vector<u8> update_smdh;
|
||||||
update_loader->ReadIcon(update_smdh);
|
result = update_loader->ReadIcon(update_smdh);
|
||||||
|
if (result != Loader::ResultStatus::Success) {
|
||||||
|
is_encrypted = result == Loader::ResultStatus::ErrorEncrypted;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
return update_smdh;
|
return update_smdh;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
return smdh;
|
GameInfoData* gid = new GameInfoData();
|
||||||
|
if (smdh.empty()) {
|
||||||
|
std::memset(&gid->smdh, 0, sizeof(Loader::SMDH));
|
||||||
|
} else {
|
||||||
|
std::memcpy(&gid->smdh, smdh.data(), smdh.size());
|
||||||
|
}
|
||||||
|
gid->loaded = true;
|
||||||
|
gid->is_encrypted = is_encrypted;
|
||||||
|
gid->title_id = program_id;
|
||||||
|
gid->file_type = Loader::GetFileTypeString(loader->GetFileType(), loader->IsFileCompressed());
|
||||||
|
|
||||||
|
return gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
static Loader::SMDH* GetPointer(JNIEnv* env, jobject obj) {
|
static GameInfoData* GetPointer(JNIEnv* env, jobject obj) {
|
||||||
return reinterpret_cast<Loader::SMDH*>(env->GetLongField(obj, IDCache::GetGameInfoPointer()));
|
return reinterpret_cast<GameInfoData*>(env->GetLongField(obj, IDCache::GetGameInfoPointer()));
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_org_citra_citra_1emu_model_GameInfo_initialize(JNIEnv* env, jclass,
|
JNIEXPORT jlong JNICALL Java_org_citra_citra_1emu_model_GameInfo_initialize(JNIEnv* env, jclass,
|
||||||
jstring j_path) {
|
jstring j_path) {
|
||||||
bool is_encrypted = false;
|
GameInfoData* game_info_data = GetNewGameInfoData(GetJString(env, j_path));
|
||||||
std::vector<u8> smdh_data = GetSMDHData(GetJString(env, j_path), is_encrypted);
|
return reinterpret_cast<jlong>(game_info_data);
|
||||||
|
|
||||||
Loader::SMDH* smdh = nullptr;
|
|
||||||
if (is_encrypted) {
|
|
||||||
smdh = new Loader::SMDH;
|
|
||||||
smdh->magic = 0xDEADDEAD;
|
|
||||||
} else if (Loader::IsValidSMDH(smdh_data)) {
|
|
||||||
smdh = new Loader::SMDH;
|
|
||||||
std::memcpy(smdh, smdh_data.data(), sizeof(Loader::SMDH));
|
|
||||||
}
|
}
|
||||||
return reinterpret_cast<jlong>(smdh);
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_model_GameInfo_isValid(JNIEnv* env,
|
||||||
|
jobject obj) {
|
||||||
|
return GetPointer(env, obj)->loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_model_GameInfo_isEncrypted(JNIEnv* env,
|
JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_model_GameInfo_isEncrypted(JNIEnv* env,
|
||||||
jobject obj) {
|
jobject obj) {
|
||||||
Loader::SMDH* smdh = GetPointer(env, obj);
|
return GetPointer(env, obj)->is_encrypted;
|
||||||
return smdh->magic == 0xDEADDEAD;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_model_GameInfo_finalize(JNIEnv* env, jobject obj) {
|
JNIEXPORT void JNICALL Java_org_citra_citra_1emu_model_GameInfo_finalize(JNIEnv* env, jobject obj) {
|
||||||
@ -91,7 +113,11 @@ JNIEXPORT void JNICALL Java_org_citra_citra_1emu_model_GameInfo_finalize(JNIEnv*
|
|||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_citra_citra_1emu_model_GameInfo_getTitle(JNIEnv* env, jobject obj) {
|
jstring Java_org_citra_citra_1emu_model_GameInfo_getTitle(JNIEnv* env, jobject obj) {
|
||||||
Loader::SMDH* smdh = GetPointer(env, obj);
|
Loader::SMDH* smdh = &GetPointer(env, obj)->smdh;
|
||||||
|
if (!smdh->IsValid()) {
|
||||||
|
return ToJString(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
Loader::SMDH::TitleLanguage language = Loader::SMDH::TitleLanguage::English;
|
Loader::SMDH::TitleLanguage language = Loader::SMDH::TitleLanguage::English;
|
||||||
|
|
||||||
// Get the title from SMDH in UTF-16 format
|
// Get the title from SMDH in UTF-16 format
|
||||||
@ -102,7 +128,11 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getTitle(JNIEnv* env, jobject o
|
|||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_citra_citra_1emu_model_GameInfo_getCompany(JNIEnv* env, jobject obj) {
|
jstring Java_org_citra_citra_1emu_model_GameInfo_getCompany(JNIEnv* env, jobject obj) {
|
||||||
Loader::SMDH* smdh = GetPointer(env, obj);
|
Loader::SMDH* smdh = &GetPointer(env, obj)->smdh;
|
||||||
|
if (!smdh->IsValid()) {
|
||||||
|
return ToJString(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
Loader::SMDH::TitleLanguage language = Loader::SMDH::TitleLanguage::English;
|
Loader::SMDH::TitleLanguage language = Loader::SMDH::TitleLanguage::English;
|
||||||
|
|
||||||
// Get the Publisher's name from SMDH in UTF-16 format
|
// Get the Publisher's name from SMDH in UTF-16 format
|
||||||
@ -113,8 +143,15 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getCompany(JNIEnv* env, jobject
|
|||||||
return ToJString(env, Common::UTF16ToUTF8(publisher).data());
|
return ToJString(env, Common::UTF16ToUTF8(publisher).data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jlong Java_org_citra_citra_1emu_model_GameInfo_getTitleID(JNIEnv* env, jobject obj) {
|
||||||
|
return static_cast<jlong>(GetPointer(env, obj)->title_id);
|
||||||
|
}
|
||||||
|
|
||||||
jstring Java_org_citra_citra_1emu_model_GameInfo_getRegions(JNIEnv* env, jobject obj) {
|
jstring Java_org_citra_citra_1emu_model_GameInfo_getRegions(JNIEnv* env, jobject obj) {
|
||||||
Loader::SMDH* smdh = GetPointer(env, obj);
|
Loader::SMDH* smdh = &GetPointer(env, obj)->smdh;
|
||||||
|
if (!smdh->IsValid()) {
|
||||||
|
return ToJString(env, "");
|
||||||
|
}
|
||||||
|
|
||||||
using GameRegion = Loader::SMDH::GameRegion;
|
using GameRegion = Loader::SMDH::GameRegion;
|
||||||
static const std::map<GameRegion, const char*> regions_map = {
|
static const std::map<GameRegion, const char*> regions_map = {
|
||||||
@ -147,7 +184,10 @@ jstring Java_org_citra_citra_1emu_model_GameInfo_getRegions(JNIEnv* env, jobject
|
|||||||
}
|
}
|
||||||
|
|
||||||
jintArray Java_org_citra_citra_1emu_model_GameInfo_getIcon(JNIEnv* env, jobject obj) {
|
jintArray Java_org_citra_citra_1emu_model_GameInfo_getIcon(JNIEnv* env, jobject obj) {
|
||||||
Loader::SMDH* smdh = GetPointer(env, obj);
|
Loader::SMDH* smdh = &GetPointer(env, obj)->smdh;
|
||||||
|
if (!smdh->IsValid()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Always get a 48x48(large) icon
|
// Always get a 48x48(large) icon
|
||||||
std::vector<u16> icon_data = smdh->GetIcon(true);
|
std::vector<u16> icon_data = smdh->GetIcon(true);
|
||||||
@ -162,12 +202,23 @@ jintArray Java_org_citra_citra_1emu_model_GameInfo_getIcon(JNIEnv* env, jobject
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jboolean Java_org_citra_citra_1emu_model_GameInfo_isSystemTitle(JNIEnv* env, jobject obj) {
|
||||||
|
return ((GetPointer(env, obj)->title_id >> 32) & 0xFFFFFFFF) == 0x00040010;
|
||||||
|
}
|
||||||
|
|
||||||
jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsVisibleSystemTitle(JNIEnv* env,
|
jboolean Java_org_citra_citra_1emu_model_GameInfo_getIsVisibleSystemTitle(JNIEnv* env,
|
||||||
jobject obj) {
|
jobject obj) {
|
||||||
Loader::SMDH* smdh = GetPointer(env, obj);
|
Loader::SMDH* smdh = &GetPointer(env, obj)->smdh;
|
||||||
if (smdh == nullptr) {
|
if (!smdh->IsValid()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return smdh->flags & Loader::SMDH::Flags::Visible;
|
return smdh->flags & Loader::SMDH::Flags::Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jstring Java_org_citra_citra_1emu_model_GameInfo_getFileType(JNIEnv* env, jobject obj) {
|
||||||
|
std::string& file_type = GetPointer(env, obj)->file_type;
|
||||||
|
|
||||||
|
return ToJString(env, file_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,12 +86,21 @@
|
|||||||
tools:text="Application Filename" />
|
tools:text="Application Filename" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/about_game_playtime"
|
android:id="@+id/about_game_filetype"
|
||||||
style="?attr/textAppearanceBodyMedium"
|
style="?attr/textAppearanceBodyMedium"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintStart_toStartOf="@id/about_game_title"
|
app:layout_constraintStart_toStartOf="@id/about_game_title"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/about_game_filename"
|
app:layout_constraintTop_toBottomOf="@+id/about_game_filename"
|
||||||
|
tools:text="Game Filetype" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/about_game_playtime"
|
||||||
|
style="?attr/textAppearanceBodyMedium"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/about_game_title"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/about_game_filetype"
|
||||||
tools:text="Game Playtime" />
|
tools:text="Game Playtime" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
@ -539,7 +539,6 @@
|
|||||||
<string name="save_load_error">Save/Load Error</string>
|
<string name="save_load_error">Save/Load Error</string>
|
||||||
<string name="fatal_error">Fatal Error</string>
|
<string name="fatal_error">Fatal Error</string>
|
||||||
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string>
|
<string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string>
|
||||||
<string name="invalid_region">Invalid region</string>
|
|
||||||
<string name="unsupported_encrypted">Unsupported encrypted application</string>
|
<string name="unsupported_encrypted">Unsupported encrypted application</string>
|
||||||
|
|
||||||
<!-- Disk Shader Cache -->
|
<!-- Disk Shader Cache -->
|
||||||
@ -565,6 +564,9 @@
|
|||||||
<string name="create_shortcut">Create Shortcut</string>
|
<string name="create_shortcut">Create Shortcut</string>
|
||||||
<string name="shortcut_name_empty">Shortcut name cannot be empty</string>
|
<string name="shortcut_name_empty">Shortcut name cannot be empty</string>
|
||||||
<string name="shortcut_image_stretch_toggle">Stretch to fit image</string>
|
<string name="shortcut_image_stretch_toggle">Stretch to fit image</string>
|
||||||
|
<string name="game_context_id">ID:</string>
|
||||||
|
<string name="game_context_file">File:</string>
|
||||||
|
<string name="game_context_type">Type:</string>
|
||||||
|
|
||||||
<!-- Performance Overlay settings -->
|
<!-- Performance Overlay settings -->
|
||||||
<string name="performance_overlay_show">Show Performance Overlay</string>
|
<string name="performance_overlay_show">Show Performance Overlay</string>
|
||||||
|
|||||||
@ -173,8 +173,8 @@ void ConfigurePerGame::LoadConfiguration() {
|
|||||||
|
|
||||||
ui->display_filepath->setText(QString::fromStdString(filename));
|
ui->display_filepath->setText(QString::fromStdString(filename));
|
||||||
|
|
||||||
ui->display_format->setText(
|
ui->display_format->setText(QString::fromStdString(
|
||||||
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())));
|
Loader::GetFileTypeString(loader->GetFileType(), loader->IsFileCompressed())));
|
||||||
|
|
||||||
const auto valueText = ReadableByteSize(FileUtil::GetSize(filename));
|
const auto valueText = ReadableByteSize(FileUtil::GetSize(filename));
|
||||||
ui->display_size->setText(valueText);
|
ui->display_size->setText(valueText);
|
||||||
|
|||||||
@ -1,3 +1,7 @@
|
|||||||
|
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
// Copyright 2018 yuzu emulator team
|
// Copyright 2018 yuzu emulator team
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
@ -112,8 +116,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
|
|||||||
res == Loader::ResultStatus::ErrorEncrypted),
|
res == Loader::ResultStatus::ErrorEncrypted),
|
||||||
new GameListItemCompat(compatibility),
|
new GameListItemCompat(compatibility),
|
||||||
new GameListItemRegion(smdh),
|
new GameListItemRegion(smdh),
|
||||||
new GameListItem(
|
new GameListItem(QString::fromStdString(Loader::GetFileTypeString(
|
||||||
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
|
loader->GetFileType(), loader->IsFileCompressed()))),
|
||||||
new GameListItemSize(FileUtil::GetSize(physical_name)),
|
new GameListItemSize(FileUtil::GetSize(physical_name)),
|
||||||
new GameListItemPlayTime(play_time_manager.GetPlayTime(program_id)),
|
new GameListItemPlayTime(play_time_manager.GetPlayTime(program_id)),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -346,6 +346,10 @@ AppLoader::CompressFileInfo AppLoader_THREEDSX::GetCompressFileInfo() {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AppLoader_THREEDSX::IsFileCompressed() {
|
||||||
|
return FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file.get()) != std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
ResultStatus AppLoader_THREEDSX::ReadIcon(std::vector<u8>& buffer) {
|
ResultStatus AppLoader_THREEDSX::ReadIcon(std::vector<u8>& buffer) {
|
||||||
if (!file->IsOpen())
|
if (!file->IsOpen())
|
||||||
return ResultStatus::Error;
|
return ResultStatus::Error;
|
||||||
|
|||||||
@ -41,6 +41,8 @@ public:
|
|||||||
|
|
||||||
CompressFileInfo GetCompressFileInfo() override;
|
CompressFileInfo GetCompressFileInfo() override;
|
||||||
|
|
||||||
|
bool IsFileCompressed() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::string filepath;
|
std::string filepath;
|
||||||
|
|||||||
@ -63,18 +63,18 @@ FileType GuessFromExtension(const std::string& extension_) {
|
|||||||
return FileType::Unknown;
|
return FileType::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* GetFileTypeString(FileType type) {
|
const char* GetFileTypeString(FileType type, bool is_compressed) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FileType::CCI:
|
case FileType::CCI:
|
||||||
return "NCSD";
|
return is_compressed ? "NCSD (Z)" : "NCSD";
|
||||||
case FileType::CXI:
|
case FileType::CXI:
|
||||||
return "NCCH";
|
return is_compressed ? "NCCH (Z)" : "NCCH";
|
||||||
case FileType::CIA:
|
case FileType::CIA:
|
||||||
return "CIA";
|
return is_compressed ? "CIA (Z)" : "CIA";
|
||||||
case FileType::ELF:
|
case FileType::ELF:
|
||||||
return "ELF";
|
return "ELF";
|
||||||
case FileType::THREEDSX:
|
case FileType::THREEDSX:
|
||||||
return "3DSX";
|
return is_compressed ? "3DSX (Z)" : "3DSX";
|
||||||
case FileType::ARTIC:
|
case FileType::ARTIC:
|
||||||
return "ARTIC";
|
return "ARTIC";
|
||||||
case FileType::Error:
|
case FileType::Error:
|
||||||
|
|||||||
@ -60,7 +60,7 @@ FileType GuessFromExtension(const std::string& extension);
|
|||||||
/**
|
/**
|
||||||
* Convert a FileType into a string which can be displayed to the user.
|
* Convert a FileType into a string which can be displayed to the user.
|
||||||
*/
|
*/
|
||||||
const char* GetFileTypeString(FileType type);
|
const char* GetFileTypeString(FileType type, bool is_compressed = false);
|
||||||
|
|
||||||
/// Return type for functions in Loader namespace
|
/// Return type for functions in Loader namespace
|
||||||
enum class ResultStatus {
|
enum class ResultStatus {
|
||||||
@ -294,6 +294,10 @@ public:
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool IsFileCompressed() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
std::unique_ptr<FileUtil::IOFile> file;
|
std::unique_ptr<FileUtil::IOFile> file;
|
||||||
|
|||||||
@ -60,9 +60,12 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile* file) {
|
|||||||
if (MakeMagic('N', 'C', 'C', 'H') == magic)
|
if (MakeMagic('N', 'C', 'C', 'H') == magic)
|
||||||
return FileType::CXI;
|
return FileType::CXI;
|
||||||
|
|
||||||
std::optional<u32> magic_zstd;
|
std::optional<u32> magic_zstd = FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file);
|
||||||
if (FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file) != std::nullopt ||
|
if (!magic_zstd.has_value()) {
|
||||||
FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file_crypto.get()) != std::nullopt) {
|
magic_zstd = FileUtil::Z3DSReadIOFile::GetUnderlyingFileMagic(file_crypto.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (magic_zstd.has_value()) {
|
||||||
if (MakeMagic('N', 'C', 'S', 'D') == magic_zstd)
|
if (MakeMagic('N', 'C', 'S', 'D') == magic_zstd)
|
||||||
return FileType::CCI;
|
return FileType::CCI;
|
||||||
|
|
||||||
@ -437,4 +440,11 @@ AppLoader::CompressFileInfo AppLoader_NCCH::GetCompressFileInfo() {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AppLoader_NCCH::IsFileCompressed() {
|
||||||
|
if (base_ncch.LoadHeader() != ResultStatus::Success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return base_ncch.IsFileCompressed();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Loader
|
} // namespace Loader
|
||||||
|
|||||||
@ -76,6 +76,8 @@ public:
|
|||||||
|
|
||||||
CompressFileInfo GetCompressFileInfo() override;
|
CompressFileInfo GetCompressFileInfo() override;
|
||||||
|
|
||||||
|
bool IsFileCompressed() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Loads .code section into memory for booting
|
* Loads .code section into memory for booting
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user