diff --git a/src/xenia/kernel/xam/xam_enum.cc b/src/xenia/kernel/xam/xam_enum.cc new file mode 100644 index 000000000..d52a6e55b --- /dev/null +++ b/src/xenia/kernel/xam/xam_enum.cc @@ -0,0 +1,121 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 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/user_module.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/kernel/xthread.h" +#include "xenia/xbox.h" + +#if XE_PLATFORM_WIN32 +#include "xenia/base/platform_win.h" +#endif + +#include "third_party/fmt/include/fmt/format.h" + +namespace xe { +namespace kernel { +namespace xam { + +// https://github.com/LestaD/SourceEngine2007/blob/master/se2007/engine/xboxsystem.cpp#L518 +dword_result_t XamEnumerate(dword_t handle, dword_t flags, lpvoid_t buffer, + dword_t buffer_length, lpdword_t items_returned, + pointer_t overlapped) { + assert_true(flags == 0); + + auto e = kernel_state()->object_table()->LookupObject(handle); + if (!e) { + if (overlapped) { + kernel_state()->CompleteOverlappedImmediateEx( + overlapped, X_ERROR_INVALID_HANDLE, X_ERROR_INVALID_HANDLE, 0); + return X_ERROR_IO_PENDING; + } else { + return X_ERROR_INVALID_HANDLE; + } + } + + size_t actual_buffer_length = (uint32_t)buffer_length; + if (buffer_length == e->items_per_enumerate()) { + actual_buffer_length = e->item_size() * e->items_per_enumerate(); + // Known culprits: + // Final Fight: Double Impact (saves) + XELOGW( + "Broken usage of XamEnumerate! buffer length={:X} vs actual " + "length={:X} " + "(item size={:X}, items per enumerate={})", + (uint32_t)buffer_length, actual_buffer_length, e->item_size(), + e->items_per_enumerate()); + } + + buffer.Zero(actual_buffer_length); + + X_RESULT result; + uint32_t item_count = 0; + + if (actual_buffer_length < e->item_size()) { + result = X_ERROR_INSUFFICIENT_BUFFER; + } else if (e->current_item() >= e->item_count()) { + result = X_ERROR_NO_MORE_FILES; + } else { + auto item_buffer = buffer.as(); + auto max_items = actual_buffer_length / e->item_size(); + while (max_items--) { + if (!e->WriteItem(item_buffer)) { + break; + } + item_buffer += e->item_size(); + item_count++; + } + result = X_ERROR_SUCCESS; + } + + if (items_returned) { + assert_true(!overlapped); + *items_returned = result == X_ERROR_SUCCESS ? item_count : 0; + return result; + } else if (overlapped) { + assert_true(!items_returned); + kernel_state()->CompleteOverlappedImmediateEx( + overlapped, + result == X_ERROR_SUCCESS ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED, + X_HRESULT_FROM_WIN32(result), + result == X_ERROR_SUCCESS ? item_count : 0); + return X_ERROR_IO_PENDING; + } else { + assert_always(); + return X_ERROR_INVALID_PARAMETER; + } +} +DECLARE_XAM_EXPORT1(XamEnumerate, kNone, kImplemented); + +dword_result_t XamCreateEnumeratorHandle(unknown_t unk1, unknown_t unk2, + unknown_t unk3, unknown_t unk4, + unknown_t unk5, unknown_t unk6, + unknown_t unk7, unknown_t unk8) { + return X_ERROR_INVALID_PARAMETER; +} +DECLARE_XAM_EXPORT1(XamCreateEnumeratorHandle, kNone, kStub); + +dword_result_t XamGetPrivateEnumStructureFromHandle(unknown_t unk1, + unknown_t unk2) { + return X_ERROR_INVALID_PARAMETER; +} +DECLARE_XAM_EXPORT1(XamGetPrivateEnumStructureFromHandle, kNone, kStub); + +void RegisterEnumExports(xe::cpu::ExportResolver* export_resolver, + KernelState* kernel_state) {} + +} // namespace xam +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/xam/xam_info.cc b/src/xenia/kernel/xam/xam_info.cc index a08ab60aa..438b8a8d0 100644 --- a/src/xenia/kernel/xam/xam_info.cc +++ b/src/xenia/kernel/xam/xam_info.cc @@ -337,91 +337,6 @@ dword_result_t XamFree(lpdword_t ptr) { } DECLARE_XAM_EXPORT1(XamFree, kMemory, kImplemented); -// https://github.com/LestaD/SourceEngine2007/blob/master/se2007/engine/xboxsystem.cpp#L518 -dword_result_t XamEnumerate(dword_t handle, dword_t flags, lpvoid_t buffer, - dword_t buffer_length, lpdword_t items_returned, - pointer_t overlapped) { - assert_true(flags == 0); - - auto e = kernel_state()->object_table()->LookupObject(handle); - if (!e) { - if (overlapped) { - kernel_state()->CompleteOverlappedImmediateEx( - overlapped, X_ERROR_INVALID_HANDLE, X_ERROR_INVALID_HANDLE, 0); - return X_ERROR_IO_PENDING; - } else { - return X_ERROR_INVALID_HANDLE; - } - } - - size_t actual_buffer_length = (uint32_t)buffer_length; - if (buffer_length == e->items_per_enumerate()) { - actual_buffer_length = e->item_size() * e->items_per_enumerate(); - // Known culprits: - // Final Fight: Double Impact (saves) - XELOGW( - "Broken usage of XamEnumerate! buffer length={:X} vs actual " - "length={:X} " - "(item size={:X}, items per enumerate={})", - (uint32_t)buffer_length, actual_buffer_length, e->item_size(), - e->items_per_enumerate()); - } - - buffer.Zero(actual_buffer_length); - - X_RESULT result; - uint32_t item_count = 0; - - if (actual_buffer_length < e->item_size()) { - result = X_ERROR_INSUFFICIENT_BUFFER; - } else if (e->current_item() >= e->item_count()) { - result = X_ERROR_NO_MORE_FILES; - } else { - auto item_buffer = buffer.as(); - auto max_items = actual_buffer_length / e->item_size(); - while (max_items--) { - if (!e->WriteItem(item_buffer)) { - break; - } - item_buffer += e->item_size(); - item_count++; - } - result = X_ERROR_SUCCESS; - } - - if (items_returned) { - assert_true(!overlapped); - *items_returned = result == X_ERROR_SUCCESS ? item_count : 0; - return result; - } else if (overlapped) { - assert_true(!items_returned); - kernel_state()->CompleteOverlappedImmediateEx( - overlapped, - result == X_ERROR_SUCCESS ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED, - X_HRESULT_FROM_WIN32(result), - result == X_ERROR_SUCCESS ? item_count : 0); - return X_ERROR_IO_PENDING; - } else { - assert_always(); - return X_ERROR_INVALID_PARAMETER; - } -} -DECLARE_XAM_EXPORT1(XamEnumerate, kNone, kImplemented); - -dword_result_t XamCreateEnumeratorHandle(unknown_t unk1, unknown_t unk2, - unknown_t unk3, unknown_t unk4, - unknown_t unk5, unknown_t unk6, - unknown_t unk7, unknown_t unk8) { - return X_ERROR_INVALID_PARAMETER; -} -DECLARE_XAM_EXPORT1(XamCreateEnumeratorHandle, kNone, kStub); - -dword_result_t XamGetPrivateEnumStructureFromHandle(unknown_t unk1, - unknown_t unk2) { - return X_ERROR_INVALID_PARAMETER; -} -DECLARE_XAM_EXPORT1(XamGetPrivateEnumStructureFromHandle, kNone, kStub); - dword_result_t XamQueryLiveHiveW(lpu16string_t name, lpvoid_t out_buf, dword_t out_size, dword_t type /* guess */) { return X_STATUS_INVALID_PARAMETER_1; diff --git a/src/xenia/kernel/xam/xam_module.cc b/src/xenia/kernel/xam/xam_module.cc index b38de2160..f3e05c56a 100644 --- a/src/xenia/kernel/xam/xam_module.cc +++ b/src/xenia/kernel/xam/xam_module.cc @@ -30,6 +30,7 @@ XamModule::XamModule(Emulator* emulator, KernelState* kernel_state) // Register all exported functions. RegisterAvatarExports(export_resolver_, kernel_state_); RegisterContentExports(export_resolver_, kernel_state_); + RegisterEnumExports(export_resolver_, kernel_state_); RegisterInfoExports(export_resolver_, kernel_state_); RegisterInputExports(export_resolver_, kernel_state_); RegisterLocaleExports(export_resolver_, kernel_state_); diff --git a/src/xenia/kernel/xam/xam_private.h b/src/xenia/kernel/xam/xam_private.h index 6006d635b..e9f256874 100644 --- a/src/xenia/kernel/xam/xam_private.h +++ b/src/xenia/kernel/xam/xam_private.h @@ -28,6 +28,7 @@ xe::cpu::Export* RegisterExport_xam(xe::cpu::Export* export_entry); KernelState* kernel_state) DECLARE_REGISTER_EXPORTS(Avatar); DECLARE_REGISTER_EXPORTS(Content); +DECLARE_REGISTER_EXPORTS(Enum); DECLARE_REGISTER_EXPORTS(Info); DECLARE_REGISTER_EXPORTS(Input); DECLARE_REGISTER_EXPORTS(Locale);