Browse Source

add firmware 21 and firmware 20 qlaunch structs

pull/3153/head
Maufeat 1 week ago
parent
commit
778bb0d4de
  1. 139
      src/core/hle/service/ns/read_only_application_control_data_interface.cpp
  2. 4
      src/core/hle/service/ns/read_only_application_control_data_interface.h

139
src/core/hle/service/ns/read_only_application_control_data_interface.cpp

@ -4,6 +4,12 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <vector>
#include <stb_image.h>
#include <stb_image_resize.h>
#include <stb_image_write.h>
#include "common/settings.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@ -17,6 +23,49 @@
namespace Service::NS {
namespace {
void JPGToMemory(void* context, void* data, int size) {
auto* buffer = static_cast<std::vector<u8>*>(context);
const auto* char_data = static_cast<const u8*>(data);
buffer->insert(buffer->end(), char_data, char_data + size);
}
void SanitizeJPEGImageSize(std::vector<u8>& image) {
constexpr std::size_t max_jpeg_image_size = 0x20000;
constexpr int profile_dimensions = 174; // for grid view thingy
int original_width, original_height, color_channels;
auto* plain_image =
stbi_load_from_memory(image.data(), static_cast<int>(image.size()), &original_width,
&original_height, &color_channels, STBI_rgb);
if (plain_image == nullptr) {
LOG_ERROR(Service_NS, "Failed to load JPEG for sanitization.");
return;
}
if (original_width != profile_dimensions || original_height != profile_dimensions) {
std::vector<u8> out_image(profile_dimensions * profile_dimensions * STBI_rgb);
stbir_resize_uint8_srgb(plain_image, original_width, original_height, 0, out_image.data(),
profile_dimensions, profile_dimensions, 0, STBI_rgb, 0,
STBIR_FILTER_BOX);
image.clear();
if (!stbi_write_jpg_to_func(JPGToMemory, &image, profile_dimensions, profile_dimensions,
STBI_rgb, out_image.data(), 90)) {
LOG_ERROR(Service_NS, "Failed to resize the user provided image.");
}
}
stbi_image_free(plain_image);
if (image.size() > max_jpeg_image_size) {
image.resize(max_jpeg_image_size);
}
}
} // namespace
IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
Core::System& system_)
: ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
@ -157,34 +206,47 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData2(
}
const auto icon_area_size = size - nacp_size;
size_t available_icon_bytes = 0;
std::vector<u8> final_icon_data;
if (control.second != nullptr) {
available_icon_bytes = control.second->GetSize();
size_t full_size = control.second->GetSize();
if (full_size > 0) {
final_icon_data.resize(full_size);
control.second->Read(final_icon_data.data(), full_size);
if (flag1 == 1) {
SanitizeJPEGImageSize(final_icon_data);
}
}
}
size_t available_icon_bytes = final_icon_data.size();
if (icon_area_size > 0) {
if (control.second != nullptr) {
const size_t to_copy = std::min(available_icon_bytes, icon_area_size);
if (to_copy > 0) {
std::vector<u8> tmp(to_copy);
control.second->Read(tmp.data(), to_copy);
std::memcpy(out_buffer.data() + nacp_size, tmp.data(), to_copy);
}
if (to_copy < icon_area_size) {
std::memset(out_buffer.data() + nacp_size + to_copy, 0, icon_area_size - to_copy);
}
} else {
std::memset(out_buffer.data() + nacp_size, 0, icon_area_size);
const size_t to_copy = (std::min)(available_icon_bytes, icon_area_size);
if (to_copy > 0) {
std::memcpy(out_buffer.data() + nacp_size, final_icon_data.data(), to_copy);
}
if (to_copy < icon_area_size) {
std::memset(out_buffer.data() + nacp_size + to_copy, 0, icon_area_size - to_copy);
}
}
const u32 total_available = static_cast<u32>(nacp_size + available_icon_bytes);
*out_total_size = (static_cast<u64>(total_available) << 32);
if (application_id == 0x0100152000022000) {
LOG_INFO(Service_NS, "Debug: AppID={:016X}, IconSize={}, TotalSize={}, Flag1={}", application_id, available_icon_bytes, total_available, flag1);
}
*out_total_size = (static_cast<u64>(total_available) << 32) | static_cast<u64>(flag1);
R_SUCCEED();
}
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData3(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u64> out_total_size,
ApplicationControlSource application_control_source, u8 flag1, u8 flag2, u64 application_id) {
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_flags_a, Out<u32> out_flags_b,
Out<u32> out_actual_size, ApplicationControlSource application_control_source, u8 flag1, u8 flag2, u64 application_id) {
LOG_INFO(Service_NS, "called with control_source={}, flags=({:02X},{:02X}), application_id={:016X}",
application_control_source, flag1, flag2, application_id);
@ -215,26 +277,43 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData3(
}
const auto icon_area_size = size - nacp_size;
size_t available_icon_bytes = 0;
std::vector<u8> final_icon_data;
if (control.second != nullptr) {
available_icon_bytes = control.second->GetSize();
size_t full_size = control.second->GetSize();
if (full_size > 0) {
final_icon_data.resize(full_size);
control.second->Read(final_icon_data.data(), full_size);
if (flag1 == 1) {
SanitizeJPEGImageSize(final_icon_data);
}
}
}
size_t available_icon_bytes = final_icon_data.size();
if (icon_area_size > 0) {
if (control.second != nullptr) {
const auto to_copy = static_cast<size_t>((std::min)(available_icon_bytes, icon_area_size));
control.second->Read(out_buffer.data() + nacp_size, to_copy);
if (to_copy < icon_area_size) {
std::memset(out_buffer.data() + nacp_size + to_copy, 0, icon_area_size - to_copy);
}
} else {
std::memset(out_buffer.data() + nacp_size, 0, icon_area_size);
LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}, zero-filling icon area",
application_id);
const size_t to_copy = (std::min)(available_icon_bytes, icon_area_size);
if (to_copy > 0) {
std::memcpy(out_buffer.data() + nacp_size, final_icon_data.data(), to_copy);
}
if (to_copy < icon_area_size) {
std::memset(out_buffer.data() + nacp_size + to_copy, 0, icon_area_size - to_copy);
}
} else {
std::memset(out_buffer.data() + nacp_size, 0, icon_area_size);
}
const u32 actual_total_size = static_cast<u32>(nacp_size + available_icon_bytes);
*out_total_size = static_cast<u64>(actual_total_size) << 32;
// Out 1: always 0x10001 (likely presents flags: Bit0=Icon, Bit16=NACP)
// Out 2: reflects flag1 application (0 if flag1=0, 0x10001 if flag1=1)
// Out 3: The actual size of data
*out_flags_a = 0x10001;
*out_flags_b = (flag1 == 1) ? 0x10001 : 0;
*out_actual_size = actual_total_size;
R_SUCCEED();
}

4
src/core/hle/service/ns/read_only_application_control_data_interface.h

@ -36,7 +36,9 @@ public:
u64 application_id);
Result GetApplicationControlData3(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u64> out_total_size,
Out<u32> out_flags_a,
Out<u32> out_flags_b,
Out<u32> out_actual_size,
ApplicationControlSource application_control_source,
u8 flag1,
u8 flag2,

Loading…
Cancel
Save