[XAM] Enumerator improvements.

- [Kernel] XEnumerator::WriteItems no longer cares about provided
  buffer size, since we know the size when the XEnumerator was created.
- [Kernel] Added XStaticEnumerator template. Previous
  XStaticEnumerator renamed to XStaticUntypedEnumerator.
- [XAM] Deferred xeXamEnumerate.
This commit is contained in:
gibbed 2020-12-04 14:52:05 -06:00 committed by Rick Gibbed
parent b18f73b949
commit e8fda5878c
8 changed files with 92 additions and 91 deletions

View File

@ -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) {

View File

@ -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<XStaticEnumerator>(new XStaticEnumerator(
kernel_state(), items_per_enumerate, sizeof(XCONTENT_DATA)));
auto e = make_object<XStaticEnumerator<XCONTENT_DATA>>(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<uint32_t>(DummyDeviceId::HDD),
XContentType(uint32_t(content_type)));
for (const auto& content_data : content_datas) {
auto item = reinterpret_cast<XCONTENT_DATA*>(e->AppendItem());
assert_not_null(item);
auto item = e->AppendItem();
*item = content_data;
}
}

View File

@ -23,7 +23,7 @@ namespace xe {
namespace kernel {
namespace xam {
void AddODDContentTest(object_ref<XStaticEnumerator> e,
void AddODDContentTest(object_ref<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>> e,
XContentType content_type) {
auto root_entry = kernel_state()->file_system()->ResolvePath(
"game:\\Content\\0000000000000000");
@ -62,13 +62,15 @@ void AddODDContentTest(object_ref<XStaticEnumerator> e,
break;
}
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
auto item = e->AppendItem();
assert_not_null(item);
item->device_id = static_cast<uint32_t>(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<uint32_t>(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<XStaticEnumerator>(new XStaticEnumerator(
kernel_state(), 1, sizeof(XCONTENT_AGGREGATE_DATA)));
auto e = make_object<XStaticEnumerator<XCONTENT_AGGREGATE_DATA>>(
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<uint32_t>(DummyDeviceId::HDD), content_type_enum,
title_id);
for (const auto& content_data : content_datas) {
auto item = reinterpret_cast<XCONTENT_AGGREGATE_DATA*>(e->AppendItem());
auto item = e->AppendItem();
assert_not_null(item);
*item = content_data;
if (item) {
*item = content_data;
}
}
}
}

View File

@ -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<XStaticEnumerator>(new XStaticEnumerator(
kernel_state(), max_count, sizeof(X_CONTENT_DEVICE_DATA)));
auto e = make_object<XStaticEnumerator<X_CONTENT_DEVICE_DATA>>(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<uint32_t>(device_info->device_id);
device_data->device_type =

View File

@ -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<XEnumerator>(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<uint32_t>(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<uint8_t*>(),
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<uint8_t*>(), &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();

View File

@ -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<X_ACHIEVEMENT_DETAILS*>(buffer_data);
size_t string_offset =

View File

@ -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<X_KENUMERATOR*>(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<uint32_t>(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<uint8_t*>(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<uint8_t*>(&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);

View File

@ -22,8 +22,8 @@ namespace kernel {
struct X_KENUMERATOR {
be<uint32_t> app_id;
be<uint32_t> message;
be<uint32_t> message2;
be<uint32_t> open_message;
be<uint32_t> close_message;
be<uint32_t> user_index;
be<uint32_t> items_per_enumerate;
be<uint32_t> 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 <typename T>
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<uint32_t>(sizeof(T)), &dummy);
auto result = Initialize(user_index, app_id, open_message, close_message,
flags, static_cast<uint32_t>(sizeof(T)), &dummy);
if (extra) {
*extra = XFAILED(result) ? nullptr : static_cast<T*>(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<uint8_t> buffer_;
};
template <typename T>
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<T*>(XStaticUntypedEnumerator::AppendItem());
}
void AppendItem(const T& item) {
auto ptr = AppendItem();
item.Write(ptr);
}
};
} // namespace kernel
} // namespace xe