<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 <NAME>. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/kernel/xboxkrnl/xboxkrnl_rtl.h"

#include <algorithm>
#include <string>

#include "xenia/base/atomic.h"
#include "xenia/base/logging.h"
#include "xenia/base/string.h"
#include "xenia/base/threading.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/user_module.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
#include "xenia/kernel/xevent.h"
#include "xenia/kernel/xthread.h"

#if XE_PLATFORM_WIN32
#include "xenia/base/platform_win.h"
#define timegm _mkgmtime
#endif

namespace xe {
namespace kernel {
namespace xboxkrnl {

// http://msdn.microsoft.com/en-us/library/ff561778
dword_result_t RtlCompareMemory(lpvoid_t source1, lpvoid_t source2,
                                dword_t length) {
  uint8_t* p1 = source1;
  uint8_t* p2 = source2;

  // Note that the return value is the number of bytes that match, so it's best
  // we just do this ourselves vs. using memcmp.
  // On Windows we could use the builtin function.

  uint32_t c = 0;
  for (uint32_t n = 0; n < length; n++, p1++, p2++) {
    if (*p1 == *p2) {
      c++;
    }
  }

  return c;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareMemory, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff552123
dword_result_t RtlCompareMemoryUlong(lpvoid_t source, dword_t length,
                                     dword_t pattern) {
  // Return 0 if source/length not aligned
  if (source.guest_address() % 4 || length % 4) {
    return 0;
  }

  uint32_t n = 0;
  for (uint32_t i = 0; i < (length / 4); i++) {
    // FIXME: This assumes as_array returns xe::be
    uint32_t val = source.as_array<uint32_t>()[i];
    if (val == pattern) {
      n++;
    }
  }

  return n;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareMemoryUlong, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff552263
void RtlFillMemoryUlong(lpvoid_t destination, dword_t length, dword_t pattern) {
  // NOTE: length must be % 4, so we can work on uint32s.
  uint32_t count = length >> 2;

  uint32_t* p = destination.as<uint32_t*>();
  uint32_t swapped_pattern = xe::byte_swap(pattern.value());
  for (uint32_t n = 0; n < count; n++, p++) {
    *p = swapped_pattern;
  }
}
DECLARE_XBOXKRNL_EXPORT(RtlFillMemoryUlong, ExportTag::kImplemented);

dword_result_t RtlUpperChar(dword_t in) {
  char c = in & 0xFF;
  if (c >= 'a' && c <= 'z') {
    return c ^ 0x20;
  }

  return c;
}
DECLARE_XBOXKRNL_EXPORT(RtlUpperChar, ExportTag::kImplemented);

dword_result_t RtlLowerChar(dword_t in) {
  char c = in & 0xFF;
  if (c >= 'A' && c <= 'Z') {
    return c ^ 0x20;
  }

  return c;
}
DECLARE_XBOXKRNL_EXPORT(RtlLowerChar, ExportTag::kImplemented);

dword_result_t RtlCompareString(lpstring_t string_1, lpstring_t string_2,
                                dword_t case_insensitive) {
  int ret = case_insensitive ? strcasecmp(string_1, string_2)
                             : std::strcmp(string_1, string_2);

  return ret;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareString, ExportTag::kImplemented);

dword_result_t RtlCompareStringN(lpstring_t string_1, dword_t string_1_len,
                                 lpstring_t string_2, dword_t string_2_len,
                                 dword_t case_insensitive) {
  uint32_t len1 = string_1_len;
  uint32_t len2 = string_2_len;

  if (string_1_len == 0xFFFF) {
    len1 = uint32_t(std::strlen(string_1));
  }
  if (string_2_len == 0xFFFF) {
    len2 = uint32_t(std::strlen(string_2));
  }
  auto len = std::min(string_1_len, string_2_len);

  int ret = case_insensitive ? strncasecmp(string_1, string_2, len)
                             : std::strncmp(string_1, string_2, len);

  return ret;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareStringN, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561918
void RtlInitAnsiString(pointer_t<X_ANSI_STRING> destination,
                       lpstring_t source) {
  if (source) {
    uint16_t length = (uint16_t)strlen(source);
    destination->length = length;
    destination->maximum_length = length + 1;
  } else {
    destination->reset();
  }

  destination->pointer = source.guest_address();
}
DECLARE_XBOXKRNL_EXPORT(RtlInitAnsiString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561899
void RtlFreeAnsiString(pointer_t<X_ANSI_STRING> string) {
  if (string->pointer) {
    kernel_memory()->SystemHeapFree(string->pointer);
  }

  string->reset();
}
DECLARE_XBOXKRNL_EXPORT(RtlFreeAnsiString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561934
void RtlInitUnicodeString(pointer_t<X_UNICODE_STRING> destination,
                          lpwstring_t source) {
  if (source) {
    destination->length = (uint16_t)source.value().size() * 2;
    destination->maximum_length = (uint16_t)(source.value().size() + 1) * 2;
    destination->pointer = source.guest_address();
  } else {
    destination->reset();
  }
}
DECLARE_XBOXKRNL_EXPORT(RtlInitUnicodeString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561903
void RtlFreeUnicodeString(pointer_t<X_UNICODE_STRING> string) {
  if (string->pointer) {
    kernel_memory()->SystemHeapFree(string->pointer);
  }

  string->reset();
}
DECLARE_XBOXKRNL_EXPORT(RtlFreeUnicodeString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff562969
dword_result_t RtlUnicodeStringToAnsiString(
    pointer_t<X_ANSI_STRING> destination_ptr,
    pointer_t<X_UNICODE_STRING> source_ptr, dword_t alloc_dest) {
  // NTSTATUS
  // _Inout_  PANSI_STRING DestinationString,
  // _In_     PCUNICODE_STRING SourceString,<commit_msg>[Kernel] Implement RtlCopyString, RtlCopyUnicodeString.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 <NAME>. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/kernel/xboxkrnl/xboxkrnl_rtl.h"

#include <algorithm>
#include <string>

#include "xenia/base/atomic.h"
#include "xenia/base/logging.h"
#include "xenia/base/string.h"
#include "xenia/base/threading.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/user_module.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h"
#include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h"
#include "xenia/kernel/xevent.h"
#include "xenia/kernel/xthread.h"

#if XE_PLATFORM_WIN32
#include "xenia/base/platform_win.h"
#define timegm _mkgmtime
#endif

namespace xe {
namespace kernel {
namespace xboxkrnl {

// http://msdn.microsoft.com/en-us/library/ff561778
dword_result_t RtlCompareMemory(lpvoid_t source1, lpvoid_t source2,
                                dword_t length) {
  uint8_t* p1 = source1;
  uint8_t* p2 = source2;

  // Note that the return value is the number of bytes that match, so it's best
  // we just do this ourselves vs. using memcmp.
  // On Windows we could use the builtin function.

  uint32_t c = 0;
  for (uint32_t n = 0; n < length; n++, p1++, p2++) {
    if (*p1 == *p2) {
      c++;
    }
  }

  return c;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareMemory, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff552123
dword_result_t RtlCompareMemoryUlong(lpvoid_t source, dword_t length,
                                     dword_t pattern) {
  // Return 0 if source/length not aligned
  if (source.guest_address() % 4 || length % 4) {
    return 0;
  }

  uint32_t n = 0;
  for (uint32_t i = 0; i < (length / 4); i++) {
    // FIXME: This assumes as_array returns xe::be
    uint32_t val = source.as_array<uint32_t>()[i];
    if (val == pattern) {
      n++;
    }
  }

  return n;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareMemoryUlong, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff552263
void RtlFillMemoryUlong(lpvoid_t destination, dword_t length, dword_t pattern) {
  // NOTE: length must be % 4, so we can work on uint32s.
  uint32_t count = length >> 2;

  uint32_t* p = destination.as<uint32_t*>();
  uint32_t swapped_pattern = xe::byte_swap(pattern.value());
  for (uint32_t n = 0; n < count; n++, p++) {
    *p = swapped_pattern;
  }
}
DECLARE_XBOXKRNL_EXPORT(RtlFillMemoryUlong, ExportTag::kImplemented);

dword_result_t RtlUpperChar(dword_t in) {
  char c = in & 0xFF;
  if (c >= 'a' && c <= 'z') {
    return c ^ 0x20;
  }

  return c;
}
DECLARE_XBOXKRNL_EXPORT(RtlUpperChar, ExportTag::kImplemented);

dword_result_t RtlLowerChar(dword_t in) {
  char c = in & 0xFF;
  if (c >= 'A' && c <= 'Z') {
    return c ^ 0x20;
  }

  return c;
}
DECLARE_XBOXKRNL_EXPORT(RtlLowerChar, ExportTag::kImplemented);

dword_result_t RtlCompareString(lpstring_t string_1, lpstring_t string_2,
                                dword_t case_insensitive) {
  int ret = case_insensitive ? strcasecmp(string_1, string_2)
                             : std::strcmp(string_1, string_2);

  return ret;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareString, ExportTag::kImplemented);

dword_result_t RtlCompareStringN(lpstring_t string_1, dword_t string_1_len,
                                 lpstring_t string_2, dword_t string_2_len,
                                 dword_t case_insensitive) {
  uint32_t len1 = string_1_len;
  uint32_t len2 = string_2_len;

  if (string_1_len == 0xFFFF) {
    len1 = uint32_t(std::strlen(string_1));
  }
  if (string_2_len == 0xFFFF) {
    len2 = uint32_t(std::strlen(string_2));
  }
  auto len = std::min(string_1_len, string_2_len);

  int ret = case_insensitive ? strncasecmp(string_1, string_2, len)
                             : std::strncmp(string_1, string_2, len);

  return ret;
}
DECLARE_XBOXKRNL_EXPORT(RtlCompareStringN, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561918
void RtlInitAnsiString(pointer_t<X_ANSI_STRING> destination,
                       lpstring_t source) {
  if (source) {
    uint16_t length = (uint16_t)strlen(source);
    destination->length = length;
    destination->maximum_length = length + 1;
  } else {
    destination->reset();
  }

  destination->pointer = source.guest_address();
}
DECLARE_XBOXKRNL_EXPORT(RtlInitAnsiString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561899
void RtlFreeAnsiString(pointer_t<X_ANSI_STRING> string) {
  if (string->pointer) {
    kernel_memory()->SystemHeapFree(string->pointer);
  }

  string->reset();
}
DECLARE_XBOXKRNL_EXPORT(RtlFreeAnsiString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561934
void RtlInitUnicodeString(pointer_t<X_UNICODE_STRING> destination,
                          lpwstring_t source) {
  if (source) {
    destination->length = (uint16_t)source.value().size() * 2;
    destination->maximum_length = (uint16_t)(source.value().size() + 1) * 2;
    destination->pointer = source.guest_address();
  } else {
    destination->reset();
  }
}
DECLARE_XBOXKRNL_EXPORT(RtlInitUnicodeString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff561903
void RtlFreeUnicodeString(pointer_t<X_UNICODE_STRING> string) {
  if (string->pointer) {
    kernel_memory()->SystemHeapFree(string->pointer);
  }

  string->reset();
}
DECLARE_XBOXKRNL_EXPORT(RtlFreeUnicodeString, ExportTag::kImplemented);

void RtlCopyString(pointer_t<X_ANSI_STRING> destination,
                   pointer_t<X_ANSI_STRING> source) {
  if (!source) {
    destination->length = 0;
    return;
  }

  auto length = std::min(destination->maximum_length, source->length);
  if (length > 0) {
    auto dst_buf = kernel_memory()->TranslateVirtual(destination->pointer);
    auto src_buf = kernel_memory()->TranslateVirtual(source->pointer);
    std::memcpy(dst_buf, src_buf, length);
  }
  destination->length = length;
}
DECLARE_XBOXKRNL_EXPORT(RtlCopyString, ExportTag::kImplemented);

void RtlCopyUnicodeString(pointer_t<X_UNICODE_STRING> destination,
                          pointer_t<X_UNICODE_STRING> source) {
  if (!source) {
    destination->length = 0;
    return;
  }

  auto length = std::min(destination->maximum_length, source->length);
  if (length > 0) {
    auto dst_buf = kernel_memory()->TranslateVirtual(destination->pointer);
    auto src_buf = kernel_memory()->TranslateVirtual(source->pointer);
    std::memcpy(dst_buf, src_buf, length * 2);
  }
  destination->length = length;
}
DECLARE_XBOXKRNL_EXPORT(RtlCopyUnicodeString, ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/ff562969
dword_result_t RtlUnicodeStringToAnsiString(
    pointer_t<X_ANSI_STRING> destination_ptr,
    pointer_t<X_UNICODE_STRING> source_ptr, dword_t alloc_dest) {
  // NTSTATUS
  // _Inout_  PANSI_STRING DestinationString,
  // _In_     PCUNICODE_STRING SourceString,
{'fraction_non_alphanumeric': 0.15306500630049663, 'fraction_numerical': 0.02423838114298421, 'mean_word_length': 3.6977715877437327, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4217273', 'n_tokens_mistral': 5039, 'n_tokens_neox': 4669, 'n_words': 867}