[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:
parent
b18f73b949
commit
e8fda5878c
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue