diff --git a/src/xenia/kernel/sources.gypi b/src/xenia/kernel/sources.gypi index 5880d03d7..7a23d285e 100644 --- a/src/xenia/kernel/sources.gypi +++ b/src/xenia/kernel/sources.gypi @@ -58,6 +58,8 @@ 'xboxkrnl_private.h', 'xboxkrnl_rtl.cc', 'xboxkrnl_rtl.h', + 'xboxkrnl_strings.cc', + 'xboxkrnl_strings.h', 'xboxkrnl_table.inc', 'xboxkrnl_threading.cc', 'xboxkrnl_threading.h', diff --git a/src/xenia/kernel/xboxkrnl_module.cc b/src/xenia/kernel/xboxkrnl_module.cc index c4d1d270d..12ecd85ae 100644 --- a/src/xenia/kernel/xboxkrnl_module.cc +++ b/src/xenia/kernel/xboxkrnl_module.cc @@ -50,6 +50,7 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) : RegisterNtExports(export_resolver_, kernel_state); RegisterObExports(export_resolver_, kernel_state); RegisterRtlExports(export_resolver_, kernel_state_); + RegisterStringExports(export_resolver_, kernel_state_); RegisterThreadingExports(export_resolver_, kernel_state); RegisterVideoExports(export_resolver_, kernel_state); diff --git a/src/xenia/kernel/xboxkrnl_private.h b/src/xenia/kernel/xboxkrnl_private.h index 41a5b6040..db1f66a7e 100644 --- a/src/xenia/kernel/xboxkrnl_private.h +++ b/src/xenia/kernel/xboxkrnl_private.h @@ -33,6 +33,7 @@ void RegisterModuleExports(ExportResolver* export_resolver, KernelState* state); void RegisterNtExports(ExportResolver* export_resolver, KernelState* state); void RegisterObExports(ExportResolver* export_resolver, KernelState* state); void RegisterRtlExports(ExportResolver* export_resolver, KernelState* state); +void RegisterStringExports(ExportResolver* export_resolver, KernelState* state); void RegisterThreadingExports(ExportResolver* export_resolver, KernelState* state); void RegisterVideoExports(ExportResolver* export_resolver, KernelState* state); diff --git a/src/xenia/kernel/xboxkrnl_rtl.cc b/src/xenia/kernel/xboxkrnl_rtl.cc index 7d4c153ae..e46baaa21 100644 --- a/src/xenia/kernel/xboxkrnl_rtl.cc +++ b/src/xenia/kernel/xboxkrnl_rtl.cc @@ -379,208 +379,6 @@ SHIM_CALL RtlMultiByteToUnicodeN_shim( } -// TODO: clean me up! -SHIM_CALL _vsnprintf_shim( - PPCContext* ppc_state, KernelState* state) { - - uint32_t buffer_ptr = SHIM_GET_ARG_32(0); - uint32_t count = SHIM_GET_ARG_32(1); - uint32_t format_ptr = SHIM_GET_ARG_32(2); - uint32_t arg_ptr = SHIM_GET_ARG_32(3); - - if (format_ptr == 0) { - SHIM_SET_RETURN(-1); - return; - } - - char *buffer = (char *)SHIM_MEM_ADDR(buffer_ptr); // TODO: ensure it never writes past the end of the buffer (count)... - const char *format = (const char *)SHIM_MEM_ADDR(format_ptr); - - int arg_index = 0; - - char *b = buffer; - for (; *format != '\0'; ++format) { - const char *start = format; - - if (*format != '%') { - *b++ = *format; - continue; - } - - ++format; - if (*format == '\0') { - break; - } - - if (*format == '%') { - *b++ = *format; - continue; - } - - const char *end; - end = format; - - // skip flags - while (*end == '-' || - *end == '+' || - *end == ' ' || - *end == '#' || - *end == '0') { - ++end; - } - - if (*end == '\0') { - break; - } - - int arg_extras = 0; - - // skip width - if (*end == '*') { - ++end; - arg_extras++; - } - else { - while (*end >= '0' && *end <= '9') { - ++end; - } - } - - if (*end == '\0') { - break; - } - - // skip precision - if (*end == '.') { - ++end; - - if (*end == '*') { - ++end; - ++arg_extras; - } - else { - while (*end >= '0' && *end <= '9') { - ++end; - } - } - } - - if (*end == '\0') { - break; - } - - // get length - int arg_size = 4; - - if (*end == 'h') { - ++end; - arg_size = 4; - if (*end == 'h') { - ++end; - } - } - else if (*end == 'l') { - ++end; - arg_size = 4; - if (*end == 'l') { - ++end; - arg_size = 8; - } - } - else if (*end == 'j') { - arg_size = 8; - ++end; - } - else if (*end == 'z') { - arg_size = 4; - ++end; - } - else if (*end == 't') { - arg_size = 8; - ++end; - } - else if (*end == 'L') { - arg_size = 8; - ++end; - } - - if (*end == '\0') { - break; - } - - if (*end == 'd' || - *end == 'i' || - *end == 'u' || - *end == 'o' || - *end == 'x' || - *end == 'X' || - *end == 'f' || - *end == 'F' || - *end == 'e' || - *end == 'E' || - *end == 'g' || - *end == 'G' || - *end == 'a' || - *end == 'A' || - *end == 'c') { - char local[512]; - local[0] = '\0'; - strncat(local, start, end + 1 - start); - - XEASSERT(arg_size == 8 || arg_size == 4); - if (arg_size == 8) { - if (arg_extras == 0) { - uint64_t value = SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... - int result = sprintf(b, local, value); - b += result; - arg_index++; - } - else { - XEASSERT(false); - } - } - else if (arg_size == 4) { - if (arg_extras == 0) { - uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... - int result = sprintf(b, local, value); - b += result; - arg_index++; - } - else { - XEASSERT(false); - } - } - } - else if (*end == 's' || - *end == 'p' || - *end == 'n') { - char local[512]; - local[0] = '\0'; - strncat(local, start, end + 1 - start); - - XEASSERT(arg_size == 4); - if (arg_extras == 0) { - uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... - const char *pointer = (const char *)SHIM_MEM_ADDR(value); - int result = sprintf(b, local, pointer); - b += result; - arg_index++; - } - else { - XEASSERT(false); - } - } - else { - XEASSERT(false); - break; - } - format = end; - } - *b++ = '\0'; - SHIM_SET_RETURN((uint32_t)(b - buffer)); -} - - uint32_t xeRtlNtStatusToDosError(X_STATUS status) { if (!status || (status & 0x20000000)) { // Success. @@ -968,8 +766,6 @@ void xe::kernel::xboxkrnl::RegisterRtlExports( SHIM_SET_MAPPING("xboxkrnl.exe", RtlUnicodeStringToAnsiString, state); SHIM_SET_MAPPING("xboxkrnl.exe", RtlMultiByteToUnicodeN, state); - SHIM_SET_MAPPING("xboxkrnl.exe", _vsnprintf, state); - SHIM_SET_MAPPING("xboxkrnl.exe", RtlTimeToTimeFields, state); SHIM_SET_MAPPING("xboxkrnl.exe", RtlTimeFieldsToTime, state); diff --git a/src/xenia/kernel/xboxkrnl_strings.cc b/src/xenia/kernel/xboxkrnl_strings.cc new file mode 100644 index 000000000..8a6dbcdd7 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl_strings.cc @@ -0,0 +1,461 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include +#include +#include +#include + + +using namespace xe; +using namespace xe::kernel; +using namespace xe::kernel::xboxkrnl; + + +namespace xe { +namespace kernel { + + +// TODO: clean me up! +SHIM_CALL _vsnprintf_shim( + PPCContext* ppc_state, KernelState* state) { + + uint32_t buffer_ptr = SHIM_GET_ARG_32(0); + uint32_t count = SHIM_GET_ARG_32(1); + uint32_t format_ptr = SHIM_GET_ARG_32(2); + uint32_t arg_ptr = SHIM_GET_ARG_32(3); + + if (format_ptr == 0) { + SHIM_SET_RETURN(-1); + return; + } + + char *buffer = (char *)SHIM_MEM_ADDR(buffer_ptr); // TODO: ensure it never writes past the end of the buffer (count)... + const char *format = (const char *)SHIM_MEM_ADDR(format_ptr); + + int arg_index = 0; + + char *b = buffer; + for (; *format != '\0'; ++format) { + const char *start = format; + + if (*format != '%') { + *b++ = *format; + continue; + } + + ++format; + if (*format == '\0') { + break; + } + + if (*format == '%') { + *b++ = *format; + continue; + } + + const char *end; + end = format; + + // skip flags + while (*end == '-' || + *end == '+' || + *end == ' ' || + *end == '#' || + *end == '0') { + ++end; + } + + if (*end == '\0') { + break; + } + + int arg_extras = 0; + + // skip width + if (*end == '*') { + ++end; + arg_extras++; + } + else { + while (*end >= '0' && *end <= '9') { + ++end; + } + } + + if (*end == '\0') { + break; + } + + // skip precision + if (*end == '.') { + ++end; + + if (*end == '*') { + ++end; + ++arg_extras; + } + else { + while (*end >= '0' && *end <= '9') { + ++end; + } + } + } + + if (*end == '\0') { + break; + } + + // get length + int arg_size = 4; + + if (*end == 'h') { + ++end; + arg_size = 4; + if (*end == 'h') { + ++end; + } + } + else if (*end == 'l') { + ++end; + arg_size = 4; + if (*end == 'l') { + ++end; + arg_size = 8; + } + } + else if (*end == 'j') { + arg_size = 8; + ++end; + } + else if (*end == 'z') { + arg_size = 4; + ++end; + } + else if (*end == 't') { + arg_size = 8; + ++end; + } + else if (*end == 'L') { + arg_size = 8; + ++end; + } + + if (*end == '\0') { + break; + } + + if (*end == 'd' || + *end == 'i' || + *end == 'u' || + *end == 'o' || + *end == 'x' || + *end == 'X' || + *end == 'f' || + *end == 'F' || + *end == 'e' || + *end == 'E' || + *end == 'g' || + *end == 'G' || + *end == 'a' || + *end == 'A' || + *end == 'c') { + char local[512]; + local[0] = '\0'; + strncat(local, start, end + 1 - start); + + XEASSERT(arg_size == 8 || arg_size == 4); + if (arg_size == 8) { + if (arg_extras == 0) { + uint64_t value = SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + int result = sprintf(b, local, value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else if (arg_size == 4) { + if (arg_extras == 0) { + uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + int result = sprintf(b, local, value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + } + else if (*end == 's' || + *end == 'p' || + *end == 'n') { + char local[512]; + local[0] = '\0'; + strncat(local, start, end + 1 - start); + + XEASSERT(arg_size == 4); + if (arg_extras == 0) { + uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + const char *pointer = (const char *)SHIM_MEM_ADDR(value); + int result = sprintf(b, local, pointer); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else { + XEASSERT(false); + break; + } + format = end; + } + *b++ = '\0'; + SHIM_SET_RETURN((uint32_t)(b - buffer)); +} + + +// TODO: clean me up! +SHIM_CALL _vswprintf_shim( + PPCContext* ppc_state, KernelState* state) { + + uint32_t buffer_ptr = SHIM_GET_ARG_32(0); + uint32_t format_ptr = SHIM_GET_ARG_32(1); + uint32_t arg_ptr = SHIM_GET_ARG_32(2); + + if (format_ptr == 0) { + SHIM_SET_RETURN(-1); + return; + } + + wchar_t*buffer = (wchar_t*)SHIM_MEM_ADDR(buffer_ptr); // TODO: ensure it never writes past the end of the buffer (count)... + const wchar_t* format = (const wchar_t*)SHIM_MEM_ADDR(format_ptr); + + // this will work since a null is the same regardless of endianness + size_t format_length = wcslen(format); + + // swap the format buffer + wchar_t *swapped_format = (wchar_t*)xe_malloc((format_length + 1) * sizeof(wchar_t)); + for (size_t i = 0; i < format_length; ++i) + { + swapped_format[i] = XESWAP16(format[i]); + } + swapped_format[format_length] = '\0'; + + // be sneaky + format = swapped_format; + + int arg_index = 0; + + wchar_t *b = buffer; + for (; *format != '\0'; ++format) { + const wchar_t *start = format; + + if (*format != '%') { + *b++ = *format; + continue; + } + + ++format; + if (*format == '\0') { + break; + } + + if (*format == '%') { + *b++ = *format; + continue; + } + + const wchar_t *end; + end = format; + + // skip flags + while (*end == '-' || + *end == '+' || + *end == ' ' || + *end == '#' || + *end == '0') { + ++end; + } + + if (*end == '\0') { + break; + } + + int arg_extras = 0; + + // skip width + if (*end == '*') { + ++end; + arg_extras++; + } + else { + while (*end >= '0' && *end <= '9') { + ++end; + } + } + + if (*end == '\0') { + break; + } + + // skip precision + if (*end == '.') { + ++end; + + if (*end == '*') { + ++end; + ++arg_extras; + } + else { + while (*end >= '0' && *end <= '9') { + ++end; + } + } + } + + if (*end == '\0') { + break; + } + + // get length + int arg_size = 4; + + if (*end == 'h') { + ++end; + arg_size = 4; + if (*end == 'h') { + ++end; + } + } + else if (*end == 'l') { + ++end; + arg_size = 4; + if (*end == 'l') { + ++end; + arg_size = 8; + } + } + else if (*end == 'j') { + arg_size = 8; + ++end; + } + else if (*end == 'z') { + arg_size = 4; + ++end; + } + else if (*end == 't') { + arg_size = 8; + ++end; + } + else if (*end == 'L') { + arg_size = 8; + ++end; + } + + if (*end == '\0') { + break; + } + + if (*end == 'd' || + *end == 'i' || + *end == 'u' || + *end == 'o' || + *end == 'x' || + *end == 'X' || + *end == 'f' || + *end == 'F' || + *end == 'e' || + *end == 'E' || + *end == 'g' || + *end == 'G' || + *end == 'a' || + *end == 'A' || + *end == 'c') { + wchar_t local[512]; + local[0] = '\0'; + wcsncat(local, start, end + 1 - start); + + XEASSERT(arg_size == 8 || arg_size == 4); + if (arg_size == 8) { + if (arg_extras == 0) { + uint64_t value = SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + int result = wsprintf(b, local, value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else if (arg_size == 4) { + if (arg_extras == 0) { + uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + int result = wsprintf(b, local, value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + } + else if (*end == 's' || + *end == 'p' || + *end == 'n') { + wchar_t local[512]; + local[0] = '\0'; + wcsncat(local, start, end + 1 - start); + + XEASSERT(arg_size == 4); + if (arg_extras == 0) { + uint32_t value = (uint32_t)SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + const char *pointer = (const char *)SHIM_MEM_ADDR(value); + int result = wsprintf(b, local, pointer); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else { + XEASSERT(false); + break; + } + format = end; + } + *b++ = '\0'; + + // swap the result buffer + for (wchar_t* swap = buffer; swap != b; ++swap) + { + *swap = XESWAP16(*swap); + } + + SHIM_SET_RETURN((uint32_t)((b - buffer) / sizeof(wchar_t))); +} + + +} // namespace kernel +} // namespace xe + + +void xe::kernel::xboxkrnl::RegisterStringExports( + ExportResolver* export_resolver, KernelState* state) { + SHIM_SET_MAPPING("xboxkrnl.exe", _vsnprintf, state); + SHIM_SET_MAPPING("xboxkrnl.exe", _vswprintf, state); +} diff --git a/src/xenia/kernel/xboxkrnl_strings.h b/src/xenia/kernel/xboxkrnl_strings.h new file mode 100644 index 000000000..859acda85 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl_strings.h @@ -0,0 +1,27 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XBOXKRNL_STRINGS_H_ +#define XENIA_KERNEL_XBOXKRNL_STRINGS_H_ + +#include +#include + +#include + + +namespace xe { +namespace kernel { + + +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_XBOXKRNL_STRINGS_H_