mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	ns: rewrite IReadOnlyApplicationControlDataInterface
This commit is contained in:
		@@ -765,6 +765,8 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/ns/pdm_qry.h
 | 
			
		||||
    hle/service/ns/platform_service_manager.cpp
 | 
			
		||||
    hle/service/ns/platform_service_manager.h
 | 
			
		||||
    hle/service/ns/read_only_application_control_data_interface.cpp
 | 
			
		||||
    hle/service/ns/read_only_application_control_data_interface.h
 | 
			
		||||
    hle/service/ns/read_only_application_record_interface.cpp
 | 
			
		||||
    hle/service/ns/read_only_application_record_interface.h
 | 
			
		||||
    hle/service/nvdrv/core/container.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include "core/hle/service/ns/ns_results.h"
 | 
			
		||||
#include "core/hle/service/ns/pdm_qry.h"
 | 
			
		||||
#include "core/hle/service/ns/platform_service_manager.h"
 | 
			
		||||
#include "core/hle/service/ns/read_only_application_control_data_interface.h"
 | 
			
		||||
#include "core/hle/service/ns/read_only_application_record_interface.h"
 | 
			
		||||
#include "core/hle/service/server_manager.h"
 | 
			
		||||
#include "core/hle/service/set/settings_server.h"
 | 
			
		||||
@@ -469,51 +470,6 @@ Result IApplicationManagerInterface::ConvertApplicationLanguageToLanguageCode(
 | 
			
		||||
    return ResultSuccess;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
 | 
			
		||||
    Core::System& system_)
 | 
			
		||||
    : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, &IReadOnlyApplicationControlDataInterface::GetApplicationControlData, "GetApplicationControlData"},
 | 
			
		||||
        {1, nullptr, "GetApplicationDesiredLanguage"},
 | 
			
		||||
        {2, nullptr, "ConvertApplicationLanguageToLanguageCode"},
 | 
			
		||||
        {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
 | 
			
		||||
        {4, nullptr, "SelectApplicationDesiredLanguage"},
 | 
			
		||||
    };
 | 
			
		||||
    // clang-format on
 | 
			
		||||
 | 
			
		||||
    RegisterHandlers(functions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
 | 
			
		||||
 | 
			
		||||
void IReadOnlyApplicationControlDataInterface::GetApplicationControlData(HLERequestContext& ctx) {
 | 
			
		||||
    enum class ApplicationControlSource : u8 {
 | 
			
		||||
        CacheOnly,
 | 
			
		||||
        Storage,
 | 
			
		||||
        StorageOnly,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct RequestParameters {
 | 
			
		||||
        ApplicationControlSource source;
 | 
			
		||||
        u64 application_id;
 | 
			
		||||
    };
 | 
			
		||||
    static_assert(sizeof(RequestParameters) == 0x10, "RequestParameters has incorrect size.");
 | 
			
		||||
 | 
			
		||||
    IPC::RequestParser rp{ctx};
 | 
			
		||||
    std::vector<u8> nacp_data{};
 | 
			
		||||
    const auto parameters{rp.PopRaw<RequestParameters>()};
 | 
			
		||||
    const auto result =
 | 
			
		||||
        system.GetARPManager().GetControlProperty(&nacp_data, parameters.application_id);
 | 
			
		||||
 | 
			
		||||
    if (result == ResultSuccess) {
 | 
			
		||||
        ctx.WriteBuffer(nacp_data.data(), nacp_data.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    IPC::ResponseBuilder rb{ctx, 2};
 | 
			
		||||
    rb.Push(result);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
 
 | 
			
		||||
@@ -32,16 +32,6 @@ private:
 | 
			
		||||
    void ConvertApplicationLanguageToLanguageCode(HLERequestContext& ctx);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class IReadOnlyApplicationControlDataInterface final
 | 
			
		||||
    : public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
 | 
			
		||||
    ~IReadOnlyApplicationControlDataInterface() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void GetApplicationControlData(HLERequestContext& ctx);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class NS final : public ServiceFramework<NS> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit NS(const char* name, Core::System& system_);
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,12 @@ enum class ApplicationRecordType : u8 {
 | 
			
		||||
    GameCard = 0x10,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class ApplicationControlSource : u8 {
 | 
			
		||||
    CacheOnly = 0,
 | 
			
		||||
    Storage = 1,
 | 
			
		||||
    StorageOnly = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ApplicationRecord {
 | 
			
		||||
    u64 application_id;
 | 
			
		||||
    ApplicationRecordType type;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,122 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "common/settings.h"
 | 
			
		||||
#include "core/file_sys/control_metadata.h"
 | 
			
		||||
#include "core/file_sys/patch_manager.h"
 | 
			
		||||
#include "core/file_sys/vfs/vfs.h"
 | 
			
		||||
#include "core/hle/service/cmif_serialization.h"
 | 
			
		||||
#include "core/hle/service/ns/language.h"
 | 
			
		||||
#include "core/hle/service/ns/ns_results.h"
 | 
			
		||||
#include "core/hle/service/ns/read_only_application_control_data_interface.h"
 | 
			
		||||
#include "core/hle/service/set/settings_server.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::NS {
 | 
			
		||||
 | 
			
		||||
IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
 | 
			
		||||
    Core::System& system_)
 | 
			
		||||
    : ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
 | 
			
		||||
    // clang-format off
 | 
			
		||||
    static const FunctionInfo functions[] = {
 | 
			
		||||
        {0, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlData>, "GetApplicationControlData"},
 | 
			
		||||
        {1, D<&IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage>, "GetApplicationDesiredLanguage"},
 | 
			
		||||
        {2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"},
 | 
			
		||||
        {3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
 | 
			
		||||
        {4, nullptr, "SelectApplicationDesiredLanguage"},
 | 
			
		||||
    };
 | 
			
		||||
    // clang-format on
 | 
			
		||||
 | 
			
		||||
    RegisterHandlers(functions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
 | 
			
		||||
 | 
			
		||||
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
 | 
			
		||||
    OutBuffer<BufferAttr_HipcMapAlias> out_buffer, Out<u32> out_actual_size,
 | 
			
		||||
    ApplicationControlSource application_control_source, u64 application_id) {
 | 
			
		||||
    LOG_INFO(Service_NS, "called with control_source={}, application_id={:016X}",
 | 
			
		||||
             application_control_source, application_id);
 | 
			
		||||
 | 
			
		||||
    const FileSys::PatchManager pm{application_id, system.GetFileSystemController(),
 | 
			
		||||
                                   system.GetContentProvider()};
 | 
			
		||||
    const auto control = pm.GetControlMetadata();
 | 
			
		||||
    const auto size = out_buffer.size();
 | 
			
		||||
 | 
			
		||||
    const auto icon_size = control.second ? control.second->GetSize() : 0;
 | 
			
		||||
    const auto total_size = 0x4000 + icon_size;
 | 
			
		||||
 | 
			
		||||
    if (size < total_size) {
 | 
			
		||||
        LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, expected_min=0x4000)",
 | 
			
		||||
                  size);
 | 
			
		||||
        R_THROW(ResultUnknown);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (control.first != nullptr) {
 | 
			
		||||
        const auto bytes = control.first->GetRawBytes();
 | 
			
		||||
        std::memcpy(out_buffer.data(), bytes.data(), bytes.size());
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_WARNING(Service_NS, "missing NACP data for application_id={:016X}, defaulting to zero",
 | 
			
		||||
                    application_id);
 | 
			
		||||
        std::memset(out_buffer.data(), 0, 0x4000);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (control.second != nullptr) {
 | 
			
		||||
        control.second->Read(out_buffer.data() + 0x4000, icon_size);
 | 
			
		||||
    } else {
 | 
			
		||||
        LOG_WARNING(Service_NS, "missing icon data for application_id={:016X}", application_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out_actual_size = static_cast<u32>(total_size);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IReadOnlyApplicationControlDataInterface::GetApplicationDesiredLanguage(
 | 
			
		||||
    Out<u8> out_desired_language, u32 supported_languages) {
 | 
			
		||||
    LOG_INFO(Service_NS, "called with supported_languages={:08X}", supported_languages);
 | 
			
		||||
 | 
			
		||||
    // Get language code from settings
 | 
			
		||||
    const auto language_code =
 | 
			
		||||
        Set::GetLanguageCodeFromIndex(static_cast<s32>(Settings::values.language_index.GetValue()));
 | 
			
		||||
 | 
			
		||||
    // Convert to application language, get priority list
 | 
			
		||||
    const auto application_language = ConvertToApplicationLanguage(language_code);
 | 
			
		||||
    if (application_language == std::nullopt) {
 | 
			
		||||
        LOG_ERROR(Service_NS, "Could not convert application language! language_code={}",
 | 
			
		||||
                  language_code);
 | 
			
		||||
        R_THROW(Service::NS::ResultApplicationLanguageNotFound);
 | 
			
		||||
    }
 | 
			
		||||
    const auto priority_list = GetApplicationLanguagePriorityList(*application_language);
 | 
			
		||||
    if (!priority_list) {
 | 
			
		||||
        LOG_ERROR(Service_NS,
 | 
			
		||||
                  "Could not find application language priorities! application_language={}",
 | 
			
		||||
                  *application_language);
 | 
			
		||||
        R_THROW(Service::NS::ResultApplicationLanguageNotFound);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Try to find a valid language.
 | 
			
		||||
    for (const auto lang : *priority_list) {
 | 
			
		||||
        const auto supported_flag = GetSupportedLanguageFlag(lang);
 | 
			
		||||
        if (supported_languages == 0 || (supported_languages & supported_flag) == supported_flag) {
 | 
			
		||||
            *out_desired_language = static_cast<u8>(lang);
 | 
			
		||||
            R_SUCCEED();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LOG_ERROR(Service_NS, "Could not find a valid language! supported_languages={:08X}",
 | 
			
		||||
              supported_languages);
 | 
			
		||||
    R_THROW(Service::NS::ResultApplicationLanguageNotFound);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode(
 | 
			
		||||
    Out<u64> out_language_code, ApplicationLanguage application_language) {
 | 
			
		||||
    const auto language_code = ConvertToLanguageCode(application_language);
 | 
			
		||||
    if (language_code == std::nullopt) {
 | 
			
		||||
        LOG_ERROR(Service_NS, "Language not found! application_language={}", application_language);
 | 
			
		||||
        R_THROW(Service::NS::ResultApplicationLanguageNotFound);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out_language_code = static_cast<u64>(*language_code);
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::NS
 | 
			
		||||
@@ -0,0 +1,29 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "core/hle/service/cmif_types.h"
 | 
			
		||||
#include "core/hle/service/ns/language.h"
 | 
			
		||||
#include "core/hle/service/ns/ns_types.h"
 | 
			
		||||
#include "core/hle/service/service.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::NS {
 | 
			
		||||
 | 
			
		||||
class IReadOnlyApplicationControlDataInterface final
 | 
			
		||||
    : public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
 | 
			
		||||
    ~IReadOnlyApplicationControlDataInterface() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Result GetApplicationControlData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
 | 
			
		||||
                                     Out<u32> out_actual_size,
 | 
			
		||||
                                     ApplicationControlSource application_control_source,
 | 
			
		||||
                                     u64 application_id);
 | 
			
		||||
    Result GetApplicationDesiredLanguage(Out<u8> out_desired_language, u32 supported_languages);
 | 
			
		||||
    Result ConvertApplicationLanguageToLanguageCode(Out<u64> out_language_code,
 | 
			
		||||
                                                    ApplicationLanguage application_language);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::NS
 | 
			
		||||
		Reference in New Issue
	
	Block a user