[Base/Kernel] Add and use truncating null-terminating string copying
This commit is contained in:
parent
68cf47e245
commit
91d5ba444a
|
@ -10,11 +10,15 @@
|
||||||
#ifndef XENIA_BASE_STRING_UTIL_H_
|
#ifndef XENIA_BASE_STRING_UTIL_H_
|
||||||
#define XENIA_BASE_STRING_UTIL_H_
|
#define XENIA_BASE_STRING_UTIL_H_
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "third_party/fmt/include/fmt/format.h"
|
#include "third_party/fmt/include/fmt/format.h"
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/base/memory.h"
|
||||||
#include "xenia/base/platform.h"
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/base/string.h"
|
#include "xenia/base/string.h"
|
||||||
#include "xenia/base/vec128.h"
|
#include "xenia/base/vec128.h"
|
||||||
|
@ -30,6 +34,40 @@
|
||||||
namespace xe {
|
namespace xe {
|
||||||
namespace string_util {
|
namespace string_util {
|
||||||
|
|
||||||
|
inline size_t copy_truncating(char* dest, const std::string_view source,
|
||||||
|
size_t dest_buffer_count) {
|
||||||
|
if (!dest_buffer_count) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t chars_copied = std::min(source.size(), dest_buffer_count - size_t(1));
|
||||||
|
std::memcpy(dest, source.data(), chars_copied);
|
||||||
|
dest[chars_copied] = '\0';
|
||||||
|
return chars_copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t copy_truncating(char16_t* dest, const std::u16string_view source,
|
||||||
|
size_t dest_buffer_count) {
|
||||||
|
if (!dest_buffer_count) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t chars_copied = std::min(source.size(), dest_buffer_count - size_t(1));
|
||||||
|
std::memcpy(dest, source.data(), chars_copied * sizeof(char16_t));
|
||||||
|
dest[chars_copied] = u'\0';
|
||||||
|
return chars_copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t copy_and_swap_truncating(char16_t* dest,
|
||||||
|
const std::u16string_view source,
|
||||||
|
size_t dest_buffer_count) {
|
||||||
|
if (!dest_buffer_count) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t chars_copied = std::min(source.size(), dest_buffer_count - size_t(1));
|
||||||
|
xe::copy_and_swap(dest, source.data(), chars_copied);
|
||||||
|
dest[chars_copied] = u'\0';
|
||||||
|
return chars_copied;
|
||||||
|
}
|
||||||
|
|
||||||
inline std::string to_hex_string(uint32_t value) {
|
inline std::string to_hex_string(uint32_t value) {
|
||||||
return fmt::format("{:08X}", value);
|
return fmt::format("{:08X}", value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
#include "xenia/kernel/xam/xam_private.h"
|
#include "xenia/kernel/xam/xam_private.h"
|
||||||
|
@ -223,7 +224,8 @@ dword_result_t XamContentCreateDeviceEnumerator(dword_t content_type,
|
||||||
xe::store_and_swap(&dev->device_type, dummy_device_info_.device_type);
|
xe::store_and_swap(&dev->device_type, dummy_device_info_.device_type);
|
||||||
xe::store_and_swap(&dev->total_bytes, dummy_device_info_.total_bytes);
|
xe::store_and_swap(&dev->total_bytes, dummy_device_info_.total_bytes);
|
||||||
xe::store_and_swap(&dev->free_bytes, dummy_device_info_.free_bytes);
|
xe::store_and_swap(&dev->free_bytes, dummy_device_info_.free_bytes);
|
||||||
xe::copy_and_swap(dev->name, dummy_device_info_.name, 28);
|
xe::copy_and_swap(dev->name, dummy_device_info_.name,
|
||||||
|
xe::countof(dev->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
*handle_out = e->handle();
|
*handle_out = e->handle();
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/string_util.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/user_module.h"
|
#include "xenia/kernel/user_module.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
|
@ -74,15 +75,15 @@ static SYSTEMTIME xeGetLocalSystemTime(uint64_t filetime) {
|
||||||
|
|
||||||
void XamFormatDateString(dword_t unk, qword_t filetime, lpvoid_t output_buffer,
|
void XamFormatDateString(dword_t unk, qword_t filetime, lpvoid_t output_buffer,
|
||||||
dword_t output_count) {
|
dword_t output_count) {
|
||||||
std::memset(output_buffer, 0, output_count * 2);
|
std::memset(output_buffer, 0, output_count * sizeof(char16_t));
|
||||||
|
|
||||||
// TODO: implement this for other platforms
|
// TODO: implement this for other platforms
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
auto st = xeGetLocalSystemTime(filetime);
|
auto st = xeGetLocalSystemTime(filetime);
|
||||||
// TODO: format this depending on users locale?
|
// TODO: format this depending on users locale?
|
||||||
auto str = fmt::format(u"{:02d}/{:02d}/{}", st.wMonth, st.wDay, st.wYear);
|
auto str = fmt::format(u"{:02d}/{:02d}/{}", st.wMonth, st.wDay, st.wYear);
|
||||||
auto copy_length = std::min(size_t(output_count), str.size()) * 2;
|
xe::string_util::copy_and_swap_truncating(output_buffer.as<char16_t*>(), str,
|
||||||
xe::copy_and_swap(output_buffer.as<char16_t*>(), str.c_str(), copy_length);
|
output_count);
|
||||||
#else
|
#else
|
||||||
assert_always();
|
assert_always();
|
||||||
#endif
|
#endif
|
||||||
|
@ -91,15 +92,15 @@ DECLARE_XAM_EXPORT1(XamFormatDateString, kNone, kImplemented);
|
||||||
|
|
||||||
void XamFormatTimeString(dword_t unk, qword_t filetime, lpvoid_t output_buffer,
|
void XamFormatTimeString(dword_t unk, qword_t filetime, lpvoid_t output_buffer,
|
||||||
dword_t output_count) {
|
dword_t output_count) {
|
||||||
std::memset(output_buffer, 0, output_count * 2);
|
std::memset(output_buffer, 0, output_count * sizeof(char16_t));
|
||||||
|
|
||||||
// TODO: implement this for other platforms
|
// TODO: implement this for other platforms
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
auto st = xeGetLocalSystemTime(filetime);
|
auto st = xeGetLocalSystemTime(filetime);
|
||||||
// TODO: format this depending on users locale?
|
// TODO: format this depending on users locale?
|
||||||
auto str = fmt::format(u"{:02d}:{:02d}", st.wHour, st.wMinute);
|
auto str = fmt::format(u"{:02d}:{:02d}", st.wHour, st.wMinute);
|
||||||
auto copy_count = std::min(size_t(output_count), str.size());
|
xe::string_util::copy_and_swap_truncating(output_buffer.as<char16_t*>(), str,
|
||||||
xe::copy_and_swap(output_buffer.as<char16_t*>(), str.c_str(), copy_count);
|
output_count);
|
||||||
#else
|
#else
|
||||||
assert_always();
|
assert_always();
|
||||||
#endif
|
#endif
|
||||||
|
@ -113,7 +114,7 @@ dword_result_t keXamBuildResourceLocator(uint64_t module,
|
||||||
uint32_t buffer_count) {
|
uint32_t buffer_count) {
|
||||||
std::u16string path;
|
std::u16string path;
|
||||||
if (!module) {
|
if (!module) {
|
||||||
path = fmt::format(u"file://media:/{0}.xzp#{0}", container, resource);
|
path = fmt::format(u"file://media:/{}.xzp#{}", container, resource);
|
||||||
XELOGD(
|
XELOGD(
|
||||||
"XamBuildResourceLocator({0}) returning locator to local file {0}.xzp",
|
"XamBuildResourceLocator({0}) returning locator to local file {0}.xzp",
|
||||||
xe::to_utf8(container));
|
xe::to_utf8(container));
|
||||||
|
@ -121,8 +122,8 @@ dword_result_t keXamBuildResourceLocator(uint64_t module,
|
||||||
path = fmt::format(u"section://{:X},{}#{}", (uint32_t)module, container,
|
path = fmt::format(u"section://{:X},{}#{}", (uint32_t)module, container,
|
||||||
resource);
|
resource);
|
||||||
}
|
}
|
||||||
auto copy_count = std::min(size_t(buffer_count), path.size());
|
xe::string_util::copy_and_swap_truncating(buffer_ptr.as<char16_t*>(), path,
|
||||||
xe::copy_and_swap(buffer_ptr.as<char16_t*>(), path.c_str(), copy_count);
|
buffer_count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "third_party/imgui/imgui.h"
|
#include "third_party/imgui/imgui.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/string_util.h"
|
||||||
#include "xenia/emulator.h"
|
#include "xenia/emulator.h"
|
||||||
#include "xenia/kernel/kernel_flags.h"
|
#include "xenia/kernel/kernel_flags.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
|
@ -188,8 +189,8 @@ class KeyboardInputDialog : public xe::ui::ImGuiDialog {
|
||||||
*out_text_ = default_text;
|
*out_text_ = default_text;
|
||||||
}
|
}
|
||||||
text_buffer_.resize(max_length);
|
text_buffer_.resize(max_length);
|
||||||
std::strncpy(text_buffer_.data(), default_text_.c_str(),
|
xe::string_util::copy_truncating(text_buffer_.data(), default_text_,
|
||||||
std::min(text_buffer_.size() - 1, default_text_.size()));
|
text_buffer_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnDraw(ImGuiIO& io) override {
|
void OnDraw(ImGuiIO& io) override {
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
|
#include "xenia/base/math.h"
|
||||||
|
#include "xenia/base/string_util.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
#include "xenia/kernel/util/shim_utils.h"
|
#include "xenia/kernel/util/shim_utils.h"
|
||||||
#include "xenia/kernel/xam/xam_private.h"
|
#include "xenia/kernel/xam/xam_private.h"
|
||||||
|
@ -91,7 +93,8 @@ X_HRESULT_result_t XamUserGetSigninInfo(dword_t user_index, dword_t flags,
|
||||||
const auto& user_profile = kernel_state()->user_profile();
|
const auto& user_profile = kernel_state()->user_profile();
|
||||||
info->xuid = user_profile->xuid();
|
info->xuid = user_profile->xuid();
|
||||||
info->signin_state = user_profile->signin_state();
|
info->signin_state = user_profile->signin_state();
|
||||||
std::strncpy(info->name, user_profile->name().data(), 15);
|
xe::string_util::copy_truncating(info->name, user_profile->name(),
|
||||||
|
xe::countof(info->name));
|
||||||
return X_E_SUCCESS;
|
return X_E_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamUserGetSigninInfo, kUserProfiles, kImplemented);
|
DECLARE_XAM_EXPORT1(XamUserGetSigninInfo, kUserProfiles, kImplemented);
|
||||||
|
@ -110,10 +113,8 @@ dword_result_t XamUserGetName(dword_t user_index, lpstring_t buffer,
|
||||||
const auto& user_name = user_profile->name();
|
const auto& user_name = user_profile->name();
|
||||||
|
|
||||||
// Real XAM will only copy a maximum of 15 characters out.
|
// Real XAM will only copy a maximum of 15 characters out.
|
||||||
size_t copy_length = std::min(
|
xe::string_util::copy_truncating(buffer, user_name,
|
||||||
{size_t(15), user_name.size(), static_cast<size_t>(buffer_len) - 1});
|
std::min(buffer_len.value(), uint32_t(15)));
|
||||||
std::memcpy(buffer, user_name.data(), copy_length);
|
|
||||||
buffer[copy_length] = '\0';
|
|
||||||
return X_ERROR_SUCCESS;
|
return X_ERROR_SUCCESS;
|
||||||
}
|
}
|
||||||
DECLARE_XAM_EXPORT1(XamUserGetName, kUserProfiles, kImplemented);
|
DECLARE_XAM_EXPORT1(XamUserGetName, kUserProfiles, kImplemented);
|
||||||
|
|
Loading…
Reference in New Issue