Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eca19aa4bf | ||
|
|
8e02538405 |
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(sphaira_VERSION 0.13.0)
|
set(sphaira_VERSION 0.13.2)
|
||||||
|
|
||||||
project(sphaira
|
project(sphaira
|
||||||
VERSION ${sphaira_VERSION}
|
VERSION ${sphaira_VERSION}
|
||||||
@@ -208,8 +208,8 @@ FetchContent_Declare(libnxtc
|
|||||||
)
|
)
|
||||||
|
|
||||||
FetchContent_Declare(nvjpg
|
FetchContent_Declare(nvjpg
|
||||||
GIT_REPOSITORY https://github.com/averne/oss-nvjpg.git
|
GIT_REPOSITORY https://github.com/ITotalJustice/oss-nvjpg.git
|
||||||
GIT_TAG 16c10a3
|
GIT_TAG 45680e7
|
||||||
)
|
)
|
||||||
|
|
||||||
set(USE_NEW_ZSTD ON)
|
set(USE_NEW_ZSTD ON)
|
||||||
|
|||||||
@@ -185,7 +185,6 @@ Result CreateDirectoryRecursivelyWithPath(FsFileSystem* fs, const FsPath& _path,
|
|||||||
FsPath new_path{};
|
FsPath new_path{};
|
||||||
std::snprintf(new_path, sizeof(new_path), "%.*s", (int)(last_slash - _path.s), _path.s);
|
std::snprintf(new_path, sizeof(new_path), "%.*s", (int)(last_slash - _path.s), _path.s);
|
||||||
R_TRY(CreateDirectoryRecursively(fs, new_path, ignore_read_only));
|
R_TRY(CreateDirectoryRecursively(fs, new_path, ignore_read_only));
|
||||||
fsFsCommit(fs);
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "app.hpp"
|
#include "app.hpp"
|
||||||
#include "threaded_file_transfer.hpp"
|
#include "threaded_file_transfer.hpp"
|
||||||
#include <mbedtls/md5.h>
|
#include <mbedtls/md5.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace sphaira::hash {
|
namespace sphaira::hash {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -16,11 +17,11 @@ struct FileSource final : BaseSource {
|
|||||||
m_is_file_based_emummc = App::IsFileBaseEmummc();
|
m_is_file_based_emummc = App::IsFileBaseEmummc();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Size(s64* out) {
|
Result Size(s64* out) override {
|
||||||
return m_file.GetSize(out);
|
return m_file.GetSize(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Read(void* buf, s64 off, s64 size, u64* bytes_read) {
|
Result Read(void* buf, s64 off, s64 size, u64* bytes_read) override {
|
||||||
const auto rc = m_file.Read(off, buf, size, 0, bytes_read);
|
const auto rc = m_file.Read(off, buf, size, 0, bytes_read);
|
||||||
if (m_fs->IsNative() && m_is_file_based_emummc) {
|
if (m_fs->IsNative() && m_is_file_based_emummc) {
|
||||||
svcSleepThread(2e+6); // 2ms
|
svcSleepThread(2e+6); // 2ms
|
||||||
@@ -38,12 +39,12 @@ private:
|
|||||||
struct MemSource final : BaseSource {
|
struct MemSource final : BaseSource {
|
||||||
MemSource(std::span<const u8> data) : m_data{data} { }
|
MemSource(std::span<const u8> data) : m_data{data} { }
|
||||||
|
|
||||||
Result Size(s64* out) {
|
Result Size(s64* out) override {
|
||||||
*out = m_data.size();
|
*out = m_data.size();
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Read(void* buf, s64 off, s64 size, u64* bytes_read) {
|
Result Read(void* buf, s64 off, s64 size, u64* bytes_read) override {
|
||||||
size = std::min<s64>(size, m_data.size() - off);
|
size = std::min<s64>(size, m_data.size() - off);
|
||||||
std::memcpy(buf, m_data.data() + off, size);
|
std::memcpy(buf, m_data.data() + off, size);
|
||||||
*bytes_read = size;
|
*bytes_read = size;
|
||||||
@@ -61,11 +62,11 @@ struct HashSource {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct HashCrc32 final : HashSource {
|
struct HashCrc32 final : HashSource {
|
||||||
void Update(const void* buf, s64 size) {
|
void Update(const void* buf, s64 size) override {
|
||||||
m_seed = crc32CalculateWithSeed(m_seed, buf, size);
|
m_seed = crc32CalculateWithSeed(m_seed, buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get(std::string& out) {
|
void Get(std::string& out) override {
|
||||||
char str[CalculateHashStrLen(sizeof(m_seed))];
|
char str[CalculateHashStrLen(sizeof(m_seed))];
|
||||||
std::snprintf(str, sizeof(str), "%08x", m_seed);
|
std::snprintf(str, sizeof(str), "%08x", m_seed);
|
||||||
out = str;
|
out = str;
|
||||||
@@ -85,11 +86,11 @@ struct HashMd5 final : HashSource {
|
|||||||
mbedtls_md5_free(&m_ctx);
|
mbedtls_md5_free(&m_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update(const void* buf, s64 size) {
|
void Update(const void* buf, s64 size) override {
|
||||||
mbedtls_md5_update_ret(&m_ctx, (const u8*)buf, size);
|
mbedtls_md5_update_ret(&m_ctx, (const u8*)buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get(std::string& out) {
|
void Get(std::string& out) override {
|
||||||
u8 hash[16];
|
u8 hash[16];
|
||||||
mbedtls_md5_finish_ret(&m_ctx, hash);
|
mbedtls_md5_finish_ret(&m_ctx, hash);
|
||||||
|
|
||||||
@@ -110,11 +111,11 @@ struct HashSha1 final : HashSource {
|
|||||||
sha1ContextCreate(&m_ctx);
|
sha1ContextCreate(&m_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update(const void* buf, s64 size) {
|
void Update(const void* buf, s64 size) override {
|
||||||
sha1ContextUpdate(&m_ctx, buf, size);
|
sha1ContextUpdate(&m_ctx, buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get(std::string& out) {
|
void Get(std::string& out) override {
|
||||||
u8 hash[SHA1_HASH_SIZE];
|
u8 hash[SHA1_HASH_SIZE];
|
||||||
sha1ContextGetHash(&m_ctx, hash);
|
sha1ContextGetHash(&m_ctx, hash);
|
||||||
|
|
||||||
@@ -135,11 +136,11 @@ struct HashSha256 final : HashSource {
|
|||||||
sha256ContextCreate(&m_ctx);
|
sha256ContextCreate(&m_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Update(const void* buf, s64 size) {
|
void Update(const void* buf, s64 size) override {
|
||||||
sha256ContextUpdate(&m_ctx, buf, size);
|
sha256ContextUpdate(&m_ctx, buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Get(std::string& out) {
|
void Get(std::string& out) override {
|
||||||
u8 hash[SHA256_HASH_SIZE];
|
u8 hash[SHA256_HASH_SIZE];
|
||||||
sha256ContextGetHash(&m_ctx, hash);
|
sha256ContextGetHash(&m_ctx, hash);
|
||||||
|
|
||||||
|
|||||||
@@ -59,17 +59,19 @@ auto nro_parse_internal(fs::Fs* fs, const fs::FsPath& path, NroEntry& entry) ->
|
|||||||
std::strncpy(nacp.lang.name, file_name, file_name_len - 4);
|
std::strncpy(nacp.lang.name, file_name, file_name_len - 4);
|
||||||
std::strcpy(nacp.lang.author, "Unknown");
|
std::strcpy(nacp.lang.author, "Unknown");
|
||||||
std::strcpy(nacp.display_version, "Unknown");
|
std::strcpy(nacp.display_version, "Unknown");
|
||||||
|
|
||||||
|
entry.icon_offset = entry.icon_size = 0;
|
||||||
entry.is_nacp_valid = false;
|
entry.is_nacp_valid = false;
|
||||||
} else {
|
} else {
|
||||||
entry.size += sizeof(asset) + asset.icon.size + asset.nacp.size + asset.romfs.size;
|
entry.size += sizeof(asset) + asset.icon.size + asset.nacp.size + asset.romfs.size;
|
||||||
R_TRY(f.Read(data.header.size + asset.nacp.offset, &nacp.lang, sizeof(nacp.lang), FsReadOption_None, &bytes_read));
|
R_TRY(f.Read(data.header.size + asset.nacp.offset, &nacp.lang, sizeof(nacp.lang), FsReadOption_None, &bytes_read));
|
||||||
R_TRY(f.Read(data.header.size + asset.nacp.offset + offsetof(NacpStruct, display_version), nacp.display_version, sizeof(nacp.display_version), FsReadOption_None, &bytes_read));
|
R_TRY(f.Read(data.header.size + asset.nacp.offset + offsetof(NacpStruct, display_version), nacp.display_version, sizeof(nacp.display_version), FsReadOption_None, &bytes_read));
|
||||||
entry.is_nacp_valid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// lazy load the icons
|
// lazy load the icons
|
||||||
entry.icon_size = asset.icon.size;
|
entry.icon_size = asset.icon.size;
|
||||||
entry.icon_offset = data.header.size + asset.icon.offset;
|
entry.icon_offset = data.header.size + asset.icon.offset;
|
||||||
|
entry.is_nacp_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1045,25 +1045,35 @@ Result Menu::DumpGames(u32 flags) {
|
|||||||
bool is_trimmed = false;
|
bool is_trimmed = false;
|
||||||
Result trim_rc = 0;
|
Result trim_rc = 0;
|
||||||
if ((flags & DumpFileFlag_XCI) && m_storage_trimmed_size < m_storage_total_size) {
|
if ((flags & DumpFileFlag_XCI) && m_storage_trimmed_size < m_storage_total_size) {
|
||||||
u8 temp{};
|
const auto start_offset = std::min<s64>(0, m_storage_trimmed_size - 0x4000);
|
||||||
if (R_FAILED(trim_rc = GcStorageRead(&temp, m_storage_trimmed_size, sizeof(temp)))) {
|
// works on fw 1.2.0 and below.
|
||||||
log_write("[GC] WARNING! GameCard is already trimmed: 0x%X FlashError: %u\n", trim_rc, trim_rc == 0x13D002);
|
std::vector<u8> temp(1024*1024*1);
|
||||||
|
if (R_FAILED(trim_rc = GcStorageRead(temp.data(), m_storage_trimmed_size, std::min<s64>(temp.size(), m_storage_total_size - start_offset)))) {
|
||||||
|
log_write("[GC] WARNING1! GameCard is already trimmed: 0x%X FlashError: %u\n", trim_rc, trim_rc == 0x13D002);
|
||||||
is_trimmed = true;
|
is_trimmed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_trimmed) {
|
||||||
|
// works on fw 1.2.0 and below.
|
||||||
|
if (R_FAILED(trim_rc = GcStorageRead(temp.data(), m_storage_total_size - temp.size(), temp.size()))) {
|
||||||
|
log_write("[GC] WARNING2! GameCard is already trimmed: 0x%X FlashError: %u\n", trim_rc, trim_rc == 0x13D002);
|
||||||
|
is_trimmed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if trimmed and the user wants to dump the full xci, error.
|
// if trimmed and the user wants to dump the full xci, error.
|
||||||
if ((flags & DumpFileFlag_XCI) && is_trimmed && App::GetApp()->m_dump_trim_xci.Get()) {
|
if ((flags & DumpFileFlag_XCI) && is_trimmed && App::GetApp()->m_dump_trim_xci.Get()) {
|
||||||
App::PushErrorBox(trim_rc, "GameCard is already trimmed!"_i18n);
|
|
||||||
} else if ((flags & DumpFileFlag_XCI) && is_trimmed) {
|
|
||||||
App::Push(std::make_shared<ui::OptionBox>(
|
App::Push(std::make_shared<ui::OptionBox>(
|
||||||
"WARNING: GameCard is already trimmed!"_i18n,
|
"WARNING: GameCard is already trimmed!"_i18n,
|
||||||
"Back"_i18n, "Continue"_i18n, 0, [&](auto op_index){
|
"Back"_i18n, "Continue"_i18n, 0, [&](auto op_index){
|
||||||
if (op_index && *op_index) {
|
if (op_index && *op_index) {
|
||||||
do_dump(flags);
|
do_dump(flags);
|
||||||
}
|
}
|
||||||
}
|
}, m_icon
|
||||||
));
|
));
|
||||||
|
} else if ((flags & DumpFileFlag_XCI) && is_trimmed) {
|
||||||
|
App::PushErrorBox(trim_rc, "GameCard is trimmed, full dump is not possible!"_i18n);
|
||||||
} else {
|
} else {
|
||||||
do_dump(flags);
|
do_dump(flags);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user