<commit_before>// Copyright (C) 2010-2012 <NAME>.
// See the file COPYING for copying permission.

#pragma once

#include <array>
#include <memory>
#include <string>
#include <vector>
#include <cassert>
#include <cstddef>
#include <exception>
#include <type_traits>

#include <windows.h>

#include "hadesmem/error.hpp"
#include "hadesmem/protect.hpp"
#include "hadesmem/detail/read_impl.hpp"
#include "hadesmem/detail/type_traits.hpp"
#include "hadesmem/detail/query_region.hpp"
#include "hadesmem/detail/protect_guard.hpp"
#include "hadesmem/detail/static_assert.hpp"

namespace hadesmem
{

class Process;

namespace detail
{

template <typename T>
T ReadUnchecked(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);
  
  T data;
  ReadUnchecked(process, address, std::addressof(data), sizeof(data));
  return data;
}

}

template <typename T>
T Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);
  
  T data;
  detail::Read(process, address, std::addressof(data), sizeof(data));
  return data;
}

template <typename T, std::size_t N>
std::array<T, N> Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);

  std::array<T, N> data;
  detail::Read(process, address, data.data(), sizeof(T) * N);
  return data;
}

// TODO: Clean up this function.
template <typename T>
std::basic_string<T> ReadString(Process const& process, PVOID address, 
  std::size_t chunk_len = 128)
{
  HADESMEM_STATIC_ASSERT(detail::IsCharType<T>::value);

  assert(chunk_len != 0);

  detail::ProtectGuard protect_guard(&process, address, 
    detail::ProtectGuardType::kRead);

  std::basic_string<T> data;

  PBYTE cur_address = static_cast<PBYTE>(address);
  MEMORY_BASIC_INFORMATION const mbi = detail::Query(process, address);
  PBYTE const region_end = static_cast<PBYTE>(mbi.BaseAddress) + 
    mbi.RegionSize;

  for (;;)
  {
    std::size_t cur_chunk_len = 0;
    std::size_t cur_chunk_size = 0;

    if (cur_address + (chunk_len * sizeof(T)) > region_end)
    {
      cur_chunk_size = reinterpret_cast<std::size_t>(region_end - 
        reinterpret_cast<DWORD_PTR>(cur_address));
      cur_chunk_len = (cur_chunk_size - (cur_chunk_size % sizeof(T))) / 
        sizeof(T);
    }
    else
    {
      cur_chunk_size = chunk_len * sizeof(T);
      cur_chunk_len = chunk_len;
    }

    std::vector<BYTE> buf(cur_chunk_size);
    detail::Read(process, cur_address, buf.data(), cur_chunk_size);

    T const* buf_beg = static_cast<T const*>(static_cast<void const*>(
      buf.data()));
    T const* buf_end = buf_beg + cur_chunk_len;
    for (T current = *buf_beg; current != T() && buf_beg != buf_end; 
      current = *++buf_beg)
    {
      data.push_back(current);
    }

    if (buf_beg != buf_end || cur_address + cur_chunk_size == region_end)
    {
      break;
    }

    cur_address += cur_chunk_size;
  }

  protect_guard.Restore();

  return data;
}

template <typename T>
std::vector<T> ReadVector(Process const& process, PVOID address, 
  std::size_t size)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);
  
  std::vector<T> data(size);
  detail::Read(process, address, data.data(), sizeof(T) * size);
  return data;
}

}<commit_msg>* Clean up ReadString a bit.<commit_after>// Copyright (C) 2010-2012 <NAME>.
// See the file COPYING for copying permission.

#pragma once

#include <array>
#include <memory>
#include <string>
#include <vector>
#include <cassert>
#include <cstddef>
#include <exception>
#include <type_traits>

#include <windows.h>

#include "hadesmem/error.hpp"
#include "hadesmem/protect.hpp"
#include "hadesmem/detail/read_impl.hpp"
#include "hadesmem/detail/type_traits.hpp"
#include "hadesmem/detail/query_region.hpp"
#include "hadesmem/detail/protect_guard.hpp"
#include "hadesmem/detail/static_assert.hpp"

namespace hadesmem
{

class Process;

namespace detail
{

template <typename T>
T ReadUnchecked(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);
  
  T data;
  ReadUnchecked(process, address, std::addressof(data), sizeof(data));
  return data;
}

}

template <typename T>
T Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);
  
  T data;
  detail::Read(process, address, std::addressof(data), sizeof(data));
  return data;
}

template <typename T, std::size_t N>
std::array<T, N> Read(Process const& process, PVOID address)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);

  std::array<T, N> data;
  detail::Read(process, address, data.data(), sizeof(T) * N);
  return data;
}

// TODO: Rewrite majority of function to not depend on T, then move the logic 
// to an implementation file.
template <typename T>
std::basic_string<T> ReadString(Process const& process, PVOID address, 
  std::size_t chunk_len = 128)
{
  HADESMEM_STATIC_ASSERT(detail::IsCharType<T>::value);

  assert(chunk_len != 0);

  detail::ProtectGuard protect_guard(&process, address, 
    detail::ProtectGuardType::kRead);

  std::basic_string<T> data;

  MEMORY_BASIC_INFORMATION const mbi = detail::Query(process, address);
  PVOID const region_end = static_cast<PBYTE>(mbi.BaseAddress) + 
    mbi.RegionSize;

  T* cur = static_cast<T*>(address);
  while (cur + 1 < region_end)
  {
    std::size_t const len_to_end = reinterpret_cast<DWORD_PTR>(region_end) - 
      reinterpret_cast<DWORD_PTR>(cur);
    std::size_t const buf_len_bytes = (std::min)(chunk_len * sizeof(T), 
      len_to_end);
    std::size_t const buf_len = buf_len_bytes / sizeof(T);

    std::vector<T> buf(buf_len);
    detail::Read(process, cur, buf.data(), buf.size() * sizeof(T));

    auto const iter = std::find(std::begin(buf), std::end(buf), T());
    std::copy(std::begin(buf), iter, std::back_inserter(data));

    if (iter != std::end(buf))
    {
      protect_guard.Restore();
      return data;
    }

    cur += buf_len;
  }

  BOOST_THROW_EXCEPTION(Error() << 
    ErrorString("Attempt to read across a region boundary."));
}

template <typename T>
std::vector<T> ReadVector(Process const& process, PVOID address, 
  std::size_t size)
{
  HADESMEM_STATIC_ASSERT(detail::IsTriviallyCopyable<T>::value);

  HADESMEM_STATIC_ASSERT(detail::IsDefaultConstructible<T>::value);
  
  std::vector<T> data(size);
  detail::Read(process, address, data.data(), sizeof(T) * size);
  return data;
}

}
{'fraction_non_alphanumeric': 0.1412151067323481, 'fraction_numerical': 0.004030452306314375, 'mean_word_length': 5.019766397124887, 'pattern_counts': {'":': 0, '<': 74, '<?xml version=': 0, '>': 72, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '104263', 'n_tokens_mistral': 2454, 'n_tokens_neox': 2334, 'n_words': 483}