<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// For information about interceptions as a whole see
// http://wiki/Main/ChromeSandboxInterceptionDesign

#include <set>

#include "sandbox/src/interception.h"

#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "sandbox/src/interception_internal.h"
#include "sandbox/src/sandbox.h"
#include "sandbox/src/sandbox_utils.h"
#include "sandbox/src/service_resolver.h"
#include "sandbox/src/target_interceptions.h"
#include "sandbox/src/target_process.h"
#include "sandbox/src/wow64.h"

namespace {

const char kMapViewOfSectionName[] = "NtMapViewOfSection";
const char kUnmapViewOfSectionName[] = "NtUnmapViewOfSection";

}  // namespace

namespace sandbox {

SANDBOX_INTERCEPT SharedMemory* g_interceptions;

InterceptionManager::InterceptionManager(TargetProcess* child_process,
                                         bool relaxed)
    : child_(child_process), names_used_(false), relaxed_(relaxed) {
  child_->AddRef();
}
InterceptionManager::~InterceptionManager() {
  child_->Release();
}

bool InterceptionManager::AddToPatchedFunctions(
    const wchar_t* dll_name, const char* function_name,
    InterceptionType interception_type, const void* replacement_code_address) {
  InterceptionData function;
  function.type = interception_type;
  function.dll = dll_name;
  function.function = function_name;
  function.interceptor_address = replacement_code_address;

  interceptions_.push_back(function);

  return true;
}

bool InterceptionManager::AddToPatchedFunctions(
    const wchar_t* dll_name, const char* function_name,
    InterceptionType interception_type, const char* replacement_function_name) {
  InterceptionData function;
  function.type = interception_type;
  function.dll = dll_name;
  function.function = function_name;
  function.interceptor = replacement_function_name;
  function.interceptor_address = NULL;

  interceptions_.push_back(function);
  names_used_ = true;

  return true;
}

bool InterceptionManager::InitializeInterceptions() {
  if (interceptions_.empty())
    return true;  // Nothing to do here

  size_t buffer_bytes = GetBufferSize();
  scoped_ptr<char> local_buffer(new char[buffer_bytes]);

  if (!SetupConfigBuffer(local_buffer.get(), buffer_bytes))
    return false;

  void* remote_buffer;
  if (!CopyDataToChild(local_buffer.get(), buffer_bytes, &remote_buffer))
    return false;

  bool hot_patch_needed = (0 != buffer_bytes);
  if (!PatchNtdll(hot_patch_needed))
    return false;

  g_interceptions = reinterpret_cast<SharedMemory*>(remote_buffer);
  child_->TransferVariable("sandbox::g_interceptions", &g_interceptions,
                           sizeof(g_interceptions));
  return true;
}

size_t InterceptionManager::GetBufferSize() const {
  std::set<std::wstring> dlls;
  size_t buffer_bytes = 0;

  std::list<InterceptionData>::const_iterator it = interceptions_.begin();
  for (; it != interceptions_.end(); ++it) {
    // skip interceptions that are performed from the parent
    if (!IsInterceptionPerformedByChild(*it))
      continue;

    if (!dlls.count(it->dll)) {
      // NULL terminate the dll name on the structure
      size_t dll_name_bytes = (it->dll.size() + 1) * sizeof(wchar_t);

      // include the dll related size
      buffer_bytes += RoundUpToMultiple(offsetof(DllPatchInfo, dll_name) +
                                            dll_name_bytes, sizeof(size_t));
      dlls.insert(it->dll);
    }

    // we have to NULL terminate the strings on the structure
    size_t strings_chars = it->function.size() + it->interceptor.size() + 2;

    // a new FunctionInfo is required per function
    size_t record_bytes = offsetof(FunctionInfo, function) + strings_chars;
    record_bytes = RoundUpToMultiple(record_bytes, sizeof(size_t));
    buffer_bytes += record_bytes;
  }

  if (0 != buffer_bytes)
    // add the part of SharedMemory that we have not counted yet
    buffer_bytes += offsetof(SharedMemory, dll_list);

  return buffer_bytes;
}

// Basically, walk the list of interceptions moving them to the config buffer,
// but keeping together all interceptions that belong to the same dll.
// The config buffer is a local buffer, not the one allocated on the child.
bool InterceptionManager::SetupConfigBuffer(void* buffer, size_t buffer_bytes) {
  if (0 == buffer_bytes)
    return true;

  DCHECK(buffer_bytes > sizeof(SharedMemory));

  SharedMemory* shared_memory = reinterpret_cast<SharedMemory*>(buffer);
  DllPatchInfo* dll_info = shared_memory->dll_list;
  int num_dlls = 0;

  shared_memory->interceptor_base = names_used_ ? child_->MainModule() : NULL;

  buffer_bytes -= offsetof(SharedMemory, dll_list);
  buffer = dll_info;

  std::list<InterceptionData>::iterator it = interceptions_.begin();
  for (; it != interceptions_.end();) {
    // skip interceptions that are performed from the parent
    if (!IsInterceptionPerformedByChild(*it)) {
      ++it;
      continue;
    }

    const std::wstring dll = it->dll;
    if (!SetupDllInfo(*it, &buffer, &buffer_bytes))
      return false;

    // walk the interceptions from this point, saving the ones that are
    // performed on this dll, and removing the entry from the list.
    // advance the iterator before removing the element from the list
    std::list<InterceptionData>::iterator rest = it;
    for (; rest != interceptions_.end();) {
      if (rest->dll == dll) {
        if (!SetupInterceptionInfo(*rest, &buffer, &buffer_bytes, dll_info))
          return false;
        if (it == rest)
          ++it;
        rest = interceptions_.erase(rest);
      } else {
        ++rest;
      }
    }
    dll_info = reinterpret_cast<DllPatchInfo*>(buffer);
    ++num_dlls;
  }

  shared_memory->num_intercepted_dlls = num_dlls;
  return true;
}

// Fills up just the part that depends on the dll, not the info that depends on
// the actual interception.
bool InterceptionManager::SetupDllInfo(const InterceptionData& data,
                                       void** buffer,
                                       size_t* buffer_bytes) const {
  DCHECK(buffer_bytes);
  DCHECK(buffer);
  DCHECK(*buffer);

  DllPatchInfo* dll_info = reinterpret_cast<DllPatchInfo*>(*buffer);

  // the strings have to be zero terminated
  size_t required = offsetof(DllPatchInfo, dll_name) +
                    (data.dll.size() + 1) * sizeof(wchar_t);
  required = RoundUpToMultiple(required, sizeof(size_t));
  if (*buffer_bytes < required)
    return false;

  *buffer_bytes -= required;
  *buffer = reinterpret_cast<char*>(*buffer) + required;

  // set up the dll info to be what we know about it at this time
  dll_info->record_bytes = required;
  dll_info->offset_to_functions = required;
  dll_info->num_functions = 0;
  data.dll._Copy_s(dll_info->dll_name, data.dll.size(), data.dll.size());
  dll_info->dll_name[data.dll.size()] = L'\0';

  return true;
}

bool InterceptionManager::SetupInterceptionInfo(const InterceptionData& data,
                                                void** buffer,
                                                size_t* buffer_bytes,
                                                DllPatchInfo* dll_info) const {
  DCHECK(buffer_bytes);
  DCHECK(buffer);
  DCHECK(*buffer);

  FunctionInfo* function = reinterpret_cast<FunctionInfo*>(*buffer);

  size_t name_bytes = data.function.size();
  size_t interceptor_bytes = data.interceptor.size();

  // the strings at the end of the structure are zero terminated
  size_t required = offsetof(FunctionInfo, function) +
                    name_bytes + interceptor_bytes + 2;
  required = RoundUpToMultiple(required, sizeof(size_t));
  if (*buffer_bytes < required)
    return false;

  // update the caller's values
  *buffer_bytes -= required;
  *buffer = reinterpret_cast<char*>(*buffer) + required;

  function->record_bytes = required;
  function->type = data.type;
  function->interceptor_address = data.interceptor_address;
  char* names = function->function;

  data.function._Copy_s(names, name_bytes, name_bytes);
  names += name_bytes;
  *names++ = '\0';

  // interceptor follows the function_name
  data.interceptor._Copy_s(names, interceptor_bytes, interceptor_bytes);
  names += interceptor_bytes;
  *names++ = '\0';

  // update the dll table
  dll_info->num_functions++;
  dll_info->record_bytes += required;

  return true;
}

bool InterceptionManager::CopyDataToChild(const void* local_buffer,
                                          size_t buffer_bytes,
                                          void** remote_buffer) const {
  DCHECK(NULL != remote_buffer);
  if (0 == buffer_bytes) {
    *remote_buffer = NULL;
    return true;
  }

  HANDLE child = child_->Process();

  // Allocate memory on the target process without specifying the address
  void* remote_data = ::VirtualAllocEx(child, NULL, buffer_bytes,
                                       MEM_COMMIT, PAGE_READWRITE);
  if (NULL == remote_data)
    return false;

  SIZE_T bytes_written;
  BOOL success = ::WriteProcessMemory(child, remote_data, local_buffer,
                                      buffer_bytes, &bytes_written);
  if (FALSE == success || bytes_written != buffer_bytes) {
    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
    return false;
  }

  *remote_buffer = remote_data;

  return true;
}

// Only return true if the child should be able to perform this interception.
bool InterceptionManager::IsInterceptionPerformedByChild(
    const InterceptionData& data) const {
  if (INTERCEPTION_INVALID == data.type)
    return false;

  if (INTERCEPTION_SERVICE_CALL == data.type)
    return false;

  if (data.type >= INTERCEPTION_LAST)
    return false;

  std::wstring ntdll(kNtdllName);
  if (ntdll == data.dll)
    return false;  // ntdll has to be intercepted from the parent

  return true;
}

bool InterceptionManager::PatchNtdll(bool hot_patch_needed) {
  // Maybe there is nothing to do
  if (!hot_patch_needed && interceptions_.empty())
    return true;

  if (hot_patch_needed) {
#if SANDBOX_EXPORTS
    AddToPatchedFunctions(kNtdllName, kMapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL,
                          "_TargetNtMapViewOfSection@44");
    AddToPatchedFunctions(kNtdllName, kUnmapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL,
                          "_TargetNtUnmapViewOfSection@12");
#else
    AddToPatchedFunctions(kNtdllName, kMapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL, &TargetNtMapViewOfSection);
    AddToPatchedFunctions(kNtdllName, kUnmapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL,
                          &TargetNtUnmapViewOfSection);
#endif
  }

  size_t thunk_bytes = interceptions_.size() * sizeof(ThunkData) +
                       sizeof(DllInterceptionData);

  // Allocate memory on the child, without specifying the desired address
  HANDLE child = child_->Process();
  DllInterceptionData* thunks = reinterpret_cast<DllInterceptionData*>(
                                    ::VirtualAllocEx(child, NULL, thunk_bytes,
                                                     MEM_COMMIT,
                                                     PAGE_EXECUTE_READWRITE));

  DllInterceptionData dll_data;
  dll_data.data_bytes = thunk_bytes;
  dll_data.num_thunks = 0;
  dll_data.used_bytes = offsetof(DllInterceptionData, thunks);

  // this should write all the individual thunks to the child's memory
  if (!PatchClientFunctions(thunks, thunk_bytes, &dll_data))
    return false;

  // and now write the first part of the table to the child's memory
  DWORD written;
  bool ok = FALSE != ::WriteProcessMemory(child, thunks, &dll_data,
                                          offsetof(DllInterceptionData, thunks),
                                          &written);

  if (!ok || (offsetof(DllInterceptionData, thunks) != written))
    return false;

  // Attempt to protect all the thunks, but ignore failure
  DWORD old_protection;
  ::VirtualProtectEx(child, thunks, thunk_bytes,
                     PAGE_EXECUTE_READ, &old_protection);

  return true;
}

bool InterceptionManager::PatchClientFunctions(DllInterceptionData* thunks,
                                               size_t thunk_bytes,
                                               DllInterceptionData* dll_data) {
  DCHECK(NULL != thunks);
  DCHECK(NULL != dll_data);

  HMODULE ntdll_base = ::GetModuleHandle(kNtdllName);
  if (!ntdll_base)
    return false;

  // Bypass purify's interception.
  wchar_t* loader_get = reinterpret_cast<wchar_t*>(
                            ::GetProcAddress(ntdll_base, "LdrGetDllHandle"));
  if (loader_get) {
    if (!GetModuleHandleHelper(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
                                   GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                               loader_get, &ntdll_base))
      return false;
  }

  Wow64 WowHelper(child_, ntdll_base);
  if (!WowHelper.WaitForNtdll(INFINITE))
    return false;

  char* interceptor_base = NULL;

#if SANDBOX_EXPORTS
  interceptor_base = reinterpret_cast<char*>(child_->MainModule());
  HMODULE local_interceptor = ::LoadLibrary(child_->Name());
#endif

  ServiceResolverThunk* thunk;
  if (WowHelper.IsWow64())
    thunk = new Wow64ResolverThunk(child_->Process(), relaxed_);
  else if (!IsXPSP2OrLater())
    thunk = new Win2kResolverThunk(child_->Process(), relaxed_);
  else
    thunk = new ServiceResolverThunk(child_->Process(), relaxed_);

  std::list<InterceptionData>::iterator it = interceptions_.begin();
  for (; it != interceptions_.end(); ++it) {
    const std::wstring ntdll(kNtdllName);
    if (it->dll != ntdll)
      break;

    if (INTERCEPTION_SERVICE_CALL != it->type)
      break;

#if SANDBOX_EXPORTS
    // We may be trying to patch by function name.
    if (NULL == it->interceptor_address) {
      const char* address;
      NTSTATUS ret = thunk->ResolveInterceptor(local_interceptor,
                                               it->interceptor.c_str(),
                                               reinterpret_cast<const void**>(
                                               &address));
      if (!NT_SUCCESS(ret))
        break;

      // Translate the local address to an address on the child.
      it->interceptor_address = interceptor_base + (address -
                                    reinterpret_cast<char*>(local_interceptor));
    }
#endif
    NTSTATUS ret = thunk->Setup(ntdll_base,
                                interceptor_base,
                                it->function.c_str(),
                                it->interceptor.c_str(),
                                it->interceptor_address,
                                &thunks->thunks[dll_data->num_thunks],
                                thunk_bytes - dll_data->used_bytes,
                                NULL);
    if (!NT_SUCCESS(ret))
      break;

    dll_data->num_thunks++;
    dll_data->used_bytes += sizeof(ThunkData);
  }

  delete(thunk);

#if SANDBOX_EXPORTS
  if (NULL != local_interceptor)
    ::FreeLibrary(local_interceptor);
#endif

  if (it != interceptions_.end())
    return false;

  return true;
}

}  // namespace sandbox

<commit_msg>For some reasons the linker excludes 2 of our hooks when linking in SANDBOX_EXPORTS mode. Add pragmas to be sure these hooks are included.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// For information about interceptions as a whole see
// http://wiki/Main/ChromeSandboxInterceptionDesign

#include <set>

#include "sandbox/src/interception.h"

#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "sandbox/src/interception_internal.h"
#include "sandbox/src/sandbox.h"
#include "sandbox/src/sandbox_utils.h"
#include "sandbox/src/service_resolver.h"
#include "sandbox/src/target_interceptions.h"
#include "sandbox/src/target_process.h"
#include "sandbox/src/wow64.h"

namespace {

const char kMapViewOfSectionName[] = "NtMapViewOfSection";
const char kUnmapViewOfSectionName[] = "NtUnmapViewOfSection";

}  // namespace

namespace sandbox {

SANDBOX_INTERCEPT SharedMemory* g_interceptions;

InterceptionManager::InterceptionManager(TargetProcess* child_process,
                                         bool relaxed)
    : child_(child_process), names_used_(false), relaxed_(relaxed) {
  child_->AddRef();
}
InterceptionManager::~InterceptionManager() {
  child_->Release();
}

bool InterceptionManager::AddToPatchedFunctions(
    const wchar_t* dll_name, const char* function_name,
    InterceptionType interception_type, const void* replacement_code_address) {
  InterceptionData function;
  function.type = interception_type;
  function.dll = dll_name;
  function.function = function_name;
  function.interceptor_address = replacement_code_address;

  interceptions_.push_back(function);

  return true;
}

bool InterceptionManager::AddToPatchedFunctions(
    const wchar_t* dll_name, const char* function_name,
    InterceptionType interception_type, const char* replacement_function_name) {
  InterceptionData function;
  function.type = interception_type;
  function.dll = dll_name;
  function.function = function_name;
  function.interceptor = replacement_function_name;
  function.interceptor_address = NULL;

  interceptions_.push_back(function);
  names_used_ = true;

  return true;
}

bool InterceptionManager::InitializeInterceptions() {
  if (interceptions_.empty())
    return true;  // Nothing to do here

  size_t buffer_bytes = GetBufferSize();
  scoped_ptr<char> local_buffer(new char[buffer_bytes]);

  if (!SetupConfigBuffer(local_buffer.get(), buffer_bytes))
    return false;

  void* remote_buffer;
  if (!CopyDataToChild(local_buffer.get(), buffer_bytes, &remote_buffer))
    return false;

  bool hot_patch_needed = (0 != buffer_bytes);
  if (!PatchNtdll(hot_patch_needed))
    return false;

  g_interceptions = reinterpret_cast<SharedMemory*>(remote_buffer);
  child_->TransferVariable("sandbox::g_interceptions", &g_interceptions,
                           sizeof(g_interceptions));
  return true;
}

size_t InterceptionManager::GetBufferSize() const {
  std::set<std::wstring> dlls;
  size_t buffer_bytes = 0;

  std::list<InterceptionData>::const_iterator it = interceptions_.begin();
  for (; it != interceptions_.end(); ++it) {
    // skip interceptions that are performed from the parent
    if (!IsInterceptionPerformedByChild(*it))
      continue;

    if (!dlls.count(it->dll)) {
      // NULL terminate the dll name on the structure
      size_t dll_name_bytes = (it->dll.size() + 1) * sizeof(wchar_t);

      // include the dll related size
      buffer_bytes += RoundUpToMultiple(offsetof(DllPatchInfo, dll_name) +
                                            dll_name_bytes, sizeof(size_t));
      dlls.insert(it->dll);
    }

    // we have to NULL terminate the strings on the structure
    size_t strings_chars = it->function.size() + it->interceptor.size() + 2;

    // a new FunctionInfo is required per function
    size_t record_bytes = offsetof(FunctionInfo, function) + strings_chars;
    record_bytes = RoundUpToMultiple(record_bytes, sizeof(size_t));
    buffer_bytes += record_bytes;
  }

  if (0 != buffer_bytes)
    // add the part of SharedMemory that we have not counted yet
    buffer_bytes += offsetof(SharedMemory, dll_list);

  return buffer_bytes;
}

// Basically, walk the list of interceptions moving them to the config buffer,
// but keeping together all interceptions that belong to the same dll.
// The config buffer is a local buffer, not the one allocated on the child.
bool InterceptionManager::SetupConfigBuffer(void* buffer, size_t buffer_bytes) {
  if (0 == buffer_bytes)
    return true;

  DCHECK(buffer_bytes > sizeof(SharedMemory));

  SharedMemory* shared_memory = reinterpret_cast<SharedMemory*>(buffer);
  DllPatchInfo* dll_info = shared_memory->dll_list;
  int num_dlls = 0;

  shared_memory->interceptor_base = names_used_ ? child_->MainModule() : NULL;

  buffer_bytes -= offsetof(SharedMemory, dll_list);
  buffer = dll_info;

  std::list<InterceptionData>::iterator it = interceptions_.begin();
  for (; it != interceptions_.end();) {
    // skip interceptions that are performed from the parent
    if (!IsInterceptionPerformedByChild(*it)) {
      ++it;
      continue;
    }

    const std::wstring dll = it->dll;
    if (!SetupDllInfo(*it, &buffer, &buffer_bytes))
      return false;

    // walk the interceptions from this point, saving the ones that are
    // performed on this dll, and removing the entry from the list.
    // advance the iterator before removing the element from the list
    std::list<InterceptionData>::iterator rest = it;
    for (; rest != interceptions_.end();) {
      if (rest->dll == dll) {
        if (!SetupInterceptionInfo(*rest, &buffer, &buffer_bytes, dll_info))
          return false;
        if (it == rest)
          ++it;
        rest = interceptions_.erase(rest);
      } else {
        ++rest;
      }
    }
    dll_info = reinterpret_cast<DllPatchInfo*>(buffer);
    ++num_dlls;
  }

  shared_memory->num_intercepted_dlls = num_dlls;
  return true;
}

// Fills up just the part that depends on the dll, not the info that depends on
// the actual interception.
bool InterceptionManager::SetupDllInfo(const InterceptionData& data,
                                       void** buffer,
                                       size_t* buffer_bytes) const {
  DCHECK(buffer_bytes);
  DCHECK(buffer);
  DCHECK(*buffer);

  DllPatchInfo* dll_info = reinterpret_cast<DllPatchInfo*>(*buffer);

  // the strings have to be zero terminated
  size_t required = offsetof(DllPatchInfo, dll_name) +
                    (data.dll.size() + 1) * sizeof(wchar_t);
  required = RoundUpToMultiple(required, sizeof(size_t));
  if (*buffer_bytes < required)
    return false;

  *buffer_bytes -= required;
  *buffer = reinterpret_cast<char*>(*buffer) + required;

  // set up the dll info to be what we know about it at this time
  dll_info->record_bytes = required;
  dll_info->offset_to_functions = required;
  dll_info->num_functions = 0;
  data.dll._Copy_s(dll_info->dll_name, data.dll.size(), data.dll.size());
  dll_info->dll_name[data.dll.size()] = L'\0';

  return true;
}

bool InterceptionManager::SetupInterceptionInfo(const InterceptionData& data,
                                                void** buffer,
                                                size_t* buffer_bytes,
                                                DllPatchInfo* dll_info) const {
  DCHECK(buffer_bytes);
  DCHECK(buffer);
  DCHECK(*buffer);

  FunctionInfo* function = reinterpret_cast<FunctionInfo*>(*buffer);

  size_t name_bytes = data.function.size();
  size_t interceptor_bytes = data.interceptor.size();

  // the strings at the end of the structure are zero terminated
  size_t required = offsetof(FunctionInfo, function) +
                    name_bytes + interceptor_bytes + 2;
  required = RoundUpToMultiple(required, sizeof(size_t));
  if (*buffer_bytes < required)
    return false;

  // update the caller's values
  *buffer_bytes -= required;
  *buffer = reinterpret_cast<char*>(*buffer) + required;

  function->record_bytes = required;
  function->type = data.type;
  function->interceptor_address = data.interceptor_address;
  char* names = function->function;

  data.function._Copy_s(names, name_bytes, name_bytes);
  names += name_bytes;
  *names++ = '\0';

  // interceptor follows the function_name
  data.interceptor._Copy_s(names, interceptor_bytes, interceptor_bytes);
  names += interceptor_bytes;
  *names++ = '\0';

  // update the dll table
  dll_info->num_functions++;
  dll_info->record_bytes += required;

  return true;
}

bool InterceptionManager::CopyDataToChild(const void* local_buffer,
                                          size_t buffer_bytes,
                                          void** remote_buffer) const {
  DCHECK(NULL != remote_buffer);
  if (0 == buffer_bytes) {
    *remote_buffer = NULL;
    return true;
  }

  HANDLE child = child_->Process();

  // Allocate memory on the target process without specifying the address
  void* remote_data = ::VirtualAllocEx(child, NULL, buffer_bytes,
                                       MEM_COMMIT, PAGE_READWRITE);
  if (NULL == remote_data)
    return false;

  SIZE_T bytes_written;
  BOOL success = ::WriteProcessMemory(child, remote_data, local_buffer,
                                      buffer_bytes, &bytes_written);
  if (FALSE == success || bytes_written != buffer_bytes) {
    ::VirtualFreeEx(child, remote_data, 0, MEM_RELEASE);
    return false;
  }

  *remote_buffer = remote_data;

  return true;
}

// Only return true if the child should be able to perform this interception.
bool InterceptionManager::IsInterceptionPerformedByChild(
    const InterceptionData& data) const {
  if (INTERCEPTION_INVALID == data.type)
    return false;

  if (INTERCEPTION_SERVICE_CALL == data.type)
    return false;

  if (data.type >= INTERCEPTION_LAST)
    return false;

  std::wstring ntdll(kNtdllName);
  if (ntdll == data.dll)
    return false;  // ntdll has to be intercepted from the parent

  return true;
}

bool InterceptionManager::PatchNtdll(bool hot_patch_needed) {
  // Maybe there is nothing to do
  if (!hot_patch_needed && interceptions_.empty())
    return true;

  if (hot_patch_needed) {
#if SANDBOX_EXPORTS
    // Make sure the functions are not excluded by the linker.
    #pragma comment(linker, "/include:_TargetNtMapViewOfSection@44")
    #pragma comment(linker, "/include:_TargetNtUnmapViewOfSection@12")

    AddToPatchedFunctions(kNtdllName, kMapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL,
                          "_TargetNtMapViewOfSection@44");
    AddToPatchedFunctions(kNtdllName, kUnmapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL,
                          "_TargetNtUnmapViewOfSection@12");
#else
    AddToPatchedFunctions(kNtdllName, kMapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL, &TargetNtMapViewOfSection);
    AddToPatchedFunctions(kNtdllName, kUnmapViewOfSectionName,
                          INTERCEPTION_SERVICE_CALL,
                          &TargetNtUnmapViewOfSection);
#endif
  }

  size_t thunk_bytes = interceptions_.size() * sizeof(ThunkData) +
                       sizeof(DllInterceptionData);

  // Allocate memory on the child, without specifying the desired address
  HANDLE child = child_->Process();
  DllInterceptionData* thunks = reinterpret_cast<DllInterceptionData*>(
                                    ::VirtualAllocEx(child, NULL, thunk_bytes,
                                                     MEM_COMMIT,
                                                     PAGE_EXECUTE_READWRITE));

  DllInterceptionData dll_data;
  dll_data.data_bytes = thunk_bytes;
  dll_data.num_thunks = 0;
  dll_data.used_bytes = offsetof(DllInterceptionData, thunks);

  // this should write all the individual thunks to the child's memory
  if (!PatchClientFunctions(thunks, thunk_bytes, &dll_data))
    return false;

  // and now write the first part of the table to the child's memory
  DWORD written;
  bool ok = FALSE != ::WriteProcessMemory(child, thunks, &dll_data,
                                          offsetof(DllInterceptionData, thunks),
                                          &written);

  if (!ok || (offsetof(DllInterceptionData, thunks) != written))
    return false;

  // Attempt to protect all the thunks, but ignore failure
  DWORD old_protection;
  ::VirtualProtectEx(child, thunks, thunk_bytes,
                     PAGE_EXECUTE_READ, &old_protection);

  return true;
}

bool InterceptionManager::PatchClientFunctions(DllInterceptionData* thunks,
                                               size_t thunk_bytes,
                                               DllInterceptionData* dll_data) {
  DCHECK(NULL != thunks);
  DCHECK(NULL != dll_data);

  HMODULE ntdll_base = ::GetModuleHandle(kNtdllName);
  if (!ntdll_base)
    return false;

  // Bypass purify's interception.
  wchar_t* loader_get = reinterpret_cast<wchar_t*>(
                            ::GetProcAddress(ntdll_base, "LdrGetDllHandle"));
  if (loader_get) {
    if (!GetModuleHandleHelper(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
                                   GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
                               loader_get, &ntdll_base))
      return false;
  }

  Wow64 WowHelper(child_, ntdll_base);
  if (!WowHelper.WaitForNtdll(INFINITE))
    return false;

  char* interceptor_base = NULL;

#if SANDBOX_EXPORTS
  interceptor_base = reinterpret_cast<char*>(child_->MainModule());
  HMODULE local_interceptor = ::LoadLibrary(child_->Name());
#endif

  ServiceResolverThunk* thunk;
  if (WowHelper.IsWow64())
    thunk = new Wow64ResolverThunk(child_->Process(), relaxed_);
  else if (!IsXPSP2OrLater())
    thunk = new Win2kResolverThunk(child_->Process(), relaxed_);
  else
    thunk = new ServiceResolverThunk(child_->Process(), relaxed_);

  std::list<InterceptionData>::iterator it = interceptions_.begin();
  for (; it != interceptions_.end(); ++it) {
    const std::wstring ntdll(kNtdllName);
    if (it->dll != ntdll)
      break;

    if (INTERCEPTION_SERVICE_CALL != it->type)
      break;

#if SANDBOX_EXPORTS
    // We may be trying to patch by function name.
    if (NULL == it->interceptor_address) {
      const char* address;
      NTSTATUS ret = thunk->ResolveInterceptor(local_interceptor,
                                               it->interceptor.c_str(),
                                               reinterpret_cast<const void**>(
                                               &address));
      if (!NT_SUCCESS(ret))
        break;

      // Translate the local address to an address on the child.
      it->interceptor_address = interceptor_base + (address -
                                    reinterpret_cast<char*>(local_interceptor));
    }
#endif
    NTSTATUS ret = thunk->Setup(ntdll_base,
                                interceptor_base,
                                it->function.c_str(),
                                it->interceptor.c_str(),
                                it->interceptor_address,
                                &thunks->thunks[dll_data->num_thunks],
                                thunk_bytes - dll_data->used_bytes,
                                NULL);
    if (!NT_SUCCESS(ret))
      break;

    dll_data->num_thunks++;
    dll_data->used_bytes += sizeof(ThunkData);
  }

  delete(thunk);

#if SANDBOX_EXPORTS
  if (NULL != local_interceptor)
    ::FreeLibrary(local_interceptor);
#endif

  if (it != interceptions_.end())
    return false;

  return true;
}

}  // namespace sandbox

<|endoftext|>


<commit_before>// $Header$

#include "TPCSector3DEditor.h"
#include <Alieve/TPCSector3D.h>

#include <TVirtualPad.h>
#include <TColor.h>

#include <TGLabel.h>
#include <TGButton.h>
#include <TGNumberEntry.h>
#include <TGColorSelect.h>
#include <TGSlider.h>
#include <TGDoubleSlider.h>

using namespace Reve;
using namespace Alieve;

//______________________________________________________________________
// TPCSector3DEditor
//

ClassImp(TPCSector3DEditor)

TPCSector3DEditor::TPCSector3DEditor(const TGWindow *p, Int_t id, Int_t width, Int_t height,
                                     UInt_t options, Pixel_t back) :
  TGedFrame(p, id, width, height, options | kVerticalFrame, back)
{
  fM = 0;
  MakeTitle("TPCSector3D");

  fRnrFrame = new TGCheckButton(this, "ShowFrame");
  AddFrame(fRnrFrame, new TGLayoutHints(kLHintsTop, 3, 1, 1, 0));
  fRnrFrame->Connect
    ("Toggled(Bool_t)","Alieve::TPCSector3DEditor", this, "DoRnrFrame()");

  {
    TGHorizontalFrame* f = new TGHorizontalFrame(this);
    TGLabel *l = new TGLabel(f, "Drift Velocity factor:");
    f->AddFrame(l, new TGLayoutHints(kLHintsLeft | kLHintsCenterY, 25, 2, 1, 1));
    fDriftVel = new TGNumberEntry(f, 0., 6, -1,
                       TGNumberFormat::kNESRealOne, TGNumberFormat::kNEAPositive,
                       TGNumberFormat::kNELLimitMinMax, 0.001, 1000.0);
    fDriftVel->GetNumberEntry()->SetToolTipText("Drift velocity factor.");
    f->AddFrame(fDriftVel, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));
    fDriftVel->Associate(f);
    fDriftVel->Connect("ValueSet(Long_t)", "Alieve::TPCSector3DEditor", this, "DoDriftVel()");
    AddFrame(f, new TGLayoutHints(kLHintsTop, 1, 1, 1, 1));
  }

  // Register the editor.
  TClass *cl = TPCSector3D::Class();
  TGedElement *ge = new TGedElement;
  ge->fGedFrame = this;
  ge->fCanvas = 0;
  cl->GetEditorList()->Add(ge);
}

TPCSector3DEditor::~TPCSector3DEditor()
{}

/**************************************************************************/

void TPCSector3DEditor::SetModel(TVirtualPad* pad, TObject* obj, Int_t /*event*/)
{
  fModel = 0;
  fPad   = 0;

  if (!obj || !obj->InheritsFrom(TPCSector3D::Class()) || obj->InheritsFrom(TVirtualPad::Class())) {
    SetActive(kFALSE);
    return;
  }

  fModel = obj;
  fPad   = pad;

  fM = dynamic_cast<TPCSector3D*>(fModel);

  fRnrFrame->SetState(fM->fRnrFrame ? kButtonDown : kButtonUp);
  fDriftVel->SetNumber(fM->fDriftVel);

  SetActive();
}

/**************************************************************************/

void TPCSector3DEditor::DoRnrFrame()
{
  fM->SetRnrFrame(fRnrFrame->IsOn());
  Update();
}

void TPCSector3DEditor::DoDriftVel()
{
  fM->SetDriftVel((Float_t) fDriftVel->GetNumber());
  Update();
}
<commit_msg>Increased precision of drift velocity widget.<commit_after>// $Header$

#include "TPCSector3DEditor.h"
#include <Alieve/TPCSector3D.h>

#include <TVirtualPad.h>
#include <TColor.h>

#include <TGLabel.h>
#include <TGButton.h>
#include <TGNumberEntry.h>
#include <TGColorSelect.h>
#include <TGSlider.h>
#include <TGDoubleSlider.h>

using namespace Reve;
using namespace Alieve;

//______________________________________________________________________
// TPCSector3DEditor
//

ClassImp(TPCSector3DEditor)

TPCSector3DEditor::TPCSector3DEditor(const TGWindow *p, Int_t id, Int_t width, Int_t height,
                                     UInt_t options, Pixel_t back) :
  TGedFrame(p, id, width, height, options | kVerticalFrame, back)
{
  fM = 0;
  MakeTitle("TPCSector3D");

  fRnrFrame = new TGCheckButton(this, "ShowFrame");
  AddFrame(fRnrFrame, new TGLayoutHints(kLHintsTop, 3, 1, 1, 0));
  fRnrFrame->Connect
    ("Toggled(Bool_t)","Alieve::TPCSector3DEditor", this, "DoRnrFrame()");

  {
    TGHorizontalFrame* f = new TGHorizontalFrame(this);
    TGLabel *l = new TGLabel(f, "Drift Velocity factor:");
    f->AddFrame(l, new TGLayoutHints(kLHintsLeft | kLHintsCenterY, 25, 2, 1, 1));
    fDriftVel = new TGNumberEntry(f, 0., 6, -1,
                       TGNumberFormat::kNESRealThree, TGNumberFormat::kNEAPositive,
                       TGNumberFormat::kNELLimitMinMax, 0.001, 1000.0);
    fDriftVel->GetNumberEntry()->SetToolTipText("Drift velocity factor.");
    f->AddFrame(fDriftVel, new TGLayoutHints(kLHintsLeft, 1, 1, 1, 1));
    fDriftVel->Associate(f);
    fDriftVel->Connect("ValueSet(Long_t)", "Alieve::TPCSector3DEditor", this, "DoDriftVel()");
    AddFrame(f, new TGLayoutHints(kLHintsTop, 1, 1, 1, 1));
  }

  // Register the editor.
  TClass *cl = TPCSector3D::Class();
  TGedElement *ge = new TGedElement;
  ge->fGedFrame = this;
  ge->fCanvas = 0;
  cl->GetEditorList()->Add(ge);
}

TPCSector3DEditor::~TPCSector3DEditor()
{}

/**************************************************************************/

void TPCSector3DEditor::SetModel(TVirtualPad* pad, TObject* obj, Int_t /*event*/)
{
  fModel = 0;
  fPad   = 0;

  if (!obj || !obj->InheritsFrom(TPCSector3D::Class()) || obj->InheritsFrom(TVirtualPad::Class())) {
    SetActive(kFALSE);
    return;
  }

  fModel = obj;
  fPad   = pad;

  fM = dynamic_cast<TPCSector3D*>(fModel);

  fRnrFrame->SetState(fM->fRnrFrame ? kButtonDown : kButtonUp);
  fDriftVel->SetNumber(fM->fDriftVel);

  SetActive();
}

/**************************************************************************/

void TPCSector3DEditor::DoRnrFrame()
{
  fM->SetRnrFrame(fRnrFrame->IsOn());
  Update();
}

void TPCSector3DEditor::DoDriftVel()
{
  fM->SetDriftVel((Float_t) fDriftVel->GetNumber());
  Update();
}
<|endoftext|>


<commit_before>//
//  MasterSystem.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 20/09/2018.
//  Copyright © 2018 Thomas Harte. All rights reserved.
//

#include "MasterSystem.hpp"

#include "../../Processors/Z80/Z80.hpp"

#include "../../Components/9918/9918.hpp"
#include "../../Components/SN76489/SN76489.hpp"

#include "../CRTMachine.hpp"
#include "../JoystickMachine.hpp"

#include "../../ClockReceiver/ForceInline.hpp"

#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"

#include "../../Analyser/Static/Sega/Target.hpp"

namespace {
const int sn76489_divider = 2;
}

namespace Sega {
namespace MasterSystem {

class ConcreteMachine:
	public Machine,
	public CPU::Z80::BusHandler,
	public CRTMachine::Machine {

	public:
		ConcreteMachine(const Analyser::Static::Sega::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
			z80_(*this),
			sn76489_(TI::SN76489::Personality::SMS, audio_queue_, sn76489_divider),
			speaker_(sn76489_) {
			speaker_.set_input_rate(3579545.0f / static_cast<float>(sn76489_divider));
			set_clock_rate(3579545);

			const auto roms = rom_fetcher("MasterSystem", {"bios.sms"});
			if(!roms[0]) {
				throw ROMMachine::Error::MissingROMs;
			}

			roms[0]->resize(8*1024);
			memcpy(&bios_, roms[0]->data(), roms[0]->size());
		}

		~ConcreteMachine() {
			audio_queue_.flush();
		}

		void setup_output(float aspect_ratio) override {
			vdp_.reset(new TI::TMS::TMS9918(TI::TMS::SMSVDP));
			get_crt()->set_video_signal(Outputs::CRT::VideoSignal::Composite);
		}

		void close_output() override {
			vdp_.reset();
		}

		Outputs::CRT::CRT *get_crt() override {
			return vdp_->get_crt();
		}

		Outputs::Speaker::Speaker *get_speaker() override {
			return &speaker_;
		}

		void run_for(const Cycles cycles) override {
			z80_.run_for(cycles);
		}

		forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
			time_since_vdp_update_ += cycle.length;
			time_since_sn76489_update_ += cycle.length;

			if(cycle.is_terminal()) {
				uint16_t address = cycle.address ? *cycle.address : 0x0000;
				switch(cycle.operation) {
					case CPU::Z80::PartialMachineCycle::ReadOpcode:
//						printf("%04x\n", address);
					case CPU::Z80::PartialMachineCycle::Read:
						if(address < 0x2000) {
							*cycle.value = bios_[address];
						} else if(address >= 0xc000) {
							*cycle.value = ram_[address & 8191];
						} else {
//							printf("lr %04x\n", address);
							*cycle.value = 0xff;
						}
					break;

					case CPU::Z80::PartialMachineCycle::Write:
						if(address >= 0xc000) {
							ram_[address & 8191] = *cycle.value;
//							printf("w %04x\n", address);
						} else {
//							printf("mw %04x\n", address);
						}
					break;

					case CPU::Z80::PartialMachineCycle::Input:
						switch(address & 0xc1) {
							case 0x00:
								printf("TODO: memory control\n");
								*cycle.value = 0xff;
							break;
							case 0x01:
								printf("TODO: I/O port control\n");
								*cycle.value = 0xff;
							break;
							case 0x40: case 0x41:
								printf("TODO: get current line\n");
								*cycle.value = 0xff;
							break;
							case 0x80: case 0x81:
								update_video();
								*cycle.value = vdp_->get_register(address);
								z80_.set_interrupt_line(vdp_->get_interrupt_line());
								time_until_interrupt_ = vdp_->get_time_until_interrupt();
							break;
							case 0xc0:
								printf("TODO: I/O port A/N\n");
								*cycle.value = 0;
							break;
							case 0xc1:
								printf("TODO: I/O port B/misc\n");
								*cycle.value = 0;
							break;

							default:
								printf("Clearly some sort of typo\n");
							break;
						}
					break;

					case CPU::Z80::PartialMachineCycle::Output:
						switch(address & 0xc1) {
							case 0x00:
								printf("TODO: memory control\n");
							break;
							case 0x01:
								printf("TODO: I/O port control\n");
							break;
							case 0x40: case 0x41:
								update_audio();
								sn76489_.set_register(*cycle.value);
							break;
							case 0x80: case 0x81:
								update_video();
								vdp_->set_register(address, *cycle.value);
								z80_.set_interrupt_line(vdp_->get_interrupt_line());
								time_until_interrupt_ = vdp_->get_time_until_interrupt();
							break;
							case 0xc0:
								printf("TODO: I/O port A/N\n");
							break;
							case 0xc1:
								printf("TODO: I/O port B/misc\n");
							break;

							default:
								printf("Clearly some sort of typo\n");
							break;
						}
					break;

					case CPU::Z80::PartialMachineCycle::Interrupt:
						*cycle.value = 0xff;
					break;

					default: break;
				}
			}

			if(time_until_interrupt_ > 0) {
				time_until_interrupt_ -= cycle.length;
				if(time_until_interrupt_ <= HalfCycles(0)) {
					z80_.set_interrupt_line(true, time_until_interrupt_);
				}
			}

			return HalfCycles(0);
		}

		void flush() {
			update_video();
			update_audio();
			audio_queue_.perform();
		}

	private:
		inline void update_audio() {
			speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
		}
		inline void update_video() {
			vdp_->run_for(time_since_vdp_update_.flush());
		}

		CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
		std::unique_ptr<TI::TMS::TMS9918> vdp_;

		Concurrency::DeferringAsyncTaskQueue audio_queue_;
		TI::SN76489 sn76489_;
		Outputs::Speaker::LowpassSpeaker<TI::SN76489> speaker_;

		HalfCycles time_since_vdp_update_;
		HalfCycles time_since_sn76489_update_;
		HalfCycles time_until_interrupt_;

		uint8_t ram_[8*1024];
		uint8_t bios_[8*1024];
};

}
}

using namespace Sega::MasterSystem;

Machine *Machine::MasterSystem(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher) {
	using Target = Analyser::Static::Sega::Target;
	const Target *const sega_target = dynamic_cast<const Target *>(target);
	return new ConcreteMachine(*sega_target, rom_fetcher);
}

Machine::~Machine() {}
<commit_msg>Adds fairly standard memory map indirection.<commit_after>//
//  MasterSystem.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 20/09/2018.
//  Copyright © 2018 Thomas Harte. All rights reserved.
//

#include "MasterSystem.hpp"

#include "../../Processors/Z80/Z80.hpp"

#include "../../Components/9918/9918.hpp"
#include "../../Components/SN76489/SN76489.hpp"

#include "../CRTMachine.hpp"
#include "../JoystickMachine.hpp"

#include "../../ClockReceiver/ForceInline.hpp"

#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"

#include "../../Analyser/Static/Sega/Target.hpp"

namespace {
const int sn76489_divider = 2;
}

namespace Sega {
namespace MasterSystem {

class ConcreteMachine:
	public Machine,
	public CPU::Z80::BusHandler,
	public CRTMachine::Machine {

	public:
		ConcreteMachine(const Analyser::Static::Sega::Target &target, const ROMMachine::ROMFetcher &rom_fetcher) :
			z80_(*this),
			sn76489_(TI::SN76489::Personality::SMS, audio_queue_, sn76489_divider),
			speaker_(sn76489_) {
			speaker_.set_input_rate(3579545.0f / static_cast<float>(sn76489_divider));
			set_clock_rate(3579545);

			for(auto &pointer: read_pointers_) {
				pointer = nullptr;
			}
			for(auto &pointer: write_pointers_) {
				pointer = nullptr;
			}

			if(target.model == Analyser::Static::Sega::Target::Model::MasterSystem) {
				const auto roms = rom_fetcher("MasterSystem", {"bios.sms"});
				if(!roms[0]) {
					throw ROMMachine::Error::MissingROMs;
				}

				roms[0]->resize(8*1024);
				memcpy(&bios_, roms[0]->data(), roms[0]->size());
				map(read_pointers_, bios_, 8*1024, 0);

				map(read_pointers_, ram_, 8*1024, 0xc000, 0x10000);
				map(write_pointers_, ram_, 8*1024, 0xc000, 0x10000);
			} else {
				map(read_pointers_, ram_, 1024, 0xc000, 0x10000);
				map(write_pointers_, ram_, 1024, 0xc000, 0x10000);
			}
		}

		~ConcreteMachine() {
			audio_queue_.flush();
		}

		void setup_output(float aspect_ratio) override {
			vdp_.reset(new TI::TMS::TMS9918(TI::TMS::SMSVDP));
			get_crt()->set_video_signal(Outputs::CRT::VideoSignal::Composite);
		}

		void close_output() override {
			vdp_.reset();
		}

		Outputs::CRT::CRT *get_crt() override {
			return vdp_->get_crt();
		}

		Outputs::Speaker::Speaker *get_speaker() override {
			return &speaker_;
		}

		void run_for(const Cycles cycles) override {
			z80_.run_for(cycles);
		}

		forceinline HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
			time_since_vdp_update_ += cycle.length;
			time_since_sn76489_update_ += cycle.length;

			if(cycle.is_terminal()) {
				uint16_t address = cycle.address ? *cycle.address : 0x0000;
				switch(cycle.operation) {
					case CPU::Z80::PartialMachineCycle::ReadOpcode:
					case CPU::Z80::PartialMachineCycle::Read:
						*cycle.value = read_pointers_[address >> 10] ? read_pointers_[address >> 10][address & 1023] : 0xff;
					break;

					case CPU::Z80::PartialMachineCycle::Write:
						if(write_pointers_[address >> 10]) write_pointers_[address >> 10][address & 1023] = *cycle.value;
					break;

					case CPU::Z80::PartialMachineCycle::Input:
						switch(address & 0xc1) {
							case 0x00:
								printf("TODO: memory control\n");
								*cycle.value = 0xff;
							break;
							case 0x01:
								printf("TODO: I/O port control\n");
								*cycle.value = 0xff;
							break;
							case 0x40: case 0x41:
								printf("TODO: get current line\n");
								*cycle.value = 0xff;
							break;
							case 0x80: case 0x81:
								update_video();
								*cycle.value = vdp_->get_register(address);
								z80_.set_interrupt_line(vdp_->get_interrupt_line());
								time_until_interrupt_ = vdp_->get_time_until_interrupt();
							break;
							case 0xc0:
								printf("TODO: I/O port A/N\n");
								*cycle.value = 0;
							break;
							case 0xc1:
								printf("TODO: I/O port B/misc\n");
								*cycle.value = 0;
							break;

							default:
								printf("Clearly some sort of typo\n");
							break;
						}
					break;

					case CPU::Z80::PartialMachineCycle::Output:
						switch(address & 0xc1) {
							case 0x00:
								printf("TODO: memory control\n");
							break;
							case 0x01:
								printf("TODO: I/O port control\n");
							break;
							case 0x40: case 0x41:
								update_audio();
								sn76489_.set_register(*cycle.value);
							break;
							case 0x80: case 0x81:
								update_video();
								vdp_->set_register(address, *cycle.value);
								z80_.set_interrupt_line(vdp_->get_interrupt_line());
								time_until_interrupt_ = vdp_->get_time_until_interrupt();
							break;
							case 0xc0:
								printf("TODO: I/O port A/N\n");
							break;
							case 0xc1:
								printf("TODO: I/O port B/misc\n");
							break;

							default:
								printf("Clearly some sort of typo\n");
							break;
						}
					break;

					case CPU::Z80::PartialMachineCycle::Interrupt:
						*cycle.value = 0xff;
					break;

					default: break;
				}
			}

			if(time_until_interrupt_ > 0) {
				time_until_interrupt_ -= cycle.length;
				if(time_until_interrupt_ <= HalfCycles(0)) {
					z80_.set_interrupt_line(true, time_until_interrupt_);
				}
			}

			return HalfCycles(0);
		}

		void flush() {
			update_video();
			update_audio();
			audio_queue_.perform();
		}

	private:
		inline void update_audio() {
			speaker_.run_for(audio_queue_, time_since_sn76489_update_.divide_cycles(Cycles(sn76489_divider)));
		}
		inline void update_video() {
			vdp_->run_for(time_since_vdp_update_.flush());
		}

		CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
		std::unique_ptr<TI::TMS::TMS9918> vdp_;

		Concurrency::DeferringAsyncTaskQueue audio_queue_;
		TI::SN76489 sn76489_;
		Outputs::Speaker::LowpassSpeaker<TI::SN76489> speaker_;

		HalfCycles time_since_vdp_update_;
		HalfCycles time_since_sn76489_update_;
		HalfCycles time_until_interrupt_;

		uint8_t ram_[8*1024];
		uint8_t bios_[8*1024];
		std::vector<uint8_t> cartridge_;

		// The memory map has a 1kb granularity; this is determined by the SG1000's 1kb of RAM.
		const uint8_t *read_pointers_[64];
		uint8_t *write_pointers_[64];
		template <typename T> void map(T **target, uint8_t *source, int size, int start_address, int end_address = -1) {
			if(end_address == -1) end_address = start_address + size;
			for(int address = start_address; address < end_address; address += 1024) {
				target[address >> 10] = &source[(address - start_address) & (size - 1)];
			}
		}
};

}
}

using namespace Sega::MasterSystem;

Machine *Machine::MasterSystem(const Analyser::Static::Target *target, const ROMMachine::ROMFetcher &rom_fetcher) {
	using Target = Analyser::Static::Sega::Target;
	const Target *const sega_target = dynamic_cast<const Target *>(target);
	return new ConcreteMachine(*sega_target, rom_fetcher);
}

Machine::~Machine() {}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: filetest.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 04:49:08 $
 *
 *  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
 *
 ************************************************************************/
#include <iostream>

#ifndef _OSL_FILE_HXX_
#include<osl/file.hxx>
#endif

#include <rtl/ustring.hxx>

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

// -----------------------------------------------------------------------------
// --------------------------------- namespaces ---------------------------------
// -----------------------------------------------------------------------------
using namespace com::sun::star::uno;

using ::rtl::OUString;
using ::osl::File;
// -----------------------------------------------------------------------------
// ---------------------------------- defines ----------------------------------
// -----------------------------------------------------------------------------
#define ASCII(x) OUString::createFromAscii(x)

// -----------------------------------------------------------------------------
// ------------------------------------ main ------------------------------------
// -----------------------------------------------------------------------------

/*
OUString operator+(const OUString &a, const OUString &b)
{
    OUString c = a;
    c += b;
    return c;
}
*/

#if (defined UNX) || (defined OS2)
int main( int argc, char * argv[] )
#else
int _cdecl main( int argc, char * argv[] )
#endif
{
    OUString aPath = ASCII("f:/local/SRC598/configmgr/workben/local_io");
    OUString aFilename = ASCII("com.sun.star.office.Setup");
    OUString aExtension = ASCII("xml");

    OUString aFullname = aPath + ASCII("/") + aFilename + ASCII(".") + aExtension;

    // Filename convertieren
    OUString aURL;
    File aConvert(ASCII(""));
    aConvert.normalizePath(aFullname, aURL);

    // File oeffnen
    File aFile(aURL);
    aFile.open(osl_File_OpenFlag_Read);

    sal_uInt64 nBytesRead;
    Sequence< sal_Int8 > aBufferSeq(2000);
    sal_Int8 *pBuff = aBufferSeq.getArray();
    aFile.read(pBuff, 2000, nBytesRead);

    aFile.close();
    return 0;
}
<commit_msg>INTEGRATION: CWS pchfix02 (1.2.60); FILE MERGED 2006/09/01 17:20:56 kaib 1.2.60.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: filetest.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 15:38:57 $
 *
 *  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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"
#include <iostream>

#ifndef _OSL_FILE_HXX_
#include<osl/file.hxx>
#endif

#include <rtl/ustring.hxx>

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif

// -----------------------------------------------------------------------------
// --------------------------------- namespaces ---------------------------------
// -----------------------------------------------------------------------------
using namespace com::sun::star::uno;

using ::rtl::OUString;
using ::osl::File;
// -----------------------------------------------------------------------------
// ---------------------------------- defines ----------------------------------
// -----------------------------------------------------------------------------
#define ASCII(x) OUString::createFromAscii(x)

// -----------------------------------------------------------------------------
// ------------------------------------ main ------------------------------------
// -----------------------------------------------------------------------------

/*
OUString operator+(const OUString &a, const OUString &b)
{
    OUString c = a;
    c += b;
    return c;
}
*/

#if (defined UNX) || (defined OS2)
int main( int argc, char * argv[] )
#else
int _cdecl main( int argc, char * argv[] )
#endif
{
    OUString aPath = ASCII("f:/local/SRC598/configmgr/workben/local_io");
    OUString aFilename = ASCII("com.sun.star.office.Setup");
    OUString aExtension = ASCII("xml");

    OUString aFullname = aPath + ASCII("/") + aFilename + ASCII(".") + aExtension;

    // Filename convertieren
    OUString aURL;
    File aConvert(ASCII(""));
    aConvert.normalizePath(aFullname, aURL);

    // File oeffnen
    File aFile(aURL);
    aFile.open(osl_File_OpenFlag_Read);

    sal_uInt64 nBytesRead;
    Sequence< sal_Int8 > aBufferSeq(2000);
    sal_Int8 *pBuff = aBufferSeq.getArray();
    aFile.read(pBuff, 2000, nBytesRead);

    aFile.close();
    return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSimple2DLayoutStrategy.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

// Please note: Lots of this code was directly 'lifted' from
// the vtkForceDirectedLayoutStrategy class
#include "vtkSimple2DLayoutStrategy.h"

#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkCommand.h>
#include <vtkDataArray.h>
#include <vtkFloatArray.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkMath.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>

#include "vtkAbstractGraph.h"
#include "vtkGraph.h"
#include "vtkTree.h"

vtkCxxRevisionMacro(vtkSimple2DLayoutStrategy, "1.4");
vtkStandardNewMacro(vtkSimple2DLayoutStrategy);

// Cool-down function.
static inline float CoolDown(float t, float r)
{
  return t-(t/r);
}

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

vtkSimple2DLayoutStrategy::vtkSimple2DLayoutStrategy()
{
  this->MaxNumberOfIterations = 100;
  this->IterationsPerLayout = 100;
  this->InitialTemperature = 1;
  this->CoolDownRate = 50.0;
  this->LayoutComplete = 0;
  this->ArcWeightField = 0;
}

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

vtkSimple2DLayoutStrategy::~vtkSimple2DLayoutStrategy()
{
  this->SetArcWeightField(0);
}

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

// Set the graph that will be laid out
void vtkSimple2DLayoutStrategy::Initialize()
{
  // Set up some quick access variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numNodes = this->Graph->GetNumberOfNodes();
  vtkIdType numArcs = this->Graph->GetNumberOfArcs();

  // The optimal distance between vertices.
  float optDist = sqrt(1.0 / static_cast<float>(numNodes));

  // Put the data into compact, fast access data structures
  this->VArray = new vtkLayoutVertex[numNodes];
  this->ArcArray =  new vtkLayoutArc[numArcs];

  // Load up the vertex data structures
  for (vtkIdType i=0; i<numNodes; ++i)
    {
    // Get point position
    double pointCoords[3];
    pts->GetPoint(i, pointCoords);

    // If coordinates are 0 then give some random value
    if ((pointCoords[0]==0) && (pointCoords[1]==0))
      {
      pointCoords[0] = optDist*(static_cast<float>(rand())/RAND_MAX - .5);
      pointCoords[1] = optDist*(static_cast<float>(rand())/RAND_MAX - .5);
      }

    // Set point position
    this->VArray[i].x = static_cast<float>(pointCoords[0]);
    this->VArray[i].y = static_cast<float>(pointCoords[1]);
    }

  // Get the weight array
  vtkDataArray* weightArray = NULL;
  double avgWeight = 0;
  if (this->ArcWeightField != NULL)
    {
    weightArray = vtkDataArray::SafeDownCast(this->Graph->GetArcData()->GetAbstractArray(this->ArcWeightField));
    if (weightArray != NULL)
      {
      for (vtkIdType w = 0; w < weightArray->GetNumberOfTuples(); w++)
        {
        double* tuple = weightArray->GetTuple(w);
        avgWeight += tuple[0];
        }
      avgWeight /= weightArray->GetNumberOfTuples();
      }
    }

  // Load up the edge data structures
  for (vtkIdType i=0; i<numArcs; ++i)
    {
    this->ArcArray[i].from = this->Graph->GetSourceNode(i);
    this->ArcArray[i].to = this->Graph->GetTargetNode(i);
    if (weightArray != NULL)
      {
      double* tuple = weightArray->GetTuple(i);
      this->ArcArray[i].weight = tuple[0] / avgWeight;
      }
    else
      {
      this->ArcArray[i].weight = 1.0;
      }
    }

  // Set some vars
  this->TotalIterations = 0;
  this->LayoutComplete = 0;
  this->Temp = this->InitialTemperature;
}

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

// Simple graph layout method
void vtkSimple2DLayoutStrategy::Layout()
{
  // Do I have a graph to layout
  if (this->Graph == NULL)
    {
    vtkErrorMacro("Graph Layout called with Graph==NULL, call SetGraph(g) first");
    this->LayoutComplete = 1;
    return;
    }

  // Set up some variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numNodes = this->Graph->GetNumberOfNodes();
  vtkIdType numArcs = this->Graph->GetNumberOfArcs();

  // The optimal distance between vertices.
  float optDist = sqrt(1.0 / static_cast<float>(numNodes));

  // This is the mega, uber, triple inner loop
  // ye of weak hearts, tread no further!
  float delta[]={0,0,0};
  float dis, disSquared;
  float repulseValue;
  float attractValue;
  for(int i = 0; i < this->IterationsPerLayout; ++i)
    {

    // Calculate the repulsive forces
    for(vtkIdType j=0; j<numNodes; ++j)
      {
      this->VArray[j].dx = 0;
      this->VArray[j].dy = 0;
      for(vtkIdType k=0; k<numNodes; ++k)
        {
        if (k != j)
          {
          delta[0] = this->VArray[j].x - this->VArray[k].x;
          delta[1] = this->VArray[j].y - this->VArray[k].y;

          // Traditional k/d replusion
          if (this->Temp > .2)
            {
            dis = fabs(delta[0]) + fabs(delta[1]);
            repulseValue = optDist/dis;
            }

          // k/d**2 replusion ( flowering :)
          else
            {
            disSquared = delta[0]*delta[0] + delta[1]*delta[1];
            repulseValue = optDist/disSquared;
            }
          this->VArray[j].dx += delta[0] * repulseValue;
          this->VArray[j].dy += delta[1] * repulseValue;
          }
        }
      }

    // Calculate the attractive forces
    for (vtkIdType j=0; j<numArcs; ++j)
      {
      delta[0] = this->VArray[this->ArcArray[j].to].x -
             this->VArray[this->ArcArray[j].from].x;
      delta[1] = this->VArray[this->ArcArray[j].to].y -
             this->VArray[this->ArcArray[j].from].y;
      disSquared = delta[0]*delta[0] + delta[1]*delta[1];

      // Emergency action on edges that are 10x
      // their 'resting' distance
      if (disSquared > 100*optDist)
        {
        float jump = this->Temp * .5;
        this->VArray[this->ArcArray[j].to].x   -= delta[0] * jump;
        this->VArray[this->ArcArray[j].to].y   -= delta[1] * jump;
        this->VArray[this->ArcArray[j].from].x += delta[0] * jump;
        this->VArray[this->ArcArray[j].from].y += delta[1] * jump;
        }

      // Perform weight adjustment
      attractValue = this->ArcArray[j].weight*disSquared/optDist;
      this->VArray[this->ArcArray[j].to].dx   -= delta[0] * attractValue;
      this->VArray[this->ArcArray[j].to].dy   -= delta[1] * attractValue;
      this->VArray[this->ArcArray[j].from].dx += delta[0] * attractValue;
      this->VArray[this->ArcArray[j].from].dy += delta[1] * attractValue;
      }

    // Combine the forces to compute new positions
    float norm;
    for (vtkIdType j=0; j<numNodes; ++j)
      {
      delta[0] = this->VArray[j].dx;
      delta[1] = this->VArray[j].dy;
      norm = vtkMath::Normalize(delta);
      float minimum = (norm < this->Temp ? norm : this->Temp);
      this->VArray[j].x += delta[0] * minimum;
      this->VArray[j].y += delta[1] * minimum;
      }

    // Reduce temperature as layout approaches a better configuration.
    this->Temp = CoolDown(this->Temp, this->CoolDownRate);

    // Announce progress
    double progress = static_cast<double>(this->TotalIterations) / static_cast<double>(this->MaxNumberOfIterations);
<
    this->InvokeEvent(vtkCommand::ProgressEvent, static_cast<void *>(&progress));

   } // End loop this->IterationsPerLayout

   // Now take the temporary point coordinate datastructure
   // and convert back to VTK data structures
   for (vtkIdType i=0; i<numNodes; ++i)
    {
    pts->SetPoint (i, this->VArray[i].x, this->VArray[i].y, 0.0);
    }

  // Check for completion of layout
  this->TotalIterations += this->IterationsPerLayout;
  if (this->TotalIterations >= this->MaxNumberOfIterations)
    {
    // I'm done
    this->LayoutComplete = 1;
    }
}

void vtkSimple2DLayoutStrategy::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "InitialTemperature: " << this->InitialTemperature << endl;
  os << indent << "MaxNumberOfIterations: " << this->MaxNumberOfIterations << endl;
  os << indent << "IterationsPerLayout: " << this->IterationsPerLayout << endl;
  os << indent << "CoolDownRate: " << this->CoolDownRate << endl;
  os << indent << "ArcWeightField: " << (this->ArcWeightField ? this->ArcWeightField : "(none)") << endl;
}
<commit_msg>COMP: Where did that stray < come from?<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSimple2DLayoutStrategy.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*----------------------------------------------------------------------------
 Copyright (c) Sandia Corporation
 See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
----------------------------------------------------------------------------*/

// Please note: Lots of this code was directly 'lifted' from
// the vtkForceDirectedLayoutStrategy class
#include "vtkSimple2DLayoutStrategy.h"

#include <vtkCellArray.h>
#include <vtkCellData.h>
#include <vtkCommand.h>
#include <vtkDataArray.h>
#include <vtkFloatArray.h>
#include <vtkInformation.h>
#include <vtkInformationVector.h>
#include <vtkMath.h>
#include <vtkObjectFactory.h>
#include <vtkPointData.h>

#include "vtkAbstractGraph.h"
#include "vtkGraph.h"
#include "vtkTree.h"

vtkCxxRevisionMacro(vtkSimple2DLayoutStrategy, "1.5");
vtkStandardNewMacro(vtkSimple2DLayoutStrategy);

// Cool-down function.
static inline float CoolDown(float t, float r)
{
  return t-(t/r);
}

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

vtkSimple2DLayoutStrategy::vtkSimple2DLayoutStrategy()
{
  this->MaxNumberOfIterations = 100;
  this->IterationsPerLayout = 100;
  this->InitialTemperature = 1;
  this->CoolDownRate = 50.0;
  this->LayoutComplete = 0;
  this->ArcWeightField = 0;
}

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

vtkSimple2DLayoutStrategy::~vtkSimple2DLayoutStrategy()
{
  this->SetArcWeightField(0);
}

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

// Set the graph that will be laid out
void vtkSimple2DLayoutStrategy::Initialize()
{
  // Set up some quick access variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numNodes = this->Graph->GetNumberOfNodes();
  vtkIdType numArcs = this->Graph->GetNumberOfArcs();

  // The optimal distance between vertices.
  float optDist = sqrt(1.0 / static_cast<float>(numNodes));

  // Put the data into compact, fast access data structures
  this->VArray = new vtkLayoutVertex[numNodes];
  this->ArcArray =  new vtkLayoutArc[numArcs];

  // Load up the vertex data structures
  for (vtkIdType i=0; i<numNodes; ++i)
    {
    // Get point position
    double pointCoords[3];
    pts->GetPoint(i, pointCoords);

    // If coordinates are 0 then give some random value
    if ((pointCoords[0]==0) && (pointCoords[1]==0))
      {
      pointCoords[0] = optDist*(static_cast<float>(rand())/RAND_MAX - .5);
      pointCoords[1] = optDist*(static_cast<float>(rand())/RAND_MAX - .5);
      }

    // Set point position
    this->VArray[i].x = static_cast<float>(pointCoords[0]);
    this->VArray[i].y = static_cast<float>(pointCoords[1]);
    }

  // Get the weight array
  vtkDataArray* weightArray = NULL;
  double avgWeight = 0;
  if (this->ArcWeightField != NULL)
    {
    weightArray = vtkDataArray::SafeDownCast(this->Graph->GetArcData()->GetAbstractArray(this->ArcWeightField));
    if (weightArray != NULL)
      {
      for (vtkIdType w = 0; w < weightArray->GetNumberOfTuples(); w++)
        {
        double* tuple = weightArray->GetTuple(w);
        avgWeight += tuple[0];
        }
      avgWeight /= weightArray->GetNumberOfTuples();
      }
    }

  // Load up the edge data structures
  for (vtkIdType i=0; i<numArcs; ++i)
    {
    this->ArcArray[i].from = this->Graph->GetSourceNode(i);
    this->ArcArray[i].to = this->Graph->GetTargetNode(i);
    if (weightArray != NULL)
      {
      double* tuple = weightArray->GetTuple(i);
      this->ArcArray[i].weight = tuple[0] / avgWeight;
      }
    else
      {
      this->ArcArray[i].weight = 1.0;
      }
    }

  // Set some vars
  this->TotalIterations = 0;
  this->LayoutComplete = 0;
  this->Temp = this->InitialTemperature;
}

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

// Simple graph layout method
void vtkSimple2DLayoutStrategy::Layout()
{
  // Do I have a graph to layout
  if (this->Graph == NULL)
    {
    vtkErrorMacro("Graph Layout called with Graph==NULL, call SetGraph(g) first");
    this->LayoutComplete = 1;
    return;
    }

  // Set up some variables
  vtkPoints* pts = this->Graph->GetPoints();
  vtkIdType numNodes = this->Graph->GetNumberOfNodes();
  vtkIdType numArcs = this->Graph->GetNumberOfArcs();

  // The optimal distance between vertices.
  float optDist = sqrt(1.0 / static_cast<float>(numNodes));

  // This is the mega, uber, triple inner loop
  // ye of weak hearts, tread no further!
  float delta[]={0,0,0};
  float dis, disSquared;
  float repulseValue;
  float attractValue;
  for(int i = 0; i < this->IterationsPerLayout; ++i)
    {

    // Calculate the repulsive forces
    for(vtkIdType j=0; j<numNodes; ++j)
      {
      this->VArray[j].dx = 0;
      this->VArray[j].dy = 0;
      for(vtkIdType k=0; k<numNodes; ++k)
        {
        if (k != j)
          {
          delta[0] = this->VArray[j].x - this->VArray[k].x;
          delta[1] = this->VArray[j].y - this->VArray[k].y;

          // Traditional k/d replusion
          if (this->Temp > .2)
            {
            dis = fabs(delta[0]) + fabs(delta[1]);
            repulseValue = optDist/dis;
            }

          // k/d**2 replusion ( flowering :)
          else
            {
            disSquared = delta[0]*delta[0] + delta[1]*delta[1];
            repulseValue = optDist/disSquared;
            }
          this->VArray[j].dx += delta[0] * repulseValue;
          this->VArray[j].dy += delta[1] * repulseValue;
          }
        }
      }

    // Calculate the attractive forces
    for (vtkIdType j=0; j<numArcs; ++j)
      {
      delta[0] = this->VArray[this->ArcArray[j].to].x -
             this->VArray[this->ArcArray[j].from].x;
      delta[1] = this->VArray[this->ArcArray[j].to].y -
             this->VArray[this->ArcArray[j].from].y;
      disSquared = delta[0]*delta[0] + delta[1]*delta[1];

      // Emergency action on edges that are 10x
      // their 'resting' distance
      if (disSquared > 100*optDist)
        {
        float jump = this->Temp * .5;
        this->VArray[this->ArcArray[j].to].x   -= delta[0] * jump;
        this->VArray[this->ArcArray[j].to].y   -= delta[1] * jump;
        this->VArray[this->ArcArray[j].from].x += delta[0] * jump;
        this->VArray[this->ArcArray[j].from].y += delta[1] * jump;
        }

      // Perform weight adjustment
      attractValue = this->ArcArray[j].weight*disSquared/optDist;
      this->VArray[this->ArcArray[j].to].dx   -= delta[0] * attractValue;
      this->VArray[this->ArcArray[j].to].dy   -= delta[1] * attractValue;
      this->VArray[this->ArcArray[j].from].dx += delta[0] * attractValue;
      this->VArray[this->ArcArray[j].from].dy += delta[1] * attractValue;
      }

    // Combine the forces to compute new positions
    float norm;
    for (vtkIdType j=0; j<numNodes; ++j)
      {
      delta[0] = this->VArray[j].dx;
      delta[1] = this->VArray[j].dy;
      norm = vtkMath::Normalize(delta);
      float minimum = (norm < this->Temp ? norm : this->Temp);
      this->VArray[j].x += delta[0] * minimum;
      this->VArray[j].y += delta[1] * minimum;
      }

    // Reduce temperature as layout approaches a better configuration.
    this->Temp = CoolDown(this->Temp, this->CoolDownRate);

    // Announce progress
    double progress = static_cast<double>(this->TotalIterations) / static_cast<double>(this->MaxNumberOfIterations);

    this->InvokeEvent(vtkCommand::ProgressEvent, static_cast<void *>(&progress));

   } // End loop this->IterationsPerLayout

   // Now take the temporary point coordinate datastructure
   // and convert back to VTK data structures
   for (vtkIdType i=0; i<numNodes; ++i)
    {
    pts->SetPoint (i, this->VArray[i].x, this->VArray[i].y, 0.0);
    }

  // Check for completion of layout
  this->TotalIterations += this->IterationsPerLayout;
  if (this->TotalIterations >= this->MaxNumberOfIterations)
    {
    // I'm done
    this->LayoutComplete = 1;
    }
}

void vtkSimple2DLayoutStrategy::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "InitialTemperature: " << this->InitialTemperature << endl;
  os << indent << "MaxNumberOfIterations: " << this->MaxNumberOfIterations << endl;
  os << indent << "IterationsPerLayout: " << this->IterationsPerLayout << endl;
  os << indent << "CoolDownRate: " << this->CoolDownRate << endl;
  os << indent << "ArcWeightField: " << (this->ArcWeightField ? this->ArcWeightField : "(none)") << endl;
}
<|endoftext|>


<commit_before>
#include "chunk_headers.hpp"
#include "glm_pod_wrappers.hpp"
#include "magic_number.hpp"
#include "msh_builder.hpp"
#include "type_pun.hpp"
#include "ucfb_reader.hpp"

namespace {

struct Collision_info {
   std::uint32_t vertex_count;
   std::uint32_t node_count;
   std::uint32_t leaf_count;
   std::uint32_t unknown;

   float bbox_info[6];
};

static_assert(std::is_standard_layout_v<Collision_info>);
static_assert(sizeof(Collision_info) == 40);

std::vector<glm::vec3> read_positions(Ucfb_reader_strict<"POSI"_mn> vertices,
                                      const std::size_t vertex_count)
{
   std::vector<glm::vec3> buffer;
   buffer.resize(vertex_count);

   const auto vertex_array = vertices.read_array<pod::Vec3>(vertex_count);

   std::memcpy(buffer.data(), vertex_array.data(), buffer.size() * sizeof(glm::vec3));

   return buffer;
}

std::vector<std::uint16_t> read_tree_leaf(Ucfb_reader_strict<"LEAF"_mn> leaf)
{
   std::uint8_t index_count = leaf.read_trivial_unaligned<std::uint8_t>();
   leaf.consume_unaligned(6);

   const auto indices = leaf.read_array<std::uint16_t>(index_count);

   return {std::cbegin(indices), std::cend(indices)};
}

void handle_tree(Ucfb_reader_strict<"TREE"_mn> tree, msh::Collsion_mesh& collision_mesh)
{
   while (tree) {
      const auto child = tree.read_child();

      if (child.magic_number() == "LEAF"_mn) {
         collision_mesh.strips.emplace_back(
            read_tree_leaf(Ucfb_reader_strict<"LEAF"_mn>{child}));
      }
   }
}
}

void handle_collision(Ucfb_reader collision, msh::Builders_map& builders)
{
   const std::string name{collision.read_child_strict<"NAME"_mn>().read_string()};

   const auto parent = collision.read_child_strict<"NODE"_mn>().read_string();

   const auto info =
      collision.read_child_strict<"INFO"_mn>().read_trivial<Collision_info>();

   msh::Collsion_mesh collision_mesh;
   collision_mesh.parent = parent;
   collision_mesh.strips.reserve(info.leaf_count);

   collision_mesh.vertices =
      read_positions(collision.read_child_strict<"POSI"_mn>(), info.vertex_count);

   handle_tree(collision.read_child_strict<"TREE"_mn>(), collision_mesh);

   builders[name].add_collision_mesh(std::move(collision_mesh));
}
<commit_msg>Fixed handle_collision chunk ordering<commit_after>
#include "chunk_headers.hpp"
#include "glm_pod_wrappers.hpp"
#include "magic_number.hpp"
#include "msh_builder.hpp"
#include "type_pun.hpp"
#include "ucfb_reader.hpp"

namespace {

struct Collision_info {
   std::uint32_t vertex_count;
   std::uint32_t node_count;
   std::uint32_t leaf_count;
   std::uint32_t unknown;

   float bbox_info[6];
};

static_assert(std::is_standard_layout_v<Collision_info>);
static_assert(sizeof(Collision_info) == 40);

std::vector<glm::vec3> read_positions(Ucfb_reader_strict<"POSI"_mn> vertices,
                                      const std::size_t vertex_count)
{
   std::vector<glm::vec3> buffer;
   buffer.resize(vertex_count);

   const auto vertex_array = vertices.read_array<pod::Vec3>(vertex_count);

   std::memcpy(buffer.data(), vertex_array.data(), buffer.size() * sizeof(glm::vec3));

   return buffer;
}

std::vector<std::uint16_t> read_tree_leaf(Ucfb_reader_strict<"LEAF"_mn> leaf)
{
   std::uint8_t index_count = leaf.read_trivial_unaligned<std::uint8_t>();
   leaf.consume_unaligned(6);

   const auto indices = leaf.read_array<std::uint16_t>(index_count);

   return {std::cbegin(indices), std::cend(indices)};
}

void handle_tree(Ucfb_reader_strict<"TREE"_mn> tree, msh::Collsion_mesh& collision_mesh)
{
   while (tree) {
      const auto child = tree.read_child();

      if (child.magic_number() == "LEAF"_mn) {
         collision_mesh.strips.emplace_back(
            read_tree_leaf(Ucfb_reader_strict<"LEAF"_mn>{child}));
      }
   }
}
}

void handle_collision(Ucfb_reader collision, msh::Builders_map& builders)
{
   const std::string name{collision.read_child_strict<"NAME"_mn>().read_string()};

   collision.read_child_strict_optional<"MASK"_mn>();

   const auto parent = collision.read_child_strict<"NODE"_mn>().read_string();

   const auto info =
      collision.read_child_strict<"INFO"_mn>().read_trivial<Collision_info>();

   msh::Collsion_mesh collision_mesh;
   collision_mesh.parent = parent;
   collision_mesh.strips.reserve(info.leaf_count);

   collision_mesh.vertices =
      read_positions(collision.read_child_strict<"POSI"_mn>(), info.vertex_count);

   handle_tree(collision.read_child_strict<"TREE"_mn>(), collision_mesh);

   builders[name].add_collision_mesh(std::move(collision_mesh));
}
<|endoftext|>