diff --git a/src/xenia/kernel/xam/apps/xam_app.cc b/src/xenia/kernel/xam/apps/xam_app.cc index 664e1e60f..ded317b41 100644 --- a/src/xenia/kernel/xam/apps/xam_app.cc +++ b/src/xenia/kernel/xam/apps/xam_app.cc @@ -57,8 +57,7 @@ X_HRESULT XamApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, std::memset(buffer, 0, data->buffer_size); } uint32_t item_count = 0; - auto result = e->WriteItems(data->buffer_ptr, buffer, data->buffer_size, - &item_count); + auto result = e->WriteItems(data->buffer_ptr, buffer, &item_count); if (result == X_ERROR_SUCCESS && item_count >= 1) { if (data->length_ptr) { diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index b708b163b..514cac962 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -86,8 +86,8 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id, *buffer_size_ptr = sizeof(XCONTENT_DATA) * items_per_enumerate; } - auto e = object_ref(new XStaticEnumerator( - kernel_state(), items_per_enumerate, sizeof(XCONTENT_DATA))); + auto e = make_object>(kernel_state(), + items_per_enumerate); auto result = e->Initialize(0xFF, 0xFE, 0x20005, 0x20007, 0); if (XFAILED(result)) { return result; @@ -99,8 +99,7 @@ dword_result_t XamContentCreateEnumerator(dword_t user_index, dword_t device_id, static_cast(DummyDeviceId::HDD), XContentType(uint32_t(content_type))); for (const auto& content_data : content_datas) { - auto item = reinterpret_cast(e->AppendItem()); - assert_not_null(item); + auto item = e->AppendItem(); *item = content_data; } } diff --git a/src/xenia/kernel/xam/xam_content_aggregate.cc b/src/xenia/kernel/xam/xam_content_aggregate.cc index 3de7b1566..765619002 100644 --- a/src/xenia/kernel/xam/xam_content_aggregate.cc +++ b/src/xenia/kernel/xam/xam_content_aggregate.cc @@ -23,7 +23,7 @@ namespace xe { namespace kernel { namespace xam { -void AddODDContentTest(object_ref e, +void AddODDContentTest(object_ref> e, XContentType content_type) { auto root_entry = kernel_state()->file_system()->ResolvePath( "game:\\Content\\0000000000000000"); @@ -62,13 +62,15 @@ void AddODDContentTest(object_ref e, break; } - auto item = reinterpret_cast(e->AppendItem()); + auto item = e->AppendItem(); assert_not_null(item); - item->device_id = static_cast(DummyDeviceId::ODD); - item->content_type = content_type; - item->set_display_name(to_utf16(content_entry->name())); - item->set_file_name(content_entry->name()); - item->title_id = title_id; + if (item) { + item->device_id = static_cast(DummyDeviceId::ODD); + item->content_type = content_type; + item->set_display_name(to_utf16(content_entry->name())); + item->set_file_name(content_entry->name()); + item->title_id = title_id; + } } } } @@ -86,8 +88,8 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid, return X_E_INVALIDARG; } - auto e = object_ref(new XStaticEnumerator( - kernel_state(), 1, sizeof(XCONTENT_AGGREGATE_DATA))); + auto e = make_object>( + kernel_state(), 1); X_KENUMERATOR_CONTENT_AGGREGATE* extra; auto result = e->Initialize(0xFF, 0xFE, 0x2000E, 0x20010, 0, &extra); if (XFAILED(result)) { @@ -116,9 +118,11 @@ dword_result_t XamContentAggregateCreateEnumerator(qword_t xuid, static_cast(DummyDeviceId::HDD), content_type_enum, title_id); for (const auto& content_data : content_datas) { - auto item = reinterpret_cast(e->AppendItem()); + auto item = e->AppendItem(); assert_not_null(item); - *item = content_data; + if (item) { + *item = content_data; + } } } } diff --git a/src/xenia/kernel/xam/xam_content_device.cc b/src/xenia/kernel/xam/xam_content_device.cc index d0aaa34f1..e4312de95 100644 --- a/src/xenia/kernel/xam/xam_content_device.cc +++ b/src/xenia/kernel/xam/xam_content_device.cc @@ -139,8 +139,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type, *buffer_size_ptr = sizeof(X_CONTENT_DEVICE_DATA) * max_count; } - auto e = object_ref(new XStaticEnumerator( - kernel_state(), max_count, sizeof(X_CONTENT_DEVICE_DATA))); + auto e = make_object>(kernel_state(), + max_count); auto result = e->Initialize(0xFE, 0xFE, 0x2000A, 0x20009, 0); if (XFAILED(result)) { return result; @@ -148,7 +148,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type, for (const auto& device_info : dummy_device_infos_) { // Copy our dummy device into the enumerator - auto device_data = (X_CONTENT_DEVICE_DATA*)e->AppendItem(); + auto device_data = e->AppendItem(); + assert_not_null(device_data); if (device_data) { device_data->device_id = static_cast(device_info->device_id); device_data->device_type = diff --git a/src/xenia/kernel/xam/xam_enum.cc b/src/xenia/kernel/xam/xam_enum.cc index ce496a523..cd511c37a 100644 --- a/src/xenia/kernel/xam/xam_enum.cc +++ b/src/xenia/kernel/xam/xam_enum.cc @@ -32,49 +32,37 @@ uint32_t xeXamEnumerate(uint32_t handle, uint32_t flags, lpvoid_t buffer_ptr, uint32_t overlapped_ptr) { assert_true(flags == 0); - X_RESULT result; - uint32_t item_count = 0; - auto e = kernel_state()->object_table()->LookupObject(handle); if (!e) { - result = X_ERROR_INVALID_HANDLE; - } else if (!buffer_ptr) { - result = X_ERROR_INVALID_PARAMETER; - } else { - size_t needed_buffer_size = e->item_size() * e->items_per_enumerate(); - - uint32_t actual_buffer_size = buffer_size; - if (buffer_size == e->items_per_enumerate()) { - actual_buffer_size = static_cast(needed_buffer_size); - // Known culprits: - // Final Fight: Double Impact (saves) - XELOGW( - "Broken usage of XamEnumerate! buffer size={:X} vs actual " - "size={:X} (item size={:X}, items per enumerate={})", - buffer_size, actual_buffer_size, e->item_size(), - e->items_per_enumerate()); - } - - result = X_ERROR_INSUFFICIENT_BUFFER; - if (actual_buffer_size >= needed_buffer_size) { - buffer_ptr.Zero(actual_buffer_size); - result = - e->WriteItems(buffer_ptr.guest_address(), buffer_ptr.as(), - actual_buffer_size, &item_count); - } + return X_ERROR_INVALID_HANDLE; } + auto run = [e, buffer_ptr](uint32_t& extended_error, + uint32_t& length) -> X_RESULT { + X_RESULT result; + uint32_t item_count; + if (!buffer_ptr) { + result = X_ERROR_INVALID_PARAMETER; + item_count = 0; + } else { + result = e->WriteItems(buffer_ptr.guest_address(), + buffer_ptr.as(), &item_count); + } + extended_error = X_HRESULT_FROM_WIN32(result); + length = item_count; + 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()->CompleteOverlappedImmediateEx( - overlapped_ptr, - result == X_ERROR_SUCCESS ? X_ERROR_SUCCESS : X_ERROR_FUNCTION_FAILED, - X_HRESULT_FROM_WIN32(result), - result == X_ERROR_SUCCESS ? item_count : 0); + kernel_state()->CompleteOverlappedDeferredEx(run, overlapped_ptr); return X_ERROR_IO_PENDING; } else { assert_always(); diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 096a59b11..aed0c765b 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -608,7 +608,7 @@ class XStaticAchievementEnumerator : public XEnumerator { } uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, - uint32_t buffer_size, uint32_t* written_count) override { + uint32_t* written_count) override { size_t count = std::min(items_.size() - current_item_, items_per_enumerate()); if (!count) { @@ -616,9 +616,6 @@ class XStaticAchievementEnumerator : public XEnumerator { } size_t size = count * item_size(); - if (size > buffer_size) { - return X_ERROR_INSUFFICIENT_BUFFER; - } auto details = reinterpret_cast(buffer_data); size_t string_offset = diff --git a/src/xenia/kernel/xenumerator.cc b/src/xenia/kernel/xenumerator.cc index 4b5ea7216..3aee21136 100644 --- a/src/xenia/kernel/xenumerator.cc +++ b/src/xenia/kernel/xenumerator.cc @@ -21,7 +21,7 @@ XEnumerator::XEnumerator(KernelState* kernel_state, size_t items_per_enumerate, XEnumerator::~XEnumerator() = default; X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, - uint32_t message, uint32_t message2, + uint32_t open_message, uint32_t close_message, uint32_t flags, uint32_t extra_size, void** extra_buffer) { auto native_object = CreateNative(sizeof(X_KENUMERATOR) + extra_size); @@ -30,8 +30,8 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, } auto guest_object = reinterpret_cast(native_object); guest_object->app_id = app_id; - guest_object->message = message; - guest_object->message2 = message2; + guest_object->open_message = open_message; + guest_object->close_message = close_message; guest_object->user_index = user_index; guest_object->items_per_enumerate = static_cast(items_per_enumerate_); @@ -44,32 +44,27 @@ X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, } X_STATUS XEnumerator::Initialize(uint32_t user_index, uint32_t app_id, - uint32_t message, uint32_t message2, + uint32_t open_message, uint32_t close_message, uint32_t flags) { - return Initialize(user_index, app_id, message, message2, flags, 0, nullptr); + return Initialize(user_index, app_id, open_message, close_message, flags, 0, + nullptr); } -uint8_t* XStaticEnumerator::AppendItem() { - buffer_.resize(++item_count_ * item_size()); - auto ptr = - const_cast(buffer_.data() + (item_count_ - 1) * item_size()); - return ptr; +uint8_t* XStaticUntypedEnumerator::AppendItem() { + size_t offset = buffer_.size(); + buffer_.resize(offset + item_size()); + return const_cast(&buffer_.data()[offset]); } -uint32_t XStaticEnumerator::WriteItems(uint32_t buffer_ptr, - uint8_t* buffer_data, - uint32_t buffer_size, - uint32_t* written_count) { +uint32_t XStaticUntypedEnumerator::WriteItems(uint32_t buffer_ptr, + uint8_t* buffer_data, + uint32_t* written_count) { size_t count = std::min(item_count_ - current_item_, items_per_enumerate()); if (!count) { return X_ERROR_NO_MORE_FILES; } size_t size = count * item_size(); - if (size > buffer_size) { - return X_ERROR_INSUFFICIENT_BUFFER; - } - size_t offset = current_item_ * item_size(); std::memcpy(buffer_data, buffer_.data() + offset, size); diff --git a/src/xenia/kernel/xenumerator.h b/src/xenia/kernel/xenumerator.h index 3af03241d..7b2218e97 100644 --- a/src/xenia/kernel/xenumerator.h +++ b/src/xenia/kernel/xenumerator.h @@ -22,8 +22,8 @@ namespace kernel { struct X_KENUMERATOR { be app_id; - be message; - be message2; + be open_message; + be close_message; be user_index; be items_per_enumerate; be flags; @@ -43,19 +43,21 @@ class XEnumerator : public XObject { size_t item_size); virtual ~XEnumerator(); - X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message, - uint32_t message2, uint32_t flags, uint32_t extra_size, - void** extra_buffer); + X_STATUS Initialize(uint32_t user_index, uint32_t app_id, + uint32_t open_message, uint32_t close_message, + uint32_t flags, uint32_t extra_size, void** extra_buffer); - X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message, - uint32_t message2, uint32_t flags); + X_STATUS Initialize(uint32_t user_index, uint32_t app_id, + uint32_t open_message, uint32_t close_message, + uint32_t flags); template - X_STATUS Initialize(uint32_t user_index, uint32_t app_id, uint32_t message, - uint32_t message2, uint32_t flags, T** extra) { + X_STATUS Initialize(uint32_t user_index, uint32_t app_id, + uint32_t open_message, uint32_t close_message, + uint32_t flags, T** extra) { void* dummy; - auto result = Initialize(user_index, app_id, message, message2, flags, - static_cast(sizeof(T)), &dummy); + auto result = Initialize(user_index, app_id, open_message, close_message, + flags, static_cast(sizeof(T)), &dummy); if (extra) { *extra = XFAILED(result) ? nullptr : static_cast(dummy); } @@ -63,7 +65,6 @@ class XEnumerator : public XObject { } virtual uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, - uint32_t buffer_size, uint32_t* written_count) = 0; size_t item_size() const { return item_size_; } @@ -74,10 +75,10 @@ class XEnumerator : public XObject { size_t item_size_; }; -class XStaticEnumerator : public XEnumerator { +class XStaticUntypedEnumerator : public XEnumerator { public: - XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate, - size_t item_size) + XStaticUntypedEnumerator(KernelState* kernel_state, + size_t items_per_enumerate, size_t item_size) : XEnumerator(kernel_state, items_per_enumerate, item_size), item_count_(0), current_item_(0) {} @@ -87,7 +88,7 @@ class XStaticEnumerator : public XEnumerator { uint8_t* AppendItem(); uint32_t WriteItems(uint32_t buffer_ptr, uint8_t* buffer_data, - uint32_t buffer_size, uint32_t* written_count) override; + uint32_t* written_count) override; private: size_t item_count_; @@ -95,6 +96,23 @@ class XStaticEnumerator : public XEnumerator { std::vector buffer_; }; +template +class XStaticEnumerator : public XStaticUntypedEnumerator { + public: + XStaticEnumerator(KernelState* kernel_state, size_t items_per_enumerate) + : XStaticUntypedEnumerator(kernel_state, items_per_enumerate, sizeof(T)) { + } + + T* AppendItem() { + return reinterpret_cast(XStaticUntypedEnumerator::AppendItem()); + } + + void AppendItem(const T& item) { + auto ptr = AppendItem(); + item.Write(ptr); + } +}; + } // namespace kernel } // namespace xe