/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2022 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/base/logging.h" #include "xenia/base/string_util.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xam/xam_module.h" #include "xenia/kernel/xam/xam_private.h" #include "xenia/kernel/xenumerator.h" #include "xenia/xbox.h" #include "third_party/fmt/include/fmt/format.h" namespace xe { namespace kernel { namespace xam { uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr, uint32_t buffer_size, uint32_t* items_returned, uint32_t overlapped_ptr) { auto e = kernel_state()->object_table()->LookupObject(handle); if (!e) { return X_ERROR_INVALID_HANDLE; } auto run = [e, buffer_ptr, buffer_size, overlapped_ptr]( uint32_t& extended_error, uint32_t& length) -> X_RESULT { X_RESULT result; uint32_t item_count = 0; if (!buffer_ptr) { result = X_ERROR_INVALID_PARAMETER; } else { result = e->WriteItems(buffer_ptr.as(), buffer_size, &item_count); } extended_error = X_HRESULT_FROM_WIN32(result); length = item_count; if (result && overlapped_ptr) { result = X_ERROR_FUNCTION_FAILED; } return result; }; if (items_returned) { assert_true(!overlapped_ptr); uint32_t extended_error; uint32_t item_count; X_RESULT result = run(extended_error, item_count); *items_returned = result == X_ERROR_SUCCESS ? item_count : 0; return result; } else if (overlapped_ptr) { assert_true(!items_returned); kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr); return X_ERROR_IO_PENDING; } else { assert_always(); return X_ERROR_INVALID_PARAMETER; } } dword_result_t XamEnumerate_entry(dword_t handle, dword_t flags, lpvoid_t buffer, dword_t buffer_length, lpdword_t items_returned, pointer_t overlapped) { uint32_t dummy; auto result = xeXamEnumerate(handle, flags, buffer, buffer_length, !overlapped ? &dummy : nullptr, overlapped); if (!overlapped && items_returned) { *items_returned = dummy; } return result; } DECLARE_XAM_EXPORT1(XamEnumerate, kNone, kImplemented); static uint32_t XMPCreateUserPlaylistEnumeratorHandle( uint32_t user_index, uint32_t app_id, uint32_t open_message, uint32_t close_message, uint32_t extra_size, uint32_t item_count, uint32_t flags, uint32_t& out_enum_handle) { auto e = object_ref( new XMPCreateUserPlaylistEnumerator(kernel_state(), item_count)); auto result = e->Initialize(user_index, app_id, open_message, close_message, flags, extra_size, nullptr); if (XFAILED(result)) { return result; } std::vector user_playlist_info = {}; for (const auto& playlist_info : user_playlist_info) { e->AppendItem(playlist_info); } XELOGI("{}: added {} items to enumerator", __func__, e->item_count()); out_enum_handle = e->handle(); return X_ERROR_SUCCESS; } constexpr uint32_t XMPCreateUserPlaylistEnumeratorMessage = 0x70026; dword_result_t XamCreateEnumeratorHandle_entry( dword_t user_index, dword_t app_id, dword_t open_message, dword_t close_message, dword_t extra_size, dword_t item_count, dword_t flags, lpdword_t out_handle) { uint32_t enum_handle = 0; X_STATUS result = 0; switch (open_message) { case XMPCreateUserPlaylistEnumeratorMessage: { result = XMPCreateUserPlaylistEnumeratorHandle( user_index, app_id, open_message, close_message, extra_size, item_count, flags, enum_handle); } break; default: { auto e = object_ref( new XStaticUntypedEnumerator(kernel_state(), item_count, extra_size)); result = e->Initialize(user_index, app_id, open_message, close_message, flags, extra_size, nullptr); enum_handle = e->handle(); } break; } if (XFAILED(result)) { return result; } *out_handle = enum_handle; return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamCreateEnumeratorHandle, kNone, kImplemented); dword_result_t XamGetPrivateEnumStructureFromHandle_entry( dword_t handle, lpdword_t out_object_ptr) { auto e = kernel_state()->object_table()->LookupObject(handle); if (!e) { return X_STATUS_INVALID_HANDLE; } // Caller takes the reference. // It's released in ObDereferenceObject. e->RetainHandle(); if (out_object_ptr.guest_address()) { *out_object_ptr = e->guest_object(); } return X_STATUS_SUCCESS; } DECLARE_XAM_EXPORT1(XamGetPrivateEnumStructureFromHandle, kNone, kImplemented); dword_result_t XamProfileCreateEnumerator_entry(dword_t device_id, lpdword_t handle_ptr) { if (!handle_ptr) { return X_ERROR_INVALID_PARAMETER; } auto e = object_ref(new ProfileEnumerator(kernel_state(), 1)); auto result = e->Initialize(XUserIndexAny, 0xFE, 0x23001, 0x23003, 0, 0x28, nullptr); if (XFAILED(result)) { return result; } const auto& accounts = kernel_state()->xam_state()->profile_manager()->GetAccounts(); for (const auto& [xuid, account] : *accounts) { e->AppendItem({xuid, account, 1}); } *handle_ptr = e->handle(); return X_ERROR_SUCCESS; } DECLARE_XAM_EXPORT1(XamProfileCreateEnumerator, kNone, kImplemented); dword_result_t XamProfileEnumerate_entry(dword_t handle, dword_t flags, lpvoid_t buffer, pointer_t overlapped) { uint32_t dummy = 0; auto result = xeXamEnumerate(handle, flags, buffer, 0, !overlapped ? &dummy : nullptr, overlapped); return result; } DECLARE_XAM_EXPORT1(XamProfileEnumerate, kNone, kImplemented); dword_result_t EnumerateMediaObjects_entry() { return X_E_NOT_IMPLEMENTED; } DECLARE_XAM_EXPORT1(EnumerateMediaObjects, kNone, kStub); dword_result_t EnumerateMediaObjects__entry() { return X_E_NOT_IMPLEMENTED; } DECLARE_XAM_EXPORT1(EnumerateMediaObjects_, kNone, kStub); dword_result_t EnumerateMediaObjects_0_entry() { return X_E_NOT_IMPLEMENTED; } DECLARE_XAM_EXPORT1(EnumerateMediaObjects_0, kNone, kStub); dword_result_t EnumerateMediaObjects_1_entry() { return X_E_NOT_IMPLEMENTED; } DECLARE_XAM_EXPORT1(EnumerateMediaObjects_1, kNone, kStub); } // namespace xam } // namespace kernel } // namespace xe DECLARE_XAM_EMPTY_REGISTER_EXPORTS(Enum);