<commit_before>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <algorithm>
#include <array>
#include <cstdint>
#include <iterator>
#include <string>
#include <utility>
#include <vector>

#include <windows.h>

#include <hadesmem/alloc.hpp>
#include <hadesmem/call.hpp>
#include <hadesmem/config.hpp>
#include <hadesmem/detail/argv_quote.hpp>
#include <hadesmem/detail/assert.hpp>
#include <hadesmem/detail/filesystem.hpp>
#include <hadesmem/detail/force_initialize.hpp>
#include <hadesmem/detail/self_path.hpp>
#include <hadesmem/detail/static_assert.hpp>
#include <hadesmem/detail/smart_handle.hpp>
#include <hadesmem/detail/trace.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/find_procedure.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/write.hpp>

namespace hadesmem
{

struct InjectFlags
{
  enum : std::uint32_t
  { kNone = 0,
    kPathResolution = 1 << 0,
    kAddToSearchOrder = 1 << 1,
    kKeepSuspended = 1 << 2,
    kInvalidFlagMaxValue = 1 << 3 };
};

inline HMODULE InjectDll(Process const& process,
                         std::wstring const& path,
                         std::uint32_t flags)
{
  HADESMEM_DETAIL_ASSERT(!(flags & ~(InjectFlags::kInvalidFlagMaxValue - 1UL)));

  bool const path_resolution = !!(flags & InjectFlags::kPathResolution);

  std::wstring const path_real = [&]() -> std::wstring
  {
    if (path_resolution && detail::IsPathRelative(path))
    {
      return detail::CombinePath(detail::GetSelfDirPath(), path);
    }

    return path;
  }();

  bool const add_path = !!(flags & InjectFlags::kAddToSearchOrder);
  if (add_path && detail::IsPathRelative(path_real))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error() << ErrorString("Cannot modify search order unless an absolute "
                             "path or path resolution is used."));
  }

  // Only performing this check when path resolution is enabled
  // because otherwise we would need to perform the check in the
  // context of the remote process, which is not possible to do without
  // introducing race conditions and other potential problems. So we
  // just let LoadLibraryExW do the check for us.
  if (path_resolution && !detail::DoesFileExist(path_real))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error() << ErrorString("Could not find module file."));
  }

  HADESMEM_DETAIL_TRACE_A("Calling ForceLdrInitializeThunk.");

  detail::ForceLdrInitializeThunk(process.GetId());

  HADESMEM_DETAIL_TRACE_FORMAT_W(L"Module path is \"%s\".", path_real.c_str());

  std::size_t const path_buf_size = (path_real.size() + 1) * sizeof(wchar_t);

  HADESMEM_DETAIL_TRACE_A("Allocating memory for module path.");

  Allocator const lib_file_remote{process, path_buf_size};

  HADESMEM_DETAIL_TRACE_A("Writing memory for module path.");

  WriteString(process, lib_file_remote.GetBase(), path_real);

  HADESMEM_DETAIL_TRACE_A("Finding LoadLibraryExW.");

  Module const kernel32_mod{process, L"kernel32.dll"};
  auto const load_library =
    FindProcedure(process, kernel32_mod, "LoadLibraryExW");

  HADESMEM_DETAIL_TRACE_A("Calling LoadLibraryExW.");

  auto const load_library_ret =
    Call(process,
         reinterpret_cast<decltype(&LoadLibraryExW)>(load_library),
         CallConv::kStdCall,
         static_cast<LPCWSTR>(lib_file_remote.GetBase()),
         nullptr,
         add_path ? LOAD_WITH_ALTERED_SEARCH_PATH : 0UL);
  if (!load_library_ret.GetReturnValue())
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"LoadLibraryExW failed."}
              << ErrorCodeWinLast{load_library_ret.GetLastError()});
  }

  return load_library_ret.GetReturnValue();
}

inline void FreeDll(Process const& process, HMODULE module)
{
  Module const kernel32_mod{process, L"kernel32.dll"};
  auto const free_library = FindProcedure(process, kernel32_mod, "FreeLibrary");

  auto const free_library_ret =
    Call(process,
         reinterpret_cast<decltype(&FreeLibrary)>(free_library),
         CallConv::kStdCall,
         module);
  if (!free_library_ret.GetReturnValue())
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"FreeLibrary failed."}
              << ErrorCodeWinLast{free_library_ret.GetLastError()});
  }
}

inline CallResult<DWORD_PTR> CallExport(Process const& process,
                                        HMODULE module,
                                        std::string const& export_name)
{
  Module const module_remote{process, module};
  auto const export_ptr = FindProcedure(process, module_remote, export_name);

  return Call(
    process, reinterpret_cast<DWORD_PTR (*)()>(export_ptr), CallConv::kDefault);
}

class CreateAndInjectData
{
public:
  explicit CreateAndInjectData(Process const& process,
                               HMODULE module,
                               DWORD_PTR export_ret,
                               DWORD export_last_error,
                               detail::SmartHandle&& thread_handle)
    : process_{process},
      module_{module},
      export_ret_{export_ret},
      export_last_error_{export_last_error},
      thread_handle_{std::move(thread_handle)}
  {
  }

  explicit CreateAndInjectData(Process&& process,
                               HMODULE module,
                               DWORD_PTR export_ret,
                               DWORD export_last_error,
                               detail::SmartHandle&& thread_handle) = delete;

#if defined(HADESMEM_DETAIL_NO_RVALUE_REFERENCES_V3)

  CreateAndInjectData(CreateAndInjectData const&) = delete;

  CreateAndInjectData& operator=(CreateAndInjectData const&) = delete;

  CreateAndInjectData(CreateAndInjectData&& other)
    : process_{std::move(other.process_)},
      module_{other.module_},
      export_ret_{other.export_ret_},
      export_last_error_{other.export_last_error_},
      thread_handle_{std::move(other.thread_handle_)}
  {
  }

  CreateAndInjectData& operator=(CreateAndInjectData&& other)
  {
    process_ = std::move(other.process_);
    module_ = other.module_;
    export_ret_ = other.export_ret_;
    export_last_error_ = other.export_last_error_;
    thread_handle_ = std::move(other.thread_handle_);

    return *this;
  }

#else

  // Workaround for Intel C++ compile error (Intel C++ 2013 SP1 Updaate 1).

  CreateAndInjectData(CreateAndInjectData const&) = delete;

  CreateAndInjectData& operator=(CreateAndInjectData const&) = delete;

  CreateAndInjectData(CreateAndInjectData&&) = default;

  CreateAndInjectData& operator=(CreateAndInjectData&&) = default;

#endif // #if defined(HADESMEM_DETAIL_NO_RVALUE_REFERENCES_V3)

  Process GetProcess() const
  {
    return process_;
  }

  HMODULE GetModule() const HADESMEM_DETAIL_NOEXCEPT
  {
    return module_;
  }

  DWORD_PTR GetExportRet() const HADESMEM_DETAIL_NOEXCEPT
  {
    return export_ret_;
  }

  DWORD GetExportLastError() const HADESMEM_DETAIL_NOEXCEPT
  {
    return export_last_error_;
  }

  HANDLE GetThreadHandle() const HADESMEM_DETAIL_NOEXCEPT
  {
    return thread_handle_.GetHandle();
  }

  void ResumeThread() const
  {
    if (::ResumeThread(thread_handle_.GetHandle()) == static_cast<DWORD>(-1))
    {
      DWORD const last_error = ::GetLastError();
      HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                      << ErrorString{"ResumeThread failed."}
                                      << ErrorCodeWinLast{last_error});
    }
  }

private:
  Process process_;
  HMODULE module_;
  DWORD_PTR export_ret_;
  DWORD export_last_error_;
  detail::SmartHandle thread_handle_;
};

template <typename ArgsIter>
inline CreateAndInjectData CreateAndInject(std::wstring const& path,
                                           std::wstring const& work_dir,
                                           ArgsIter args_beg,
                                           ArgsIter args_end,
                                           std::wstring const& module,
                                           std::string const& export_name,
                                           std::uint32_t flags,
                                           std::uint32_t steam_app_id = 0)
{
  using ArgsIterValueType = typename std::iterator_traits<ArgsIter>::value_type;
  HADESMEM_DETAIL_STATIC_ASSERT(
    std::is_base_of<std::wstring, ArgsIterValueType>::value);

  std::wstring const command_line = [&]()
  {
    std::wstring command_line_temp;
    detail::ArgvQuote(&command_line_temp, path, false);
    auto const parse_arg = [&](std::wstring const& arg)
    {
      command_line_temp += L' ';
      detail::ArgvQuote(&command_line_temp, arg, false);
    };
    std::for_each(args_beg, args_end, parse_arg);
    return command_line_temp;
  }();

  std::vector<wchar_t> proc_args(std::begin(command_line),
                                 std::end(command_line));
  proc_args.push_back(L'\0');

  std::wstring const work_dir_real = [&]() -> std::wstring
  {
    if (work_dir.empty() && !path.empty() && !detail::IsPathRelative(path))
    {
      std::size_t const separator = path.find_last_of(L"\\/");
      if (separator != std::wstring::npos && separator != path.size() - 1)
      {
        return path.substr(0, separator + 1);
      }
    }

    return work_dir;
  }();

  auto const read_steam_env_var = [](std::wstring const& name,
                                     std::pair<bool, std::vector<wchar_t>>& var)
  {
    var.second.resize(HADESMEM_DETAIL_MAX_PATH_UNICODE);

    auto const err = ::GetEnvironmentVariableW(
      name.c_str(), var.second.data(), var.second.size());
    if (!err || err > var.second.size())
    {
      DWORD const last_error = ::GetLastError();
      if (last_error != ERROR_ENVVAR_NOT_FOUND)
      {
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"GetEnvironmentVariable failed."}
                  << ErrorCodeWinLast{last_error});
      }

      var.first = false;
    }

    var.first = true;
  };

  auto const write_steam_env_var = [](std::wstring const& name,
                                      std::uint32_t steam_app_id)
  {
    auto const steam_app_id_str = detail::NumToStr<wchar_t>(steam_app_id);
    if (!::SetEnvironmentVariableW(name.c_str(), steam_app_id_str.c_str()))
    {
      DWORD const last_error = ::GetLastError();
      HADESMEM_DETAIL_THROW_EXCEPTION(
        Error{} << ErrorString{"SetEnvironmentVariable failed."}
                << ErrorCodeWinLast{last_error});
    }
  };

  std::pair<bool, std::vector<wchar_t>> old_steam_app_id;
  std::pair<bool, std::vector<wchar_t>> old_steam_game_id;

  if (steam_app_id)
  {
    read_steam_env_var(L"SteamAppId", old_steam_app_id);
    read_steam_env_var(L"SteamGameId", old_steam_game_id);

    write_steam_env_var(L"SteamAppId", steam_app_id);
    write_steam_env_var(L"SteamGameId", steam_app_id);
  }

  STARTUPINFO start_info{};
  start_info.cb = static_cast<DWORD>(sizeof(start_info));
  PROCESS_INFORMATION proc_info{};
  if (!::CreateProcessW(path.c_str(),
                        proc_args.data(),
                        nullptr,
                        nullptr,
                        FALSE,
                        CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT,
                        nullptr,
                        work_dir_real.empty() ? nullptr : work_dir_real.c_str(),
                        &start_info,
                        &proc_info))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"CreateProcess failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  auto const restore_steam_env_var = [](
    std::wstring const& name, std::pair<bool, std::vector<wchar_t>>& var)
  {
    if (!::SetEnvironmentVariableW(name.c_str(),
                                   var.first ? var.second.data() : nullptr))
    {
      DWORD const last_error = ::GetLastError();
      HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                      << ErrorString{"CreateProcess failed."}
                                      << ErrorCodeWinLast{last_error});
    }
  };

  if (steam_app_id)
  {
    restore_steam_env_var(L"SteamAppId", old_steam_app_id);
    restore_steam_env_var(L"SteamGameId", old_steam_game_id);
  }

  detail::SmartHandle const proc_handle{proc_info.hProcess};
  detail::SmartHandle thread_handle{proc_info.hThread};

  try
  {
    Process const process{proc_info.dwProcessId};

    HMODULE const remote_module = InjectDll(process, module, flags);

    CallResult<DWORD_PTR> const export_ret = [&]()
    {
      if (!export_name.empty())
      {
        return CallExport(process, remote_module, export_name);
      }

      return CallResult<DWORD_PTR>(0, 0);
    }();

    if (!(flags & InjectFlags::kKeepSuspended))
    {
      if (::ResumeThread(thread_handle.GetHandle()) == static_cast<DWORD>(-1))
      {
        DWORD const last_error = ::GetLastError();
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"ResumeThread failed."}
                  << ErrorCodeWinLast{last_error}
                  << ErrorCodeWinRet{export_ret.GetReturnValue()}
                  << ErrorCodeWinOther{export_ret.GetLastError()});
      }
    }

    return CreateAndInjectData{process,
                               remote_module,
                               export_ret.GetReturnValue(),
                               export_ret.GetLastError(),
                               std::move(thread_handle)};
  }
  catch (std::exception const& /*e*/)
  {
    // Terminate process if injection failed, otherwise the 'zombie' process
    // would be leaked.
    BOOL const terminated = ::TerminateProcess(proc_handle.GetHandle(), 0);
    (void)terminated;
    HADESMEM_DETAIL_ASSERT(terminated != FALSE);

    throw;
  }
}
}
<commit_msg>* [Injector] x64 compile fix.<commit_after>// Copyright (C) 2010-2014 Joshua Boyce.
// See the file COPYING for copying permission.

#pragma once

#include <algorithm>
#include <array>
#include <cstdint>
#include <iterator>
#include <string>
#include <utility>
#include <vector>

#include <windows.h>

#include <hadesmem/alloc.hpp>
#include <hadesmem/call.hpp>
#include <hadesmem/config.hpp>
#include <hadesmem/detail/argv_quote.hpp>
#include <hadesmem/detail/assert.hpp>
#include <hadesmem/detail/filesystem.hpp>
#include <hadesmem/detail/force_initialize.hpp>
#include <hadesmem/detail/self_path.hpp>
#include <hadesmem/detail/static_assert.hpp>
#include <hadesmem/detail/smart_handle.hpp>
#include <hadesmem/detail/trace.hpp>
#include <hadesmem/error.hpp>
#include <hadesmem/find_procedure.hpp>
#include <hadesmem/module.hpp>
#include <hadesmem/process.hpp>
#include <hadesmem/write.hpp>

namespace hadesmem
{

struct InjectFlags
{
  enum : std::uint32_t
  { kNone = 0,
    kPathResolution = 1 << 0,
    kAddToSearchOrder = 1 << 1,
    kKeepSuspended = 1 << 2,
    kInvalidFlagMaxValue = 1 << 3 };
};

inline HMODULE InjectDll(Process const& process,
                         std::wstring const& path,
                         std::uint32_t flags)
{
  HADESMEM_DETAIL_ASSERT(!(flags & ~(InjectFlags::kInvalidFlagMaxValue - 1UL)));

  bool const path_resolution = !!(flags & InjectFlags::kPathResolution);

  std::wstring const path_real = [&]() -> std::wstring
  {
    if (path_resolution && detail::IsPathRelative(path))
    {
      return detail::CombinePath(detail::GetSelfDirPath(), path);
    }

    return path;
  }();

  bool const add_path = !!(flags & InjectFlags::kAddToSearchOrder);
  if (add_path && detail::IsPathRelative(path_real))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error() << ErrorString("Cannot modify search order unless an absolute "
                             "path or path resolution is used."));
  }

  // Only performing this check when path resolution is enabled
  // because otherwise we would need to perform the check in the
  // context of the remote process, which is not possible to do without
  // introducing race conditions and other potential problems. So we
  // just let LoadLibraryExW do the check for us.
  if (path_resolution && !detail::DoesFileExist(path_real))
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error() << ErrorString("Could not find module file."));
  }

  HADESMEM_DETAIL_TRACE_A("Calling ForceLdrInitializeThunk.");

  detail::ForceLdrInitializeThunk(process.GetId());

  HADESMEM_DETAIL_TRACE_FORMAT_W(L"Module path is \"%s\".", path_real.c_str());

  std::size_t const path_buf_size = (path_real.size() + 1) * sizeof(wchar_t);

  HADESMEM_DETAIL_TRACE_A("Allocating memory for module path.");

  Allocator const lib_file_remote{process, path_buf_size};

  HADESMEM_DETAIL_TRACE_A("Writing memory for module path.");

  WriteString(process, lib_file_remote.GetBase(), path_real);

  HADESMEM_DETAIL_TRACE_A("Finding LoadLibraryExW.");

  Module const kernel32_mod{process, L"kernel32.dll"};
  auto const load_library =
    FindProcedure(process, kernel32_mod, "LoadLibraryExW");

  HADESMEM_DETAIL_TRACE_A("Calling LoadLibraryExW.");

  auto const load_library_ret =
    Call(process,
         reinterpret_cast<decltype(&LoadLibraryExW)>(load_library),
         CallConv::kStdCall,
         static_cast<LPCWSTR>(lib_file_remote.GetBase()),
         nullptr,
         add_path ? LOAD_WITH_ALTERED_SEARCH_PATH : 0UL);
  if (!load_library_ret.GetReturnValue())
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"LoadLibraryExW failed."}
              << ErrorCodeWinLast{load_library_ret.GetLastError()});
  }

  return load_library_ret.GetReturnValue();
}

inline void FreeDll(Process const& process, HMODULE module)
{
  Module const kernel32_mod{process, L"kernel32.dll"};
  auto const free_library = FindProcedure(process, kernel32_mod, "FreeLibrary");

  auto const free_library_ret =
    Call(process,
         reinterpret_cast<decltype(&FreeLibrary)>(free_library),
         CallConv::kStdCall,
         module);
  if (!free_library_ret.GetReturnValue())
  {
    HADESMEM_DETAIL_THROW_EXCEPTION(
      Error{} << ErrorString{"FreeLibrary failed."}
              << ErrorCodeWinLast{free_library_ret.GetLastError()});
  }
}

inline CallResult<DWORD_PTR> CallExport(Process const& process,
                                        HMODULE module,
                                        std::string const& export_name)
{
  Module const module_remote{process, module};
  auto const export_ptr = FindProcedure(process, module_remote, export_name);

  return Call(
    process, reinterpret_cast<DWORD_PTR (*)()>(export_ptr), CallConv::kDefault);
}

class CreateAndInjectData
{
public:
  explicit CreateAndInjectData(Process const& process,
                               HMODULE module,
                               DWORD_PTR export_ret,
                               DWORD export_last_error,
                               detail::SmartHandle&& thread_handle)
    : process_{process},
      module_{module},
      export_ret_{export_ret},
      export_last_error_{export_last_error},
      thread_handle_{std::move(thread_handle)}
  {
  }

  explicit CreateAndInjectData(Process&& process,
                               HMODULE module,
                               DWORD_PTR export_ret,
                               DWORD export_last_error,
                               detail::SmartHandle&& thread_handle) = delete;

#if defined(HADESMEM_DETAIL_NO_RVALUE_REFERENCES_V3)

  CreateAndInjectData(CreateAndInjectData const&) = delete;

  CreateAndInjectData& operator=(CreateAndInjectData const&) = delete;

  CreateAndInjectData(CreateAndInjectData&& other)
    : process_{std::move(other.process_)},
      module_{other.module_},
      export_ret_{other.export_ret_},
      export_last_error_{other.export_last_error_},
      thread_handle_{std::move(other.thread_handle_)}
  {
  }

  CreateAndInjectData& operator=(CreateAndInjectData&& other)
  {
    process_ = std::move(other.process_);
    module_ = other.module_;
    export_ret_ = other.export_ret_;
    export_last_error_ = other.export_last_error_;
    thread_handle_ = std::move(other.thread_handle_);

    return *this;
  }

#else

  // Workaround for Intel C++ compile error (Intel C++ 2013 SP1 Updaate 1).

  CreateAndInjectData(CreateAndInjectData const&) = delete;

  CreateAndInjectData& operator=(CreateAndInjectData const&) = delete;

  CreateAndInjectData(CreateAndInjectData&&) = default;

  CreateAndInjectData& operator=(CreateAndInjectData&&) = default;

#endif // #if defined(HADESMEM_DETAIL_NO_RVALUE_REFERENCES_V3)

  Process GetProcess() const
  {
    return process_;
  }

  HMODULE GetModule() const HADESMEM_DETAIL_NOEXCEPT
  {
    return module_;
  }

  DWORD_PTR GetExportRet() const HADESMEM_DETAIL_NOEXCEPT
  {
    return export_ret_;
  }

  DWORD GetExportLastError() const HADESMEM_DETAIL_NOEXCEPT
  {
    return export_last_error_;
  }

  HANDLE GetThreadHandle() const HADESMEM_DETAIL_NOEXCEPT
  {
    return thread_handle_.GetHandle();
  }

  void ResumeThread() const
  {
    if (::ResumeThread(thread_handle_.GetHandle()) == static_cast<DWORD>(-1))
    {
      DWORD const last_error = ::GetLastError();
      HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                      << ErrorString{"ResumeThread failed."}
                                      << ErrorCodeWinLast{last_error});
    }
  }

private:
  Process process_;
  HMODULE module_;
  DWORD_PTR export_ret_;
  DWORD export_last_error_;
  detail::SmartHandle thread_handle_;
};

template <typename ArgsIter>
inline CreateAndInjectData CreateAndInject(std::wstring const& path,
                                           std::wstring const& work_dir,
                                           ArgsIter args_beg,
                                           ArgsIter args_end,
                                           std::wstring const& module,
                                           std::string const& export_name,
                                           std::uint32_t flags,
                                           std::uint32_t steam_app_id = 0)
{
  using ArgsIterValueType = typename std::iterator_traits<ArgsIter>::value_type;
  HADESMEM_DETAIL_STATIC_ASSERT(
    std::is_base_of<std::wstring, ArgsIterValueType>::value);

  std::wstring const command_line = [&]()
  {
    std::wstring command_line_temp;
    detail::ArgvQuote(&command_line_temp, path, false);
    auto const parse_arg = [&](std::wstring const& arg)
    {
      command_line_temp += L' ';
      detail::ArgvQuote(&command_line_temp, arg, false);
    };
    std::for_each(args_beg, args_end, parse_arg);
    return command_line_temp;
  }();

  std::vector<wchar_t> proc_args(std::begin(command_line),
                                 std::end(command_line));
  proc_args.push_back(L'\0');

  std::wstring const work_dir_real = [&]() -> std::wstring
  {
    if (work_dir.empty() && !path.empty() && !detail::IsPathRelative(path))
    {
      std::size_t const separator = path.find_last_of(L"\\/");
      if (separator != std::wstring::npos && separator != path.size() - 1)
      {
        return path.substr(0, separator + 1);
      }
    }

    return work_dir;
  }();

  auto const read_steam_env_var = [](std::wstring const& name,
                                     std::pair<bool, std::vector<wchar_t>>& var)
  {
    var.second.resize(HADESMEM_DETAIL_MAX_PATH_UNICODE);

    auto const err = ::GetEnvironmentVariableW(
      name.c_str(), var.second.data(), static_cast<DWORD>(var.second.size()));
    if (!err || err > var.second.size())
    {
      DWORD const last_error = ::GetLastError();
      if (last_error != ERROR_ENVVAR_NOT_FOUND)
      {
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"GetEnvironmentVariable failed."}
                  << ErrorCodeWinLast{last_error});
      }

      var.first = false;
    }

    var.first = true;
  };

  auto const write_steam_env_var = [](std::wstring const& name,
                                      std::uint32_t steam_app_id)
  {
    auto const steam_app_id_str = detail::NumToStr<wchar_t>(steam_app_id);
    if (!::SetEnvironmentVariableW(name.c_str(), steam_app_id_str.c_str()))
    {
      DWORD const last_error = ::GetLastError();
      HADESMEM_DETAIL_THROW_EXCEPTION(
        Error{} << ErrorString{"SetEnvironmentVariable failed."}
                << ErrorCodeWinLast{last_error});
    }
  };

  std::pair<bool, std::vector<wchar_t>> old_steam_app_id;
  std::pair<bool, std::vector<wchar_t>> old_steam_game_id;

  if (steam_app_id)
  {
    read_steam_env_var(L"SteamAppId", old_steam_app_id);
    read_steam_env_var(L"SteamGameId", old_steam_game_id);

    write_steam_env_var(L"SteamAppId", steam_app_id);
    write_steam_env_var(L"SteamGameId", steam_app_id);
  }

  STARTUPINFO start_info{};
  start_info.cb = static_cast<DWORD>(sizeof(start_info));
  PROCESS_INFORMATION proc_info{};
  if (!::CreateProcessW(path.c_str(),
                        proc_args.data(),
                        nullptr,
                        nullptr,
                        FALSE,
                        CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT,
                        nullptr,
                        work_dir_real.empty() ? nullptr : work_dir_real.c_str(),
                        &start_info,
                        &proc_info))
  {
    DWORD const last_error = ::GetLastError();
    HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                    << ErrorString{"CreateProcess failed."}
                                    << ErrorCodeWinLast{last_error});
  }

  auto const restore_steam_env_var = [](
    std::wstring const& name, std::pair<bool, std::vector<wchar_t>>& var)
  {
    if (!::SetEnvironmentVariableW(name.c_str(),
                                   var.first ? var.second.data() : nullptr))
    {
      DWORD const last_error = ::GetLastError();
      HADESMEM_DETAIL_THROW_EXCEPTION(Error{}
                                      << ErrorString{"CreateProcess failed."}
                                      << ErrorCodeWinLast{last_error});
    }
  };

  if (steam_app_id)
  {
    restore_steam_env_var(L"SteamAppId", old_steam_app_id);
    restore_steam_env_var(L"SteamGameId", old_steam_game_id);
  }

  detail::SmartHandle const proc_handle{proc_info.hProcess};
  detail::SmartHandle thread_handle{proc_info.hThread};

  try
  {
    Process const process{proc_info.dwProcessId};

    HMODULE const remote_module = InjectDll(process, module, flags);

    CallResult<DWORD_PTR> const export_ret = [&]()
    {
      if (!export_name.empty())
      {
        return CallExport(process, remote_module, export_name);
      }

      return CallResult<DWORD_PTR>(0, 0);
    }();

    if (!(flags & InjectFlags::kKeepSuspended))
    {
      if (::ResumeThread(thread_handle.GetHandle()) == static_cast<DWORD>(-1))
      {
        DWORD const last_error = ::GetLastError();
        HADESMEM_DETAIL_THROW_EXCEPTION(
          Error{} << ErrorString{"ResumeThread failed."}
                  << ErrorCodeWinLast{last_error}
                  << ErrorCodeWinRet{export_ret.GetReturnValue()}
                  << ErrorCodeWinOther{export_ret.GetLastError()});
      }
    }

    return CreateAndInjectData{process,
                               remote_module,
                               export_ret.GetReturnValue(),
                               export_ret.GetLastError(),
                               std::move(thread_handle)};
  }
  catch (std::exception const& /*e*/)
  {
    // Terminate process if injection failed, otherwise the 'zombie' process
    // would be leaked.
    BOOL const terminated = ::TerminateProcess(proc_handle.GetHandle(), 0);
    (void)terminated;
    HADESMEM_DETAIL_ASSERT(terminated != FALSE);

    throw;
  }
}
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// Copyright (c) 2014 Michael G. Brehm
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//-----------------------------------------------------------------------------

#include "stdafx.h"						// Include project pre-compiled headers
#include "MemoryRegion.h"				// Include MemoryRegion declarations

#pragma warning(push, 4)				// Enable maximum compiler warnings

//-----------------------------------------------------------------------------
// Static Initializers

MemoryRegion::SystemInfo MemoryRegion::s_sysinfo;
size_t const MemoryRegion::AllocationGranularity = MemoryRegion::s_sysinfo.dwAllocationGranularity;
size_t const MemoryRegion::PageSize = MemoryRegion::s_sysinfo.dwPageSize;

//-----------------------------------------------------------------------------
// MemoryRegion Constructor (private)
//
// Arguments:
//
//	base		- Optional base address to use for the allocation
//	length		- Length of the memory region to allocate
//	flags		- Memory region allocation type flags
//	protect		- Memory region protection flags

MemoryRegion::MemoryRegion(void* base, size_t length, DWORD flags, DWORD protect)
{
	// Verify that the specified address aligns with the allocation granularity.
	// Unlike Commit/Protect/etc, do not automatically adjust this before reserving
	if(base && (uintptr_t(base) % AllocationGranularity)) throw Win32Exception(ERROR_MAPPED_ALIGNMENT);

	// Pass the arguments onto VirtualAlloc() and just throw any resultant error
	m_base = VirtualAlloc(base, length, flags, protect);
	if(!m_base) throw Win32Exception();

	m_length = length;					// Save the length for destructor
}

//-----------------------------------------------------------------------------
// MemoryRegion Destructor

MemoryRegion::~MemoryRegion()
{
	if(m_base) VirtualFree(m_base, m_length, MEM_RELEASE);
}

//-----------------------------------------------------------------------------
// MemoryRegion::AlignToAllocationGranularity (static)
//
// Aligns an address down to the system allocation granularity
//
// Arguments:
//
//	address		- Address to be aligned

void* MemoryRegion::AlignToAllocationGranularity(void* address)
{
	return reinterpret_cast<void*>(AlignDown(uintptr_t(address), MemoryRegion::AllocationGranularity));
}

//-----------------------------------------------------------------------------
// MemoryRegion::AlignToPageSize (static)
//
// Aligns an address down to the system page size
//
// Arguments:
//
//	address		- Address to be aligned

void* MemoryRegion::AlignToPageSize(void* address)
{
	return reinterpret_cast<void*>(AlignDown(uintptr_t(address), MemoryRegion::PageSize));
}

//-----------------------------------------------------------------------------
// MemoryRegion::AlignDown (private, static)
//
// Aligns an offset down to the specified alignment
//
// Arguments:
//
//	address		- Address to be aligned
//	alignment	- Alignment

uintptr_t MemoryRegion::AlignDown(uintptr_t address, size_t alignment)
{
	if(alignment < 1) throw Exception(E_ARGUMENTOUTOFRANGE, _T("alignment"));

	if(address < alignment) return 0;
	else return AlignUp(address - (alignment - 1), alignment);
}

//---------------------------------------------------------------------------
// MemoryRegion::AlignUp (private, static)
//
// Aligns an offset up to the specified alignment
//
// Arguments:
//
//	address		- Address to be aligned
//	alignment	- Alignment

uintptr_t MemoryRegion::AlignUp(uintptr_t address, size_t alignment)
{
	if(alignment < 1) throw Exception(E_ARGUMENTOUTOFRANGE, _T("alignment"));

	if(address == 0) return 0;
	else return address + ((alignment - (address % alignment)) % alignment);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Commit
//
// Commits page(s) of memory within the region using the specified protection
// attributes.  If address does not align on a page boundary it will be aligned
// down and returned as the result from this function
//
// Arguments:
//
//	address		- Base address to be committed
//	length		- Length of the region to be committed
//	protect		- Protection flags to be applied to the committed region

void* MemoryRegion::Commit(void* address, size_t length, DWORD protect)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualAlloc() to commit the page(s) within the region
	return VirtualAlloc(reinterpret_cast<void*>(aligned), length, MEM_COMMIT, protect);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Decommit
//
// Decommits page(s) of memory from within the region
//
// Arguments:
//
//	address		- Base address to be decommitted
//	length		- Length of the region to be decommitted

void* MemoryRegion::Decommit(void* address, size_t length)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualFree() to decommit the page(s) from within the region
	if(!VirtualFree(reinterpret_cast<void*>(aligned), length, MEM_DECOMMIT)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Lock
//
// Locks page(s) of the region into physical memory
//
// Arguments:
//
//	address		- Base address to be locked
//	length		- Length of the region to be locked

void* MemoryRegion::Lock(void* address, size_t length)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualLock() to lock the page(s) into physical memory
	if(!VirtualLock(reinterpret_cast<void*>(aligned), length)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Protect
//
// Applies new protection flags to page(s) within the allocated region
//
// Arguments:
//
//	address		- Base address to apply the protection
//	length		- Length of the memory to apply the protection to
//	protect		- Virtual memory protection flags

void* MemoryRegion::Protect(void* address, size_t length, DWORD protect)
{
	DWORD		oldprotect;					// Old protection flags

	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Apply the requested protection flags; throw away the rest
	if(!VirtualProtect(reinterpret_cast<void*>(aligned), length, protect, &oldprotect)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Unlock
//
// Unlocks page(s) of the region from physical memory
//
// Arguments:
//
//	address		- Base address to be unlocked
//	length		- Length of the region to be unlocked

void* MemoryRegion::Unlock(void* address, size_t length)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualUnlock() to unlock the page(s) from physical memory
	if(!VirtualUnlock(reinterpret_cast<void*>(aligned), length)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------

#pragma warning(pop)
<commit_msg>Downward align virtual memory reservations; 32-bit ELF binaries don't typically align on 64KiB boundaries<commit_after>//-----------------------------------------------------------------------------
// Copyright (c) 2014 Michael G. Brehm
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//-----------------------------------------------------------------------------

#include "stdafx.h"						// Include project pre-compiled headers
#include "MemoryRegion.h"				// Include MemoryRegion declarations

#pragma warning(push, 4)				// Enable maximum compiler warnings

//-----------------------------------------------------------------------------
// Static Initializers

MemoryRegion::SystemInfo MemoryRegion::s_sysinfo;
size_t const MemoryRegion::AllocationGranularity = MemoryRegion::s_sysinfo.dwAllocationGranularity;
size_t const MemoryRegion::PageSize = MemoryRegion::s_sysinfo.dwPageSize;

//-----------------------------------------------------------------------------
// MemoryRegion Constructor (private)
//
// Arguments:
//
//	base		- Optional base address to use for the allocation
//	length		- Length of the memory region to allocate
//	flags		- Memory region allocation type flags
//	protect		- Memory region protection flags

MemoryRegion::MemoryRegion(void* base, size_t length, DWORD flags, DWORD protect)
{
	uintptr_t requested = uintptr_t(base);
	uintptr_t aligned = uintptr_t(AlignToAllocationGranularity(base));

	// Adjust the requested length to accomodate any downward alignment
	length += requested - aligned;

	// Pass the arguments onto VirtualAlloc() and just throw any resultant error
	m_base = VirtualAlloc(base, length, flags, protect);
	if(!m_base) throw Win32Exception();

	m_length = length;					// Save the length for destructor
}

//-----------------------------------------------------------------------------
// MemoryRegion Destructor

MemoryRegion::~MemoryRegion()
{
	if(m_base) VirtualFree(m_base, m_length, MEM_RELEASE);
}

//-----------------------------------------------------------------------------
// MemoryRegion::AlignToAllocationGranularity (static)
//
// Aligns an address down to the system allocation granularity
//
// Arguments:
//
//	address		- Address to be aligned

void* MemoryRegion::AlignToAllocationGranularity(void* address)
{
	return reinterpret_cast<void*>(AlignDown(uintptr_t(address), MemoryRegion::AllocationGranularity));
}

//-----------------------------------------------------------------------------
// MemoryRegion::AlignToPageSize (static)
//
// Aligns an address down to the system page size
//
// Arguments:
//
//	address		- Address to be aligned

void* MemoryRegion::AlignToPageSize(void* address)
{
	return reinterpret_cast<void*>(AlignDown(uintptr_t(address), MemoryRegion::PageSize));
}

//-----------------------------------------------------------------------------
// MemoryRegion::AlignDown (private, static)
//
// Aligns an offset down to the specified alignment
//
// Arguments:
//
//	address		- Address to be aligned
//	alignment	- Alignment

uintptr_t MemoryRegion::AlignDown(uintptr_t address, size_t alignment)
{
	if(alignment < 1) throw Exception(E_ARGUMENTOUTOFRANGE, _T("alignment"));

	if(address < alignment) return 0;
	else return AlignUp(address - (alignment - 1), alignment);
}

//---------------------------------------------------------------------------
// MemoryRegion::AlignUp (private, static)
//
// Aligns an offset up to the specified alignment
//
// Arguments:
//
//	address		- Address to be aligned
//	alignment	- Alignment

uintptr_t MemoryRegion::AlignUp(uintptr_t address, size_t alignment)
{
	if(alignment < 1) throw Exception(E_ARGUMENTOUTOFRANGE, _T("alignment"));

	if(address == 0) return 0;
	else return address + ((alignment - (address % alignment)) % alignment);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Commit
//
// Commits page(s) of memory within the region using the specified protection
// attributes.  If address does not align on a page boundary it will be aligned
// down and returned as the result from this function
//
// Arguments:
//
//	address		- Base address to be committed
//	length		- Length of the region to be committed
//	protect		- Protection flags to be applied to the committed region

void* MemoryRegion::Commit(void* address, size_t length, DWORD protect)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualAlloc() to commit the page(s) within the region
	return VirtualAlloc(reinterpret_cast<void*>(aligned), length, MEM_COMMIT, protect);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Decommit
//
// Decommits page(s) of memory from within the region
//
// Arguments:
//
//	address		- Base address to be decommitted
//	length		- Length of the region to be decommitted

void* MemoryRegion::Decommit(void* address, size_t length)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualFree() to decommit the page(s) from within the region
	if(!VirtualFree(reinterpret_cast<void*>(aligned), length, MEM_DECOMMIT)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Lock
//
// Locks page(s) of the region into physical memory
//
// Arguments:
//
//	address		- Base address to be locked
//	length		- Length of the region to be locked

void* MemoryRegion::Lock(void* address, size_t length)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualLock() to lock the page(s) into physical memory
	if(!VirtualLock(reinterpret_cast<void*>(aligned), length)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Protect
//
// Applies new protection flags to page(s) within the allocated region
//
// Arguments:
//
//	address		- Base address to apply the protection
//	length		- Length of the memory to apply the protection to
//	protect		- Virtual memory protection flags

void* MemoryRegion::Protect(void* address, size_t length, DWORD protect)
{
	DWORD		oldprotect;					// Old protection flags

	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Apply the requested protection flags; throw away the rest
	if(!VirtualProtect(reinterpret_cast<void*>(aligned), length, protect, &oldprotect)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------
// MemoryRegion::Unlock
//
// Unlocks page(s) of the region from physical memory
//
// Arguments:
//
//	address		- Base address to be unlocked
//	length		- Length of the region to be unlocked

void* MemoryRegion::Unlock(void* address, size_t length)
{
	uintptr_t base = uintptr_t(m_base);
	uintptr_t requested = uintptr_t(address);
	uintptr_t aligned = uintptr_t(AlignToPageSize(address));

	// Verify the requested address space is not outside of the region
	length += requested - aligned;
	if((aligned < base) || ((aligned + length) > (base + m_length))) throw Exception(E_BOUNDS);

	// Use VirtualUnlock() to unlock the page(s) from physical memory
	if(!VirtualUnlock(reinterpret_cast<void*>(aligned), length)) throw Win32Exception();

	return reinterpret_cast<void*>(aligned);
}

//-----------------------------------------------------------------------------

#pragma warning(pop)
<|endoftext|>


<commit_before>/**
 * @file   lllinstancetracker.cpp
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

// Precompiled header
#include "linden_common.h"
// associated header
#include "llinstancetracker.h"
// STL headers
// std headers
// external library headers
// other Linden headers

//static
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
{
	static std::map<std::string, void *> instances;

	std::string k = info.name();
	if(instances.find(k) == instances.end())
	{
		instances[k] = NULL;
	}

	return instances[k];
}

<commit_msg>instancetracker improvements, by Nicky Dasmijn<commit_after>/**
 * @file   lllinstancetracker.cpp
 *
 * $LicenseInfo:firstyear=2009&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

// Precompiled header
#include "linden_common.h"
// associated header
#include "llinstancetracker.h"
// STL headers
// std headers
// external library headers
// other Linden headers

//static
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
{
// <ND> This is called a HUGE amount of times. Just use the name() ptr in a map instead of making expensive string compares each time
//	static std::map<std::string, void *> instances;
//
//	std::string k = info.name();
//	if(instances.find(k) == instances.end())
//	{
//		instances[k] = NULL;
//	}
//
//	return instances[k];

	static std::map<char const*, void *> instances;
	std::map< char const *, void* >::iterator itr = instances.find( info.name() );
	//	std::string k = info.name();
	if(itr == instances.end())
	{
		itr = instances.insert( std::make_pair( info.name(), (void*)0 ) ).first;
	}
	return itr->second;
// </ND>

}

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: numvset.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2005-01-21 15:00:37 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef _SVX_NUMVSET_HXX
#define _SVX_NUMVSET_HXX

// include ---------------------------------------------------------------

#ifndef _VALUESET_HXX //autogen
#include <svtools/valueset.hxx>
#endif
#include <limits.h>
#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_H_
#include <com/sun/star/uno/Sequence.h>
#endif
#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif

#ifndef INCLUDED_SVXDLLAPI_H
#include "svx/svxdllapi.h"
#endif

namespace com{namespace sun{ namespace star{
    namespace container{
        class XIndexAccess;
    }
    namespace beans{
        struct PropertyValue;
    }
    namespace text{
        class XNumberingFormatter;
    }
}}}

class SvxBrushItem;
class SvxNumRule;
struct SvxBmpItemInfo
{
    SvxBrushItem*   pBrushItem;
    USHORT          nItemId;
};

/*-----------------09/09/97 01:05pm-----------------

--------------------------------------------------*/
class SVX_DLLPUBLIC SvxNumValueSet : public ValueSet
{
    Color           aLineColor;
    USHORT          nPageType;
    BOOL            bHTMLMode;
    Rectangle       aOrgRect;
    VirtualDevice*  pVDev;

    com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter> xFormatter;
    com::sun::star::lang::Locale aLocale;

    com::sun::star::uno::Sequence<
        com::sun::star::uno::Sequence<
            com::sun::star::beans::PropertyValue> > aNumSettings;

    com::sun::star::uno::Sequence<
        com::sun::star::uno::Reference<
            com::sun::star::container::XIndexAccess> > aOutlineSettings;
    public:
        SvxNumValueSet( Window* pParent, const ResId& rResId, USHORT nType );
        ~SvxNumValueSet();

    virtual void    UserDraw( const UserDrawEvent& rUDEvt );

    void            SetHTMLMode(BOOL bSet) {bHTMLMode = bSet;}
    void            SetNumberingSettings(
        const com::sun::star::uno::Sequence<
            com::sun::star::uno::Sequence<
                com::sun::star::beans::PropertyValue> >& aNum,
        com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter>& xFormatter,
        const com::sun::star::lang::Locale& rLocale );

    void            SetOutlineNumberingSettings(
            com::sun::star::uno::Sequence<
                com::sun::star::uno::Reference<
                    com::sun::star::container::XIndexAccess> >& rOutline,
            com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter>& xFormatter,
            const com::sun::star::lang::Locale& rLocale);
};

/*-----------------13.02.97 09.32-------------------

--------------------------------------------------*/

class SVX_DLLPUBLIC SvxBmpNumValueSet : public SvxNumValueSet
{
    String      sBullets;
    Timer       aFormatTimer;
    BOOL        bGrfNotFound;

    protected:
        DECL_LINK(FormatHdl_Impl, Timer*);

    void            SetGrfNotFound(BOOL bSet) {bGrfNotFound = bSet;}
    BOOL            IsGrfNotFound()const {return bGrfNotFound;}

    Timer&          GetFormatTimer() {return aFormatTimer;}

    public:
        SvxBmpNumValueSet( Window* pParent, const ResId& rResId/*, const List& rStrNames*/);
        ~SvxBmpNumValueSet();

    virtual void    UserDraw( const UserDrawEvent& rUDEvt );

};
/*-----------------02.12.97 10:31-------------------

--------------------------------------------------*/

class SvxNumberingPreview : public Window
{
    const SvxNumRule*   pActNum;
    Font                aStdFont;
    long                nPageWidth;
    const String*       pOutlineNames;
    BOOL                bPosition;
    UINT16              nActLevel;

    protected:
        virtual void        Paint( const Rectangle& rRect );

    public:
        SvxNumberingPreview(Window* pParent, const ResId& rResId ) :
            Window(pParent, rResId),
            pActNum(0),nPageWidth(0), pOutlineNames(0), bPosition(FALSE), nActLevel(USHRT_MAX)
            { SetBorderStyle( WINDOW_BORDER_MONO ); }

        void    SetNumRule(const SvxNumRule* pNum)
                    {pActNum = pNum; Invalidate();};
        void    SetPageWidth(long nPgWidth)
                                {nPageWidth = nPgWidth;}
        void    SetOutlineNames(const String* pNames)
                        {pOutlineNames = pNames;}
        void    SetPositionMode()
                        { bPosition = TRUE;}
        void    SetLevel(USHORT nSet) {nActLevel = nSet;}

};

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.5.430); FILE MERGED 2005/09/05 14:15:50 rt 1.5.430.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: numvset.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 18:08:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SVX_NUMVSET_HXX
#define _SVX_NUMVSET_HXX

// include ---------------------------------------------------------------

#ifndef _VALUESET_HXX //autogen
#include <svtools/valueset.hxx>
#endif
#include <limits.h>
#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_H_
#include <com/sun/star/uno/Sequence.h>
#endif
#ifndef _COM_SUN_STAR_LANG_LOCALE_HPP_
#include <com/sun/star/lang/Locale.hpp>
#endif

#ifndef INCLUDED_SVXDLLAPI_H
#include "svx/svxdllapi.h"
#endif

namespace com{namespace sun{ namespace star{
    namespace container{
        class XIndexAccess;
    }
    namespace beans{
        struct PropertyValue;
    }
    namespace text{
        class XNumberingFormatter;
    }
}}}

class SvxBrushItem;
class SvxNumRule;
struct SvxBmpItemInfo
{
    SvxBrushItem*   pBrushItem;
    USHORT          nItemId;
};

/*-----------------09/09/97 01:05pm-----------------

--------------------------------------------------*/
class SVX_DLLPUBLIC SvxNumValueSet : public ValueSet
{
    Color           aLineColor;
    USHORT          nPageType;
    BOOL            bHTMLMode;
    Rectangle       aOrgRect;
    VirtualDevice*  pVDev;

    com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter> xFormatter;
    com::sun::star::lang::Locale aLocale;

    com::sun::star::uno::Sequence<
        com::sun::star::uno::Sequence<
            com::sun::star::beans::PropertyValue> > aNumSettings;

    com::sun::star::uno::Sequence<
        com::sun::star::uno::Reference<
            com::sun::star::container::XIndexAccess> > aOutlineSettings;
    public:
        SvxNumValueSet( Window* pParent, const ResId& rResId, USHORT nType );
        ~SvxNumValueSet();

    virtual void    UserDraw( const UserDrawEvent& rUDEvt );

    void            SetHTMLMode(BOOL bSet) {bHTMLMode = bSet;}
    void            SetNumberingSettings(
        const com::sun::star::uno::Sequence<
            com::sun::star::uno::Sequence<
                com::sun::star::beans::PropertyValue> >& aNum,
        com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter>& xFormatter,
        const com::sun::star::lang::Locale& rLocale );

    void            SetOutlineNumberingSettings(
            com::sun::star::uno::Sequence<
                com::sun::star::uno::Reference<
                    com::sun::star::container::XIndexAccess> >& rOutline,
            com::sun::star::uno::Reference<com::sun::star::text::XNumberingFormatter>& xFormatter,
            const com::sun::star::lang::Locale& rLocale);
};

/*-----------------13.02.97 09.32-------------------

--------------------------------------------------*/

class SVX_DLLPUBLIC SvxBmpNumValueSet : public SvxNumValueSet
{
    String      sBullets;
    Timer       aFormatTimer;
    BOOL        bGrfNotFound;

    protected:
        DECL_LINK(FormatHdl_Impl, Timer*);

    void            SetGrfNotFound(BOOL bSet) {bGrfNotFound = bSet;}
    BOOL            IsGrfNotFound()const {return bGrfNotFound;}

    Timer&          GetFormatTimer() {return aFormatTimer;}

    public:
        SvxBmpNumValueSet( Window* pParent, const ResId& rResId/*, const List& rStrNames*/);
        ~SvxBmpNumValueSet();

    virtual void    UserDraw( const UserDrawEvent& rUDEvt );

};
/*-----------------02.12.97 10:31-------------------

--------------------------------------------------*/

class SvxNumberingPreview : public Window
{
    const SvxNumRule*   pActNum;
    Font                aStdFont;
    long                nPageWidth;
    const String*       pOutlineNames;
    BOOL                bPosition;
    UINT16              nActLevel;

    protected:
        virtual void        Paint( const Rectangle& rRect );

    public:
        SvxNumberingPreview(Window* pParent, const ResId& rResId ) :
            Window(pParent, rResId),
            pActNum(0),nPageWidth(0), pOutlineNames(0), bPosition(FALSE), nActLevel(USHRT_MAX)
            { SetBorderStyle( WINDOW_BORDER_MONO ); }

        void    SetNumRule(const SvxNumRule* pNum)
                    {pActNum = pNum; Invalidate();};
        void    SetPageWidth(long nPgWidth)
                                {nPageWidth = nPgWidth;}
        void    SetOutlineNames(const String* pNames)
                        {pOutlineNames = pNames;}
        void    SetPositionMode()
                        { bPosition = TRUE;}
        void    SetLevel(USHORT nSet) {nActLevel = nSet;}

};

#endif

<|endoftext|>


<commit_before>// Module:  Log4CPLUS
// File:    strftime.cxx
// Created: 4/2003
// Author:  Tad E. Smith
//
//
// Copyright (C) Tad E. Smith  All rights reserved.
//
// This software is published under the terms of the Apache Software
// License version 1.1, a copy of which has been included with this
// distribution in the LICENSE.APL file.
//
// $Log: not supported by cvs2svn $

#include <log4cplus/helpers/strftime.h>

#include <ctime>
#ifdef TM_IN_SYS_TIME
#include <sys/time.h>
#endif

using namespace log4cplus;

//////////////////////////////////////////////////////////////////////////////
// Global methods
//////////////////////////////////////////////////////////////////////////////

size_t
log4cplus::helpers::strftime(tchar* s, size_t max,
                             const tchar* format, const struct tm* tm)
{
#ifdef UNICODE
    return ::wcsftime(s, max, format, tm);
#else
    return std::strftime(s, max, format, tm);
#endif
}

<commit_msg>Now call the strftime() function in the global namespace.<commit_after>// Module:  Log4CPLUS
// File:    strftime.cxx
// Created: 4/2003
// Author:  Tad E. Smith
//
//
// Copyright (C) Tad E. Smith  All rights reserved.
//
// This software is published under the terms of the Apache Software
// License version 1.1, a copy of which has been included with this
// distribution in the LICENSE.APL file.
//
// $Log: not supported by cvs2svn $
// Revision 1.1  2003/04/19 22:55:27  tcsmith
// Initial version.
//

#include <log4cplus/helpers/strftime.h>

#ifdef TM_IN_SYS_TIME
#include <sys/time.h>
#endif

using namespace log4cplus;

//////////////////////////////////////////////////////////////////////////////
// Global methods
//////////////////////////////////////////////////////////////////////////////

size_t
log4cplus::helpers::strftime(tchar* s, size_t max,
                             const tchar* format, const struct tm* tm)
{
#ifdef UNICODE
    return ::wcsftime(s, max, format, tm);
#else
    return ::strftime(s, max, format, tm);
#endif
}

<|endoftext|>


<commit_before>/*
Allocore Example: Simple World

Description:
This example demonstrates how to use the App class to create a 3D space with
audio and graphics rendering callbacks.

Author:
Lance Putnam, 6/2011, putnam.lance@gmail.com
*/

#include "alloutil/al_App.hpp"

using namespace al;

class MyApp : public App{
public:

	double phase;

	MyApp(): phase(0){}

	virtual void onSound(AudioIOData& io){
		while(io()){
			float in = io.in(0);

			float out1 = 0;
			float out2 = 0;

			io.out(0) = out1;
			io.out(1) = out2;
		}
	}

	virtual void onAnimate(double dt){
		// The phase will ramp from 0 to 1 over 1 second
		phase += dt;
		if(phase >= 1.) phase -= 1.;
	}

	virtual void onDraw(Graphics& g, const Viewpoint& v){

		// Note: we don't need to do all the normal graphics setup as this
		// is handled by the App's stereographic object. We can just draw
		// our geometry immediately!

		Mesh& m = g.mesh();

		m.reset();
		m.primitive(g.TRIANGLES);

		int N = addSphere(m, 1, 32, 32);

		for(int i=0; i<N; ++i){
			m.color(HSV(0.1, 0.5, al::fold(phase + i*0.5/N, 0.5)+0.5));
		}

		g.draw(m);
	}
};

MyApp app;

int main(){
	app.camera().near(0.1).far(25);
	app.nav().pos(0,0,4);
	app.nav().quat().fromAxisAngle(0, 0,0,1);

	// Initialize a single window
	// Anything in App::onDraw will be rendered
	app.initWindow(Window::Dim(600,400));

	// Initialize audio so that App::onSound is called
	app.initAudio(
		44100,		// sample rate, in Hz
		128,		// block size
		2,			// number of output channels to open
		1			// number of input channels to open
	);

	app.start();
	return 0;
}
<commit_msg>example update<commit_after>/*
Allocore Example: Simple App

Description:
This example demonstrates how to use the App class to create a 3D space with
audio and graphics rendering callbacks.

Author:
Lance Putnam, 6/2011, putnam.lance@gmail.com
*/

#include "alloutil/al_App.hpp"

using namespace al;

// We inherit from App to create our own custom application
class MyApp : public App{
public:

	double phase;

	// Ths constructor is where we initialize the application
	MyApp(): phase(0){
		// Configure our camera lens
		camera().near(0.1).far(25).fovy(45);

		// Set navigation position and orientation
		nav().pos(0,0,4);
		nav().quat().fromAxisAngle(0, 0,0,1);

		// Initialize a single window
		// Anything in App::onDraw will be rendered
		initWindow(Window::Dim(600,400));

		// Initialize audio so that App::onSound is called
		initAudio(
			44100,		// sample rate, in Hz
			128,		// block size
			2,			// number of output channels to open
			1			// number of input channels to open
		);
	}

	// This is the audio callback
	virtual void onSound(AudioIOData& io){

		// Things here occur at block rate...

		// This is the sample loop
		while(io()){
			//float in = io.in(0);

			float out1 = 0;
			float out2 = 0;

			io.out(0) = out1;
			io.out(1) = out2;
		}
	}

	// This is the application's (graphical) model update.
	// This is called once for each frame of graphics. Typically, you will
	// update your application's geometry, physics, etc. here.
	virtual void onAnimate(double dt){
		// The phase will ramp from 0 to 1 over 1 second. We will use it to
		// animate the color of a sphere.
		phase += dt;
		if(phase >= 1.) phase -= 1.;
	}

	// This is the application's view update.
	// This is called one or more times per frame, for each window, viewport,
	// and eye (for stereoscopic). Typically, this is where you send drawing
	// commands to the GPU.
	virtual void onDraw(Graphics& g, const Viewpoint& v){

		// Note: we don't need to do all the normal graphics setup as this
		// is handled by the App's stereographic object. We can just draw
		// our geometry immediately!

		Mesh& m = g.mesh();

		m.reset();
		m.primitive(g.TRIANGLES);

		int N = addSphere(m, 1, 32, 32);

		for(int i=0; i<N; ++i){
			m.color(HSV(0.1, 0.5, al::fold(phase + i*0.5/N, 0.5)+0.5));
		}

		g.draw(m);
	}

	// This is the application's key down controller.
	virtual void onKeyDown(const ViewpointWindow& w, const Keyboard& k){
		printf("Pressed the %c key.\n", k.key());
	}
};

MyApp app;

int main(){
	app.start();
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Morwenn
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <algorithm>
#include <cstddef>
#include <functional>
#include <iterator>
#include <type_traits>
#include <cpp-sort/sorter_facade.h>
#include <cpp-sort/utility/as_function.h>
#include <cpp-sort/utility/functional.h>
#include <cpp-sort/utility/size.h>

namespace detail
{
    template<
        typename ForwardIterator,
        typename StrictWeakOrdering,
        typename Projection
    >
    auto bubble_sort(ForwardIterator first, StrictWeakOrdering compare,
                     Projection projection, std::size_t size)
        -> void
    {
        if (size < 2) return;

        auto&& proj = cppsort::utility::as_function(projection);

        while (--size)
        {
            ForwardIterator current = first;
            ForwardIterator next = std::next(current);
            for (std::size_t i = 0 ; i < size ; ++i)
            {
                if (compare(proj(*next), proj(*current)))
                {
                    std::iter_swap(current, next);
                }
                ++next;
                ++current;
            }
        }
    }

    struct bubble_sorter_impl
    {
        // Pair of iterators overload
        template<
            typename ForwardIterator,
            typename StrictWeakOrdering = std::less<>,
            typename Projection = cppsort::utility::identity,
            typename = std::enable_if_t<cppsort::is_projection_iterator<
                Projection, ForwardIterator, StrictWeakOrdering
            >>
        >
        auto operator()(ForwardIterator first, ForwardIterator last,
                        StrictWeakOrdering compare={}, Projection projection={}) const
            -> void
        {
            static_assert(
                std::is_base_of<
                    std::forward_iterator_tag,
                    typename std::iterator_traits<ForwardIterator>::iterator_category
                >::value,
                "bubble_sorter requires at least forward iterators"
            );

            bubble_sort(first,
                        compare, projection,
                        std::distance(first, last));
        }

        // Iterable overload
        template<
            typename ForwardIterable,
            typename StrictWeakOrdering = std::less<>,
            typename Projection = cppsort::utility::identity,
            typename = std::enable_if_t<cppsort::is_projection<
                Projection, ForwardIterable, StrictWeakOrdering
            >>
        >
        auto operator()(ForwardIterable& iterable, StrictWeakOrdering compare={},
                        Projection projection={}) const
            -> void
        {
            static_assert(
                std::is_base_of<
                    std::forward_iterator_tag,
                    typename std::iterator_traits<decltype(std::begin(iterable))>::iterator_category
                >::value,
                "bubble_sorter requires at least forward iterators"
            );

            bubble_sort(std::begin(iterable),
                        compare, projection,
                        cppsort::utility::size(iterable));
        }

        // Sorter traits
        using iterator_category = std::forward_iterator_tag;
        using is_stable = std::true_type;
    };
}

struct bubble_sorter:
    cppsort::sorter_facade<detail::bubble_sorter_impl>
{};

#include <array>
#include <cassert>
#include <numeric>
#include <cpp-sort/sort.h>

int main()
{
    // Check that the bubble_sorter can sort any permutation
    // of an array of 8 values

    // Fill the collection in sorted order
    std::array<int, 8> collection;
    std::iota(std::begin(collection), std::end(collection), 0);

    // Projection to sort in descending order
    auto projection = [](int n) { return -n; };

    // For each possible permutation of collection
    do
    {
        auto to_sort = collection;
        // Bubble sort the collection
        cppsort::sort(to_sort, bubble_sorter{}, projection);
        // Check that it is indeed sorted
        assert(std::is_sorted(std::begin(to_sort), std::end(to_sort), std::greater<>{}));
    } while (std::next_permutation(std::begin(collection), std::end(collection)));
}
<commit_msg>Update example with new projection handling.<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015-2016 Morwenn
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
#include <algorithm>
#include <cstddef>
#include <functional>
#include <iterator>
#include <type_traits>
#include <cpp-sort/sorter_facade.h>
#include <cpp-sort/sorter_traits.h>
#include <cpp-sort/utility/size.h>

namespace detail
{
    template<
        typename ForwardIterator,
        typename StrictWeakOrdering
    >
    auto bubble_sort(ForwardIterator first, StrictWeakOrdering compare,
                     std::size_t size)
        -> void
    {
        if (size < 2) return;

        while (--size)
        {
            ForwardIterator current = first;
            ForwardIterator next = std::next(current);
            for (std::size_t i = 0 ; i < size ; ++i)
            {
                if (compare(*next, *current))
                {
                    std::iter_swap(current, next);
                }
                ++next;
                ++current;
            }
        }
    }

    struct bubble_sorter_impl
    {
        // Pair of iterators overload
        template<
            typename ForwardIterator,
            typename StrictWeakOrdering = std::less<>,
            typename = std::enable_if_t<not cppsort::is_projection_iterator<
                StrictWeakOrdering, ForwardIterator
            >>
        >
        auto operator()(ForwardIterator first, ForwardIterator last,
                        StrictWeakOrdering compare={}) const
            -> void
        {
            static_assert(
                std::is_base_of<
                    std::forward_iterator_tag,
                    typename std::iterator_traits<ForwardIterator>::iterator_category
                >::value,
                "bubble_sorter requires at least forward iterators"
            );

            bubble_sort(first, compare,
                        std::distance(first, last));
        }

        // Iterable overload
        template<
            typename ForwardIterable,
            typename StrictWeakOrdering = std::less<>,
            typename = std::enable_if_t<not cppsort::is_projection<
                StrictWeakOrdering, ForwardIterable
            >>
        >
        auto operator()(ForwardIterable& iterable, StrictWeakOrdering compare={}) const
            -> void
        {
            static_assert(
                std::is_base_of<
                    std::forward_iterator_tag,
                    typename std::iterator_traits<decltype(std::begin(iterable))>::iterator_category
                >::value,
                "bubble_sorter requires at least forward iterators"
            );

            bubble_sort(std::begin(iterable), compare,
                        cppsort::utility::size(iterable));
        }

        // Sorter traits
        using iterator_category = std::forward_iterator_tag;
        using is_stable = std::true_type;
    };
}

struct bubble_sorter:
    cppsort::sorter_facade<detail::bubble_sorter_impl>
{};

#include <array>
#include <cassert>
#include <numeric>
#include <cpp-sort/sort.h>

int main()
{
    // Check that the bubble_sorter can sort any permutation
    // of an array of 8 values

    // Fill the collection in sorted order
    std::array<int, 8> collection;
    std::iota(std::begin(collection), std::end(collection), 0);

    // Projection to sort in descending order
    auto projection = [](int n) { return -n; };

    // For each possible permutation of collection
    do
    {
        auto to_sort = collection;
        // Bubble sort the collection
        cppsort::sort(to_sort, bubble_sorter{}, projection);
        // Check that it is sorted in descending order
        assert(std::is_sorted(std::begin(to_sort), std::end(to_sort), std::greater<>{}));
    } while (std::next_permutation(std::begin(collection), std::end(collection)));
}
<|endoftext|>


<commit_before>#include "prutengine/Application.hpp"
#include "prutengine/deprecated/TestScene.hpp"
#include "prutengine/platform/OpenGL.hpp"
#include "prutengine/AssetManager.hpp"
#include "prutengine/math/Matrix4x4.hpp"
#include "prutengine/math/Utilities.hpp"
#include "prutengine/platform/Input.hpp"
#include "prutengine/exceptions/RenderingException.hpp"
#include "easylogging++.h"

using namespace PrutEngine;

std::shared_ptr<Application> Application::instance;

void Application::start(){
    this->currentScene = std::unique_ptr<AbstractScene>(new TestScene());
}

Application::Application(){
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CW);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
}

std::shared_ptr<Application> Application::getInstance(){
	if(instance == nullptr){
		instance = std::shared_ptr<Application>(new Application());
        instance->start();//Make sure the gameobjects in the application can use this pointer
	}
	return instance;
}

void Application::keyDown(unsigned short keyCode){
    if(keyCode == KeyCodes::ESCAPE_KEY){
        this->quit();
    }else{
        this->currentScene->keyDown(keyCode);
    }
}

void Application::loop(){
    clock_t timer;
    timer = clock();

    static const GLfloat background[] = { 0.0f, 0.25f, 0.0f, 1.0f };
    static const GLfloat depth = 1.0f;
    glViewport(0, 0, 600, 600);

    glClearBufferfv(GL_COLOR, 0, background);
    glClearBufferfv(GL_DEPTH, 0, &depth);

    GLenum error = glGetError();
    if(error != GL_NO_ERROR){
        Exceptions::RenderingException exception("Rendering error occured in the mainloop");
        std::string errorMsg;
        do{
            switch(error){
            case GL_INVALID_ENUM:
                errorMsg = "My first info log using default logger";
                break;
            case GL_INVALID_VALUE:
                errorMsg = "found invalid value \n";
                break;
            case GL_INVALID_OPERATION:
                errorMsg = "found invalid operation \n";
                break;
            case GL_OUT_OF_MEMORY:
                errorMsg = "Opengl experienced an out of memory exception \n";
                break;
            case GL_INVALID_FRAMEBUFFER_OPERATION:
                errorMsg =  "Invalid framebuffer operation \n";
                break;
            default:
                errorMsg = "Found an error with code " + std::to_string(error);
                break;
            }
         LOG(WARNING) << errorMsg;
         exception.addError(errorMsg);
        }while((error = glGetError()) != GL_NO_ERROR);
        throw exception;
    }

  /*  GLenum errors = GL_NO_ERROR;
    while((errors = glGetError()) != GL_NO_ERROR){
        switch(errors){
            case GL_INVALID_ENUM:
               // std::cout << "? \n";
                LOG(ERROR) << "My first info log using default logger";
                break;
            case GL_INVALID_VALUE:
                LOG(ERROR) << "found invalid value \n";
                break;
            case GL_INVALID_OPERATION:
                LOG(ERROR) <<"found invalid operation \n";
                break;
            case GL_OUT_OF_MEMORY:
                LOG(ERROR) << "Opengl experienced an out of memory exception \n";
                break;
            case GL_INVALID_FRAMEBUFFER_OPERATION:
                LOG(ERROR) << "Invalid framebuffer operation \n";
                break;
            default:
                LOG(ERROR) << "Found an error \n";
                break;
        }

    }*/

	currentScene->update(time_per_frame);

    this->time_per_frame = 0.00001f * (clock() - timer);

}
<commit_msg>Removed some legacy code<commit_after>#include "prutengine/Application.hpp"
#include "prutengine/deprecated/TestScene.hpp"
#include "prutengine/platform/OpenGL.hpp"
#include "prutengine/AssetManager.hpp"
#include "prutengine/math/Matrix4x4.hpp"
#include "prutengine/math/Utilities.hpp"
#include "prutengine/platform/Input.hpp"
#include "prutengine/exceptions/RenderingException.hpp"
#include "easylogging++.h"

using namespace PrutEngine;

std::shared_ptr<Application> Application::instance;

void Application::start(){
    this->currentScene = std::unique_ptr<AbstractScene>(new TestScene());
}

Application::Application(){
    glEnable(GL_CULL_FACE);
    glFrontFace(GL_CW);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
}

std::shared_ptr<Application> Application::getInstance(){
	if(instance == nullptr){
		instance = std::shared_ptr<Application>(new Application());
        instance->start();//Make sure the gameobjects in the application can use this pointer
	}
	return instance;
}

void Application::keyDown(unsigned short keyCode){
    if(keyCode == KeyCodes::ESCAPE_KEY){
        this->quit();
    }else{
        this->currentScene->keyDown(keyCode);
    }
}

void Application::loop(){
    clock_t timer;
    timer = clock();

    static const GLfloat background[] = { 0.0f, 0.25f, 0.0f, 1.0f };
    static const GLfloat depth = 1.0f;
    glViewport(0, 0, 600, 600);

    glClearBufferfv(GL_COLOR, 0, background);
    glClearBufferfv(GL_DEPTH, 0, &depth);

    GLenum error = glGetError();
    if(error != GL_NO_ERROR){
        Exceptions::RenderingException exception("Rendering error occured in the mainloop");
        std::string errorMsg;
        do{
            switch(error){
            case GL_INVALID_ENUM:
                errorMsg = "My first info log using default logger";
                break;
            case GL_INVALID_VALUE:
                errorMsg = "found invalid value \n";
                break;
            case GL_INVALID_OPERATION:
                errorMsg = "found invalid operation \n";
                break;
            case GL_OUT_OF_MEMORY:
                errorMsg = "Opengl experienced an out of memory exception \n";
                break;
            case GL_INVALID_FRAMEBUFFER_OPERATION:
                errorMsg =  "Invalid framebuffer operation \n";
                break;
            default:
                errorMsg = "Found an error with code " + std::to_string(error);
                break;
            }
         LOG(WARNING) << errorMsg;
         exception.addError(errorMsg);
        }while((error = glGetError()) != GL_NO_ERROR);
        throw exception;
    }

	currentScene->update(time_per_frame);

    this->time_per_frame = 0.00001f * (clock() - timer);

}
<|endoftext|>


<commit_before>#include <QString>
#include "module.h"
#include "kernel.h"
#include "ilwisobject.h"
#include "ilwisdata.h"
#include "domain.h"
#include "numericdomain.h"
#include "range.h"
#include "numericrange.h"
#include "itemrange.h"
#include "datadefinition.h"

using namespace Ilwis;

DataDefinition::DataDefinition() : _range(0)
{
}

DataDefinition::DataDefinition(const DataDefinition& def)
{
    domain(def.domain());
    if ( !def.range().isNull())
        _range.reset(def.range()->clone());
    else
        _range.reset(0);
}

DataDefinition::DataDefinition(const IDomain &dm, Range *rng)
{
    domain(dm);
    if ( rng)
        _range.reset(rng);
}

DataDefinition::~DataDefinition()
{
}

DataDefinition &DataDefinition::operator =(const DataDefinition &def1)
{
    domain(def1.domain());
    _range = def1.range();

    return *this;
}

Ilwis::PRange DataDefinition::range() const
{
    return _range;
}

void DataDefinition::range(Range* vr)
{
    _range = QSharedPointer<Range>(vr);
}

IDomain DataDefinition::domain() const
{
    return _domain;
}

void DataDefinition::domain(const IDomain &dom)
{
    _domain = dom;
    if ( _domain.isValid() && _domain->ilwisType() == itNUMERICDOMAIN) {
        INumericDomain nd = _domain.get<NumericDomain>();
        Range *r = nd->range<Range>()->clone();
        if ( r)
            _range.reset(r);
    }
}

bool DataDefinition::isValid() const
{
    return _domain.isValid();
}

DataDefinition DataDefinition::merge(const DataDefinition &def1, const DataDefinition &def2)
{
    IDomain dm;
    if ( !def1.isValid() && def2.isValid())
        return def2;
    if ( !def2.isValid() && def1.isValid())
        return def1;

    if ( def1.domain()->ilwisType() == itNUMERICDOMAIN && def1.domain()->ilwisType() == itNUMERICDOMAIN) {
        if ( def1.domain()->code() == "boolean" && def2.domain()->code() == "boolean") {
            return DataDefinition(def1);
        }
        SPNumericRange nr1 = def1.range().dynamicCast<NumericRange>();
        SPNumericRange nr2 = def1.range().dynamicCast<NumericRange>();
        NumericRange *nrNew = NumericRange::merge(nr1, nr2);
        if ( def1.domain()->name() == def1.domain()->name()) {
            return DataDefinition(def1.domain(), nrNew);
        } else {
            dm.prepare("value");
            return DataDefinition(dm, nrNew);
        }
    }
    if ( def1.domain()->ilwisType() == itITEMDOMAIN && def1.domain()->ilwisType() == itITEMDOMAIN) {
        SPItemRange nr1 = def1.range().dynamicCast<ItemRange>();
        SPItemRange nr2 = def1.range().dynamicCast<ItemRange>();
        ItemRange *nrNew = ItemRange::merge(nr1, nr2);
        if ( def1.domain()->name() == def1.domain()->name()) {
            return DataDefinition(def1.domain(), nrNew);
        } else {
            dm.prepare("value");
            return DataDefinition(dm, nrNew);
        }
    }
    return DataDefinition();
}

<commit_msg>range is now correctly set when a domain is attached to the definition<commit_after>#include <QString>
#include "module.h"
#include "kernel.h"
#include "ilwisobject.h"
#include "ilwisdata.h"
#include "domain.h"
#include "numericdomain.h"
#include "itemdomain.h"
#include "range.h"
#include "numericrange.h"
#include "domainitem.h"
#include "identifieritem.h"
#include "thematicitem.h"
#include "itemrange.h"
#include "datadefinition.h"

using namespace Ilwis;

DataDefinition::DataDefinition() : _range(0)
{
}

DataDefinition::DataDefinition(const DataDefinition& def)
{
    domain(def.domain());
    if ( !def.range().isNull())
        _range.reset(def.range()->clone());
    else
        _range.reset(0);
}

DataDefinition::DataDefinition(const IDomain &dm, Range *rng)
{
    domain(dm);
    if ( rng)
        _range.reset(rng);
}

DataDefinition::~DataDefinition()
{
}

DataDefinition &DataDefinition::operator =(const DataDefinition &def1)
{
    domain(def1.domain());
    _range = def1.range();

    return *this;
}

Ilwis::PRange DataDefinition::range() const
{
    return _range;
}

void DataDefinition::range(Range* vr)
{
    _range = QSharedPointer<Range>(vr);
}

IDomain DataDefinition::domain() const
{
    return _domain;
}

void DataDefinition::domain(const IDomain &dom)
{
    _domain = dom;
    if ( !_domain.isValid())
        return;

    Range *r = _domain->range<>();
    if ( r)
        _range.reset(r->clone());
}

bool DataDefinition::isValid() const
{
    return _domain.isValid();
}

DataDefinition DataDefinition::merge(const DataDefinition &def1, const DataDefinition &def2)
{
    IDomain dm;
    if ( !def1.isValid() && def2.isValid())
        return def2;
    if ( !def2.isValid() && def1.isValid())
        return def1;

    if ( def1.domain()->ilwisType() == itNUMERICDOMAIN && def1.domain()->ilwisType() == itNUMERICDOMAIN) {
        if ( def1.domain()->code() == "boolean" && def2.domain()->code() == "boolean") {
            return DataDefinition(def1);
        }
        SPNumericRange nr1 = def1.range().dynamicCast<NumericRange>();
        SPNumericRange nr2 = def1.range().dynamicCast<NumericRange>();
        NumericRange *nrNew = NumericRange::merge(nr1, nr2);
        if ( def1.domain()->name() == def1.domain()->name()) {
            return DataDefinition(def1.domain(), nrNew);
        } else {
            dm.prepare("value");
            return DataDefinition(dm, nrNew);
        }
    }
    if ( def1.domain()->ilwisType() == itITEMDOMAIN && def1.domain()->ilwisType() == itITEMDOMAIN) {
        SPItemRange nr1 = def1.range().dynamicCast<ItemRange>();
        SPItemRange nr2 = def1.range().dynamicCast<ItemRange>();
        ItemRange *nrNew = ItemRange::merge(nr1, nr2);
        if ( def1.domain()->name() == def1.domain()->name()) {
            return DataDefinition(def1.domain(), nrNew);
        } else {
            dm.prepare("value");
            return DataDefinition(dm, nrNew);
        }
    }
    return DataDefinition();
}

<|endoftext|>


<commit_before>#include "log.h"
#include "config.h"
#include <sys/time.h>
#include <stdarg.h>
#include "lock.h"

//#define DISABLE_LOGGING

using namespace std;

Log *Log::_singleton;

Log::Log(UInt32 coreCount)
   : _coreCount(coreCount)
{
   char filename[256];
   _files = new FILE* [2 * _coreCount + 1];
   for (UInt32 i = 0; i < _coreCount; i++)
   {
      sprintf(filename, "output_files/app_%u", i);
      _files[i] = fopen(filename, "w");
      assert(_files[i] != NULL);
   }
   for (UInt32 i = _coreCount; i < 2 * _coreCount; i++)
   {
      sprintf(filename, "output_files/sim_%u", i-_coreCount);
      _files[i] = fopen(filename, "w");
      assert(_files[i] != NULL);
   }
   _files[_coreCount * 2] = fopen("output_files/system", "w");
   assert(_files[_coreCount * 2]);

   _locks = new Lock* [2 * _coreCount + 1];
   for (UInt32 i = 0; i < 2 * _coreCount + 1; i++)
   {
      _locks[i] = Lock::create();
   }

   g_config->getDisabledLogModules(_disabledModules);

   assert(_singleton == NULL);
   _singleton = this;
}

Log::~Log()
{
   _singleton = NULL;

   for (UInt32 i = 0; i < 2 * _coreCount + 1; i++)
   {
      fclose(_files[i]);
      delete _locks[i];
   }
   delete [] _files;
   delete [] _locks;
}

Log* Log::getSingleton()
{
   assert(_singleton);
   return _singleton;
}

Boolean Log::isEnabled(const char* module)
{
#ifdef DISABLE_LOGGING
   return false;
#endif
   return _disabledModules.find(module) == _disabledModules.end();
}

UInt64 Log::getTimestamp()
{
   timeval t;
   gettimeofday(&t, NULL);
   return (((UInt64)t.tv_sec) * 1000000 + t.tv_usec);
}

// FIXME: See note below.
class Chip;
extern Chip* g_chip;
SInt32 chipRank(SInt32 *);

void Log::log(UInt32 rank, const char *module, const char *format, ...)
{
#ifdef DISABLE_LOGGING
   return;
#endif

   UInt32 fileRank;
   if (rank == (UInt32)-1)
      fileRank = 2 * _coreCount;
   else
   {
      // FIXME: This is an ugly hack. Net/shared mem threads do not have
      // a rank, so we can use chipRank to discover which thread we are
      // on.

      if (g_chip == NULL)
      {
         fileRank = rank + _coreCount;
      }
      else
      {
         SInt32 myChipRank;
         chipRank(&myChipRank);
         if (myChipRank == -1)
            fileRank = rank + _coreCount;
         else
            fileRank = rank;
      }
   }

   if (!isEnabled(module))
      return;

   _locks[fileRank]->acquire();

   fprintf(_files[fileRank], "%llu [%i] [%s] ", getTimestamp(), (rank > _coreCount ? -1 : (SInt32)rank), module);

   va_list args;
   va_start(args, format);
   vfprintf(_files[fileRank], format, args);
   va_end(args);

   fprintf(_files[fileRank], "\n");

   _locks[fileRank]->release();
}

void Log::notifyWarning()
{
   if (_state == None)
   {
      fprintf(stderr, "LOG : Check logs -- there is a warning!\n");
      _state = Warning;
   }
}

void Log::notifyError()
{
   if (_state == None || _state == Warning)
   {
      fprintf(stderr, "LOG : Check logs -- there is an ERROR!\n");
      _state = Error;
   }
}

<commit_msg>[misc/log] Flush files after each write.<commit_after>#include "log.h"
#include "config.h"
#include <sys/time.h>
#include <stdarg.h>
#include "lock.h"

//#define DISABLE_LOGGING

using namespace std;

Log *Log::_singleton;

Log::Log(UInt32 coreCount)
   : _coreCount(coreCount)
{
   char filename[256];
   _files = new FILE* [2 * _coreCount + 1];
   for (UInt32 i = 0; i < _coreCount; i++)
   {
      sprintf(filename, "output_files/app_%u", i);
      _files[i] = fopen(filename, "w");
      assert(_files[i] != NULL);
   }
   for (UInt32 i = _coreCount; i < 2 * _coreCount; i++)
   {
      sprintf(filename, "output_files/sim_%u", i-_coreCount);
      _files[i] = fopen(filename, "w");
      assert(_files[i] != NULL);
   }
   _files[_coreCount * 2] = fopen("output_files/system", "w");
   assert(_files[_coreCount * 2]);

   _locks = new Lock* [2 * _coreCount + 1];
   for (UInt32 i = 0; i < 2 * _coreCount + 1; i++)
   {
      _locks[i] = Lock::create();
   }

   g_config->getDisabledLogModules(_disabledModules);

   assert(_singleton == NULL);
   _singleton = this;
}

Log::~Log()
{
   _singleton = NULL;

   for (UInt32 i = 0; i < 2 * _coreCount + 1; i++)
   {
      fclose(_files[i]);
      delete _locks[i];
   }
   delete [] _files;
   delete [] _locks;
}

Log* Log::getSingleton()
{
   assert(_singleton);
   return _singleton;
}

Boolean Log::isEnabled(const char* module)
{
#ifdef DISABLE_LOGGING
   return false;
#endif
   return _disabledModules.find(module) == _disabledModules.end();
}

UInt64 Log::getTimestamp()
{
   timeval t;
   gettimeofday(&t, NULL);
   return (((UInt64)t.tv_sec) * 1000000 + t.tv_usec);
}

// FIXME: See note below.
class Chip;
extern Chip* g_chip;
SInt32 chipRank(SInt32 *);

void Log::log(UInt32 rank, const char *module, const char *format, ...)
{
#ifdef DISABLE_LOGGING
   return;
#endif

   UInt32 fileRank;
   if (rank == (UInt32)-1)
      fileRank = 2 * _coreCount;
   else
   {
      // FIXME: This is an ugly hack. Net/shared mem threads do not have
      // a rank, so we can use chipRank to discover which thread we are
      // on.

      if (g_chip == NULL)
      {
         fileRank = rank + _coreCount;
      }
      else
      {
         SInt32 myChipRank;
         chipRank(&myChipRank);
         if (myChipRank == -1)
            fileRank = rank + _coreCount;
         else
            fileRank = rank;
      }
   }

   if (!isEnabled(module))
      return;

   _locks[fileRank]->acquire();

   fprintf(_files[fileRank], "%llu [%i] [%s] ", getTimestamp(), (rank > _coreCount ? -1 : (SInt32)rank), module);

   va_list args;
   va_start(args, format);
   vfprintf(_files[fileRank], format, args);
   va_end(args);

   fprintf(_files[fileRank], "\n");

   fflush(_files[fileRank]);

   _locks[fileRank]->release();
}

void Log::notifyWarning()
{
   if (_state == None)
   {
      fprintf(stderr, "LOG : Check logs -- there is a warning!\n");
      _state = Warning;
   }
}

void Log::notifyError()
{
   if (_state == None || _state == Warning)
   {
      fprintf(stderr, "LOG : Check logs -- there is an ERROR!\n");
      _state = Error;
   }
}

<|endoftext|>