[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:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user