<commit_before>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <atlbase.h>
#include <atlapp.h>
#include <malloc.h>

#include "base/command_line.h"
#include "base/icu_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stats_table.h"
#include "base/string_util.h"
#include "base/win_util.h"
#include "chrome/browser/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_counters.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_util.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/resource_bundle.h"
#include "sandbox/src/sandbox.h"
#include "tools/memory_watcher/memory_watcher.h"

extern int BrowserMain(CommandLine &, int, sandbox::BrokerServices*);
extern int RendererMain(CommandLine &, int, sandbox::TargetServices*);
extern int PluginMain(CommandLine &, int, sandbox::TargetServices*);

static const wchar_t kProfilingDll[] = L"memory_watcher.dll";

// Load the memory profiling DLL.  All it needs to be activated
// is to be loaded.  Return true on success, false otherwise.
bool LoadMemoryProfiler() {
  HMODULE prof_module = LoadLibrary(kProfilingDll);
  return prof_module != NULL;
}

CAppModule _Module;

// TODO(erikkay): isn't this already defined somewhere?
#define DLLEXPORT __declspec(dllexport)

// We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
extern "C" {
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo *sandbox_info,
                                 TCHAR* command_line, int show_command);
}

#pragma optimize("", off)
// Handlers for invalid parameter and pure call. They generate a breakpoint to
// tell breakpad that it needs to dump the process.
void InvalidParameter(const wchar_t* expression, const wchar_t* function,
                      const wchar_t* file, unsigned int line,
                      uintptr_t reserved) {
  __debugbreak();
}

void PureCall() {
  __debugbreak();
}

// Handlers to silently dump the current process when there is an assert in
// chrome.
void ChromeAssert(const std::string& str) {
  // Get the breakpad pointer from chrome.exe
  typedef void (__stdcall *DumpProcessFunction)();
  DumpProcessFunction DumpProcess = reinterpret_cast<DumpProcessFunction>(
      ::GetProcAddress(::GetModuleHandle(L"chrome.exe"), "DumpProcess"));
  if (DumpProcess)
    DumpProcess();
}

#pragma optimize("", on)

// Try to unload DLLs that malfunction with the sandboxed processes.
static void EvictTroublesomeDlls() {
  const wchar_t* troublesome_dlls[] = {
      L"smumhook.dll",  // spyware doctor version 5 and above.
      NULL              // Must be null. Here you can add with the debugger.
  };

  for(int ix = 0; ix != arraysize(troublesome_dlls); ++ix) {
    if (!troublesome_dlls[ix])
      break;
    HMODULE module = ::GetModuleHandleW(troublesome_dlls[ix]);
    if (module) {
      LOG(WARNING) << "dll to evict found: " << ix;
      if (::FreeLibrary(module)) {
        DCHECK(NULL == ::GetModuleHandleW(troublesome_dlls[ix]));
      }
    }
  }
}

DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo *sandbox_info,
                                 TCHAR* command_line, int show_command) {
#ifdef _CRTDBG_MAP_ALLOC
  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
#else
  _CrtSetReportMode(_CRT_ASSERT, 0);
#endif

  // Register the invalid param handler and pure call handler to be able to
  // notify breakpad when it happens.
  _set_invalid_parameter_handler(InvalidParameter);
  _set_purecall_handler(PureCall);

  CommandLine parsed_command_line;

  // Enable the low fragmentation heap for the CRT heap. The heap is not changed
  // if the process is run under the debugger is enabled or if certain gflags
  // are set.
  bool use_lfh = false;
  if (parsed_command_line.HasSwitch(switches::kUseLowFragHeapCrt))
    use_lfh = parsed_command_line.GetSwitchValue(switches::kUseLowFragHeapCrt)
        != L"false";
  if (use_lfh) {
    void* crt_heap = reinterpret_cast<void*>(_get_heap_handle());
    ULONG enable_lfh = 2;
    HeapSetInformation(crt_heap, HeapCompatibilityInformation,
                       &enable_lfh, sizeof(enable_lfh));
  }

  // Initialize the Chrome path provider.
  chrome::RegisterPathProvider();

  // Initialize the Stats Counters table.  With this initialized,
  // the StatsViewer can be utilized to read counters outside of
  // Chrome.  These lines can be commented out to effectively turn
  // counters 'off'.  The table is created and exists for the life
  // of the process.  It is not cleaned up.
  StatsTable *stats_table = new StatsTable(chrome::kStatsFilename,
      chrome::kStatsMaxThreads, chrome::kStatsMaxCounters);
  StatsTable::set_current(stats_table);

  StatsScope<StatsCounterTimer>
      startup_timer(chrome::Counters::chrome_main());

  // Enable the heap profiler as early as possible!
  if (parsed_command_line.HasSwitch(switches::kMemoryProfiling))
    if (!LoadMemoryProfiler())
      exit(-1);

  // Enable Message Loop related state asap.
  if (parsed_command_line.HasSwitch(switches::kMessageLoopStrategy)) {
    std::wstring details =
        parsed_command_line.GetSwitchValue(switches::kMessageLoopStrategy);
    int strategy = 0;
    if (details.size()) {
      strategy = static_cast<int>(StringToInt64(details));
    }
    MessageLoop::SetStrategy(strategy);
  }
  if (parsed_command_line.HasSwitch(switches::kMessageLoopHistogrammer))
    MessageLoop::EnableHistogrammer(true);

  sandbox::TargetServices* target_services = NULL;
  sandbox::BrokerServices* broker_services = NULL;
  if (sandbox_info) {
    target_services = sandbox_info->target_services;
    broker_services = sandbox_info->broker_services;
  }

  std::wstring process_type =
    parsed_command_line.GetSwitchValue(switches::kProcessType);

  bool do_dll_eviction = false;

  // Checks if the sandbox is enabled in this process and initializes it if this
  // is the case. The crash handler depends on this so it has to be done before
  // its initialization.
  if (target_services && !parsed_command_line.HasSwitch(switches::kNoSandbox)) {
    if ((process_type == switches::kRendererProcess) ||
        (process_type == switches::kPluginProcess &&
         parsed_command_line.HasSwitch(switches::kSafePlugins))) {
      target_services->Init();
      do_dll_eviction = true;
    }
  }

  _Module.Init(NULL, instance);

  // Allocate a message loop for this thread
  MessageLoop main_message_loop;

  // Notice a user data directory override if any
  const std::wstring user_data_dir =
      parsed_command_line.GetSwitchValue(switches::kUserDataDir);
  if (!user_data_dir.empty())
    PathService::Override(chrome::DIR_USER_DATA, user_data_dir);

  bool single_process =
    parsed_command_line.HasSwitch(switches::kSingleProcess);
  if (single_process)
    RenderProcessHost::set_run_renderer_in_process(true);

  bool icu_result = icu_util::Initialize();
  CHECK(icu_result);

  logging::OldFileDeletionState file_state =
      logging::APPEND_TO_OLD_LOG_FILE;
  if (process_type.empty()) {
    file_state = logging::DELETE_OLD_LOG_FILE;
  }
  logging::InitChromeLogging(parsed_command_line, file_state);

#ifdef NDEBUG
  if (parsed_command_line.HasSwitch(switches::kSilentDumpOnDCHECK) &&
      parsed_command_line.HasSwitch(switches::kEnableDCHECK)) {
    logging::SetLogAssertHandler(ChromeAssert);
  }
#endif

  if (!process_type.empty()) {
    // Initialize ResourceBundle which handles files loaded from external
    // sources.  The language should have been passed in to us from the
    // browser process as a command line flag.
    ResourceBundle::InitSharedInstance(std::wstring());
  }

  // Eviction of injected DLLs is done early enough that it is likely
  // to only cover DLLs injected by means of appInit_dlls registry key.
  if (do_dll_eviction)
      EvictTroublesomeDlls();

  startup_timer.Stop();  // End of Startup Time Measurement.

  int rv;
  if (process_type == switches::kRendererProcess) {
    rv = RendererMain(parsed_command_line, show_command, target_services);
  } else if (process_type == switches::kPluginProcess) {
    rv = PluginMain(parsed_command_line, show_command, target_services);
  } else if (process_type.empty()) {
    int ole_result = OleInitialize(NULL);
    DCHECK(ole_result == S_OK);
    rv = BrowserMain(parsed_command_line, show_command, broker_services);
    OleUninitialize();
  } else {
    NOTREACHED() << "Unknown process type";
    rv = -1;
  }

  if (!process_type.empty()) {
    ResourceBundle::CleanupSharedInstance();
  }

#ifdef _CRTDBG_MAP_ALLOC
  _CrtDumpMemoryLeaks();
#endif

  _Module.Term();

  logging::CleanupChromeLogging();

  return rv;
}
<commit_msg>Trap all malloc/new allocation failures in chrome.dll at allocation point. This won't fix the failure but this will help classifying minidumps.<commit_after>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <atlbase.h>
#include <atlapp.h>
#include <malloc.h>
#include <new.h>

#include "base/command_line.h"
#include "base/icu_util.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stats_table.h"
#include "base/string_util.h"
#include "base/win_util.h"
#include "chrome/browser/render_process_host.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_counters.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/env_util.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/resource_bundle.h"
#include "sandbox/src/sandbox.h"
#include "tools/memory_watcher/memory_watcher.h"

extern int BrowserMain(CommandLine &, int, sandbox::BrokerServices*);
extern int RendererMain(CommandLine &, int, sandbox::TargetServices*);
extern int PluginMain(CommandLine &, int, sandbox::TargetServices*);

static const wchar_t kProfilingDll[] = L"memory_watcher.dll";

// Load the memory profiling DLL.  All it needs to be activated
// is to be loaded.  Return true on success, false otherwise.
bool LoadMemoryProfiler() {
  HMODULE prof_module = LoadLibrary(kProfilingDll);
  return prof_module != NULL;
}

CAppModule _Module;

// TODO(erikkay): isn't this already defined somewhere?
#define DLLEXPORT __declspec(dllexport)

// We use extern C for the prototype DLLEXPORT to avoid C++ name mangling.
extern "C" {
DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo *sandbox_info,
                                 TCHAR* command_line, int show_command);
}

#pragma optimize("", off)
// Handlers for invalid parameter and pure call. They generate a breakpoint to
// tell breakpad that it needs to dump the process.
void InvalidParameter(const wchar_t* expression, const wchar_t* function,
                      const wchar_t* file, unsigned int line,
                      uintptr_t reserved) {
  __debugbreak();
}

void PureCall() {
  __debugbreak();
}

int OnNoMemory(size_t memory_size) {
  __debugbreak();
  // Return memory_size so it is not optimized out. Make sure the return value
  // is at least 1 so malloc/new is retried, especially useful when under a
  // debugger.
  return memory_size ? static_cast<int>(memory_size) : 1;
}

// Handlers to silently dump the current process when there is an assert in
// chrome.
void ChromeAssert(const std::string& str) {
  // Get the breakpad pointer from chrome.exe
  typedef void (__stdcall *DumpProcessFunction)();
  DumpProcessFunction DumpProcess = reinterpret_cast<DumpProcessFunction>(
      ::GetProcAddress(::GetModuleHandle(L"chrome.exe"), "DumpProcess"));
  if (DumpProcess)
    DumpProcess();
}

#pragma optimize("", on)

// Try to unload DLLs that malfunction with the sandboxed processes.
static void EvictTroublesomeDlls() {
  const wchar_t* troublesome_dlls[] = {
      L"smumhook.dll",  // spyware doctor version 5 and above.
      NULL              // Must be null. Here you can add with the debugger.
  };

  for(int ix = 0; ix != arraysize(troublesome_dlls); ++ix) {
    if (!troublesome_dlls[ix])
      break;
    HMODULE module = ::GetModuleHandleW(troublesome_dlls[ix]);
    if (module) {
      LOG(WARNING) << "dll to evict found: " << ix;
      if (::FreeLibrary(module)) {
        DCHECK(NULL == ::GetModuleHandleW(troublesome_dlls[ix]));
      }
    }
  }
}

DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance,
                                 sandbox::SandboxInterfaceInfo *sandbox_info,
                                 TCHAR* command_line, int show_command) {
#ifdef _CRTDBG_MAP_ALLOC
  _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
  _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
#else
  _CrtSetReportMode(_CRT_ASSERT, 0);
#endif

  // Register the invalid param handler and pure call handler to be able to
  // notify breakpad when it happens.
  _set_invalid_parameter_handler(InvalidParameter);
  _set_purecall_handler(PureCall);
  // Gather allocation failure.
  _set_new_handler(&OnNoMemory);
  // Make sure malloc() calls the new handler too.
  _set_new_mode(1);

  CommandLine parsed_command_line;

  // Enable the low fragmentation heap for the CRT heap. The heap is not changed
  // if the process is run under the debugger is enabled or if certain gflags
  // are set.
  bool use_lfh = false;
  if (parsed_command_line.HasSwitch(switches::kUseLowFragHeapCrt))
    use_lfh = parsed_command_line.GetSwitchValue(switches::kUseLowFragHeapCrt)
        != L"false";
  if (use_lfh) {
    void* crt_heap = reinterpret_cast<void*>(_get_heap_handle());
    ULONG enable_lfh = 2;
    HeapSetInformation(crt_heap, HeapCompatibilityInformation,
                       &enable_lfh, sizeof(enable_lfh));
  }

  // Initialize the Chrome path provider.
  chrome::RegisterPathProvider();

  // Initialize the Stats Counters table.  With this initialized,
  // the StatsViewer can be utilized to read counters outside of
  // Chrome.  These lines can be commented out to effectively turn
  // counters 'off'.  The table is created and exists for the life
  // of the process.  It is not cleaned up.
  StatsTable *stats_table = new StatsTable(chrome::kStatsFilename,
      chrome::kStatsMaxThreads, chrome::kStatsMaxCounters);
  StatsTable::set_current(stats_table);

  StatsScope<StatsCounterTimer>
      startup_timer(chrome::Counters::chrome_main());

  // Enable the heap profiler as early as possible!
  if (parsed_command_line.HasSwitch(switches::kMemoryProfiling))
    if (!LoadMemoryProfiler())
      exit(-1);

  // Enable Message Loop related state asap.
  if (parsed_command_line.HasSwitch(switches::kMessageLoopStrategy)) {
    std::wstring details =
        parsed_command_line.GetSwitchValue(switches::kMessageLoopStrategy);
    int strategy = 0;
    if (details.size()) {
      strategy = static_cast<int>(StringToInt64(details));
    }
    MessageLoop::SetStrategy(strategy);
  }
  if (parsed_command_line.HasSwitch(switches::kMessageLoopHistogrammer))
    MessageLoop::EnableHistogrammer(true);

  sandbox::TargetServices* target_services = NULL;
  sandbox::BrokerServices* broker_services = NULL;
  if (sandbox_info) {
    target_services = sandbox_info->target_services;
    broker_services = sandbox_info->broker_services;
  }

  std::wstring process_type =
    parsed_command_line.GetSwitchValue(switches::kProcessType);

  bool do_dll_eviction = false;

  // Checks if the sandbox is enabled in this process and initializes it if this
  // is the case. The crash handler depends on this so it has to be done before
  // its initialization.
  if (target_services && !parsed_command_line.HasSwitch(switches::kNoSandbox)) {
    if ((process_type == switches::kRendererProcess) ||
        (process_type == switches::kPluginProcess &&
         parsed_command_line.HasSwitch(switches::kSafePlugins))) {
      target_services->Init();
      do_dll_eviction = true;
    }
  }

  _Module.Init(NULL, instance);

  // Allocate a message loop for this thread
  MessageLoop main_message_loop;

  // Notice a user data directory override if any
  const std::wstring user_data_dir =
      parsed_command_line.GetSwitchValue(switches::kUserDataDir);
  if (!user_data_dir.empty())
    PathService::Override(chrome::DIR_USER_DATA, user_data_dir);

  bool single_process =
    parsed_command_line.HasSwitch(switches::kSingleProcess);
  if (single_process)
    RenderProcessHost::set_run_renderer_in_process(true);

  bool icu_result = icu_util::Initialize();
  CHECK(icu_result);

  logging::OldFileDeletionState file_state =
      logging::APPEND_TO_OLD_LOG_FILE;
  if (process_type.empty()) {
    file_state = logging::DELETE_OLD_LOG_FILE;
  }
  logging::InitChromeLogging(parsed_command_line, file_state);

#ifdef NDEBUG
  if (parsed_command_line.HasSwitch(switches::kSilentDumpOnDCHECK) &&
      parsed_command_line.HasSwitch(switches::kEnableDCHECK)) {
    logging::SetLogAssertHandler(ChromeAssert);
  }
#endif

  if (!process_type.empty()) {
    // Initialize ResourceBundle which handles files loaded from external
    // sources.  The language should have been passed in to us from the
    // browser process as a command line flag.
    ResourceBundle::InitSharedInstance(std::wstring());
  }

  // Eviction of injected DLLs is done early enough that it is likely
  // to only cover DLLs injected by means of appInit_dlls registry key.
  if (do_dll_eviction)
      EvictTroublesomeDlls();

  startup_timer.Stop();  // End of Startup Time Measurement.

  int rv;
  if (process_type == switches::kRendererProcess) {
    rv = RendererMain(parsed_command_line, show_command, target_services);
  } else if (process_type == switches::kPluginProcess) {
    rv = PluginMain(parsed_command_line, show_command, target_services);
  } else if (process_type.empty()) {
    int ole_result = OleInitialize(NULL);
    DCHECK(ole_result == S_OK);
    rv = BrowserMain(parsed_command_line, show_command, broker_services);
    OleUninitialize();
  } else {
    NOTREACHED() << "Unknown process type";
    rv = -1;
  }

  if (!process_type.empty()) {
    ResourceBundle::CleanupSharedInstance();
  }

#ifdef _CRTDBG_MAP_ALLOC
  _CrtDumpMemoryLeaks();
#endif

  _Module.Term();

  logging::CleanupChromeLogging();

  return rv;
}
<|endoftext|>


<commit_before><commit_msg>Have rlz record first search event in a corner case<commit_after><|endoftext|>


<commit_before>//
//  MCHTMLRendererCallback.cpp
//  mailcore2
//
//  Created by DINH Viêt Hoà on 2/2/13.
//  Copyright (c) 2013 MailCore. All rights reserved.
//

#include "MCHTMLRendererCallback.h"

#include "MCAddressDisplay.h"
#include "MCDateFormatter.h"
#include "MCSizeFormatter.h"
#include "MCAttachment.h"

using namespace mailcore;

mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForHeader(mailcore::MessageHeader * header)
{
    mailcore::HashMap * result = mailcore::HashMap::hashMap();

    if (header->from() != NULL) {
        result->setObjectForKey(MCSTR("HASFROM"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("FROM"), mailcore::AddressDisplay::displayStringForAddress(header->from())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTFROM"), mailcore::AddressDisplay::shortDisplayStringForAddress(header->from())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTFROM"), mailcore::AddressDisplay::veryShortDisplayStringForAddress(header->from())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOFROM"), mailcore::HashMap::hashMap());
    }

    if ((header->to() != NULL) && (header->to()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASTO"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("TO"), mailcore::AddressDisplay::displayStringForAddresses(header->to())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->to())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->to())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOTO"), mailcore::HashMap::hashMap());
    }

    if ((header->cc() != NULL) && (header->cc()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASCC"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("CC"), mailcore::AddressDisplay::displayStringForAddresses(header->cc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->cc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->cc())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOCC"), mailcore::HashMap::hashMap());
    }

    if ((header->bcc() != NULL) && (header->bcc()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASBCC"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("BCC"), mailcore::AddressDisplay::displayStringForAddresses(header->bcc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTBCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->bcc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTBCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->bcc())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOBCC"), mailcore::HashMap::hashMap());
    }

    mailcore::Array * recipient = new mailcore::Array();
    recipient->addObjectsFromArray(header->to());
    recipient->addObjectsFromArray(header->cc());
    recipient->addObjectsFromArray(header->bcc());

    if (recipient->count() > 0) {
        result->setObjectForKey(MCSTR("HASRECIPIENT"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("RECIPIENT"), mailcore::AddressDisplay::displayStringForAddresses(recipient)->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTRECIPIENT"), mailcore::AddressDisplay::shortDisplayStringForAddresses(recipient)->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTRECIPIENT"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(recipient)->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NORECIPIENT"), mailcore::HashMap::hashMap());
    }
    recipient->release();

    if ((header->replyTo() != NULL) && (header->replyTo()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASREPLYTO"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("REPLYTO"), mailcore::AddressDisplay::displayStringForAddresses(header->replyTo())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTREPLYTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->replyTo())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTREPLYTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->replyTo())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOREPLYTO"), mailcore::HashMap::hashMap());
    }

    if ((header->subject() != NULL) && (header->subject()->length() > 0)) {
        result->setObjectForKey(MCSTR("EXTRACTEDSUBJECT"), header->partialExtractedSubject()->htmlEncodedString());
        result->setObjectForKey(MCSTR("SUBJECT"), header->subject()->htmlEncodedString());
        result->setObjectForKey(MCSTR("HASSUBJECT"), mailcore::HashMap::hashMap());
    }
    else {
        result->setObjectForKey(MCSTR("NOSUBJECT"), mailcore::HashMap::hashMap());
    }

    mailcore::String * dateString;
    static mailcore::DateFormatter * fullFormatter = NULL;
    if (fullFormatter == NULL) {
        fullFormatter = new mailcore::DateFormatter();
        fullFormatter->setDateStyle(mailcore::DateFormatStyleFull);
        fullFormatter->setTimeStyle(mailcore::DateFormatStyleFull);
    }
    dateString = fullFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("FULLDATE"), dateString->htmlEncodedString());
    }
    static mailcore::DateFormatter * longFormatter = NULL;
    if (longFormatter == NULL) {
        longFormatter = new mailcore::DateFormatter();
        longFormatter->setDateStyle(mailcore::DateFormatStyleLong);
        longFormatter->setTimeStyle(mailcore::DateFormatStyleLong);
    }
    dateString = longFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("LONGDATE"), dateString->htmlEncodedString());
    }
    static mailcore::DateFormatter * mediumFormatter = NULL;
    if (mediumFormatter == NULL) {
        mediumFormatter = new mailcore::DateFormatter();
        mediumFormatter->setDateStyle(mailcore::DateFormatStyleMedium);
        mediumFormatter->setTimeStyle(mailcore::DateFormatStyleMedium);
    }
    dateString = mediumFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("MEDIUMDATE"), dateString->htmlEncodedString());
    }
    static mailcore::DateFormatter * shortFormatter = NULL;
    if (shortFormatter == NULL) {
        shortFormatter = new mailcore::DateFormatter();
        shortFormatter->setDateStyle(mailcore::DateFormatStyleShort);
        shortFormatter->setTimeStyle(mailcore::DateFormatStyleShort);
    }
    dateString = shortFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("SHORTDATE"), dateString->htmlEncodedString());
    }

    return result;
}

mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForPart(mailcore::AbstractPart * part)
{
    mailcore::HashMap * result = mailcore::HashMap::hashMap();
    mailcore::String * filename = NULL;

    if (part->filename() != NULL) {
        filename = part->filename()->lastPathComponent();
    }

    if (filename != NULL) {
        result->setObjectForKey(MCSTR("FILENAME"), filename->htmlEncodedString());
    }

    if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) {
        mailcore::IMAPPart * imapPart = (mailcore::IMAPPart *) part;
        mailcore::String * value = mailcore::SizeFormatter::stringWithSize(imapPart->size());
        result->setObjectForKey(MCSTR("SIZE"), value);
        result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap());
    }
    else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) {
        mailcore::Attachment * attachment = (mailcore::Attachment *) part;
        mailcore::String * value = mailcore::SizeFormatter::stringWithSize(attachment->data()->length());
        result->setObjectForKey(MCSTR("SIZE"), value);
        result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap());
    }
    else {
        result->setObjectForKey(MCSTR("NOSIZE"), mailcore::HashMap::hashMap());
    }

    if (part->contentID() != NULL) {
        result->setObjectForKey(MCSTR("CONTENTID"), part->contentID());
    }
    if (part->uniqueID() != NULL) {
        result->setObjectForKey(MCSTR("UNIQUEID"), part->uniqueID());
    }

    return result;
}

mailcore::String * HTMLRendererTemplateCallback::templateForMainHeader(MessageHeader * header)
{
    return MCSTR("
\
                 {{#HASFROM}}\

From: {{FROM}}
\
                 {{/HASFROM}}\
                 {{#HASTO}}\

To: {{TO}}
\
                 {{/HASTO}}\
                 {{#HASCC}}\

Cc: {{CC}}
\
                 {{/HASCC}}\
                 {{#HASBCC}}\

Bcc: {{BCC}}
\
                 {{/HASBCC}}\
                 {{#NORECIPIENT}}\

To: Undisclosed recipient
\
                 {{/NORECIPIENT}}\
                 {{#HASSUBJECT}}\

Subject: {{EXTRACTEDSUBJECT}}
\
                 {{/HASSUBJECT}}\
                 {{#NOSUBJECT}}\

Subject: No Subject
\
                 {{/NOSUBJECT}}\

Date: {{LONGDATE}}
\

");
}

mailcore::String * HTMLRendererTemplateCallback::templateForEmbeddedMessageHeader(MessageHeader * header)
{
    return templateForMainHeader(header);
}

mailcore::String * HTMLRendererTemplateCallback::templateForImage(AbstractPart * part)
{
    return MCSTR("");
}

mailcore::String * HTMLRendererTemplateCallback::templateForAttachment(AbstractPart * part)
{
    return MCSTR("{{#HASSIZE}}\

- {{FILENAME}}, {{SIZE}}
\
                 {{/HASSIZE}}\
                 {{#NOSIZE}}\

- {{FILENAME}}
\
                 {{/NOSIZE}}\
                 ");
}

mailcore::String * HTMLRendererTemplateCallback::templateForMessage(AbstractMessage * message)
{
    return MCSTR("
{{HEADER}}

{{BODY}}
");
}

mailcore::String * HTMLRendererTemplateCallback::templateForEmbeddedMessage(AbstractMessagePart * part)
{
    return MCSTR("
{{HEADER}}

{{BODY}}
");
}

mailcore::String * HTMLRendererTemplateCallback::templateForAttachmentSeparator()
{
    return MCSTR("
");
}

mailcore::String * HTMLRendererTemplateCallback::filterHTMLForMessage(mailcore::String * html)
{
    return html;
}

mailcore::String * HTMLRendererTemplateCallback::filterHTMLForPart(mailcore::String * html)
{
    return html;
}

bool HTMLRendererTemplateCallback::canPreviewPart(AbstractPart * part)
{
    return false;
}

bool HTMLRendererTemplateCallback::shouldShowPart(AbstractPart * part)
{
    return true;
}
<commit_msg>Fixed part size in default rendering (fixed #595)<commit_after>//
//  MCHTMLRendererCallback.cpp
//  mailcore2
//
//  Created by DINH Viêt Hoà on 2/2/13.
//  Copyright (c) 2013 MailCore. All rights reserved.
//

#include "MCHTMLRendererCallback.h"

#include "MCAddressDisplay.h"
#include "MCDateFormatter.h"
#include "MCSizeFormatter.h"
#include "MCAttachment.h"

using namespace mailcore;

mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForHeader(mailcore::MessageHeader * header)
{
    mailcore::HashMap * result = mailcore::HashMap::hashMap();

    if (header->from() != NULL) {
        result->setObjectForKey(MCSTR("HASFROM"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("FROM"), mailcore::AddressDisplay::displayStringForAddress(header->from())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTFROM"), mailcore::AddressDisplay::shortDisplayStringForAddress(header->from())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTFROM"), mailcore::AddressDisplay::veryShortDisplayStringForAddress(header->from())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOFROM"), mailcore::HashMap::hashMap());
    }

    if ((header->to() != NULL) && (header->to()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASTO"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("TO"), mailcore::AddressDisplay::displayStringForAddresses(header->to())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->to())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->to())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOTO"), mailcore::HashMap::hashMap());
    }

    if ((header->cc() != NULL) && (header->cc()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASCC"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("CC"), mailcore::AddressDisplay::displayStringForAddresses(header->cc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->cc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->cc())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOCC"), mailcore::HashMap::hashMap());
    }

    if ((header->bcc() != NULL) && (header->bcc()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASBCC"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("BCC"), mailcore::AddressDisplay::displayStringForAddresses(header->bcc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTBCC"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->bcc())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTBCC"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->bcc())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOBCC"), mailcore::HashMap::hashMap());
    }

    mailcore::Array * recipient = new mailcore::Array();
    recipient->addObjectsFromArray(header->to());
    recipient->addObjectsFromArray(header->cc());
    recipient->addObjectsFromArray(header->bcc());

    if (recipient->count() > 0) {
        result->setObjectForKey(MCSTR("HASRECIPIENT"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("RECIPIENT"), mailcore::AddressDisplay::displayStringForAddresses(recipient)->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTRECIPIENT"), mailcore::AddressDisplay::shortDisplayStringForAddresses(recipient)->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTRECIPIENT"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(recipient)->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NORECIPIENT"), mailcore::HashMap::hashMap());
    }
    recipient->release();

    if ((header->replyTo() != NULL) && (header->replyTo()->count() > 0)) {
        result->setObjectForKey(MCSTR("HASREPLYTO"), mailcore::HashMap::hashMap());
        result->setObjectForKey(MCSTR("REPLYTO"), mailcore::AddressDisplay::displayStringForAddresses(header->replyTo())->htmlEncodedString());
        result->setObjectForKey(MCSTR("SHORTREPLYTO"), mailcore::AddressDisplay::shortDisplayStringForAddresses(header->replyTo())->htmlEncodedString());
        result->setObjectForKey(MCSTR("VERYSHORTREPLYTO"), mailcore::AddressDisplay::veryShortDisplayStringForAddresses(header->replyTo())->htmlEncodedString());
    }
    else {
        result->setObjectForKey(MCSTR("NOREPLYTO"), mailcore::HashMap::hashMap());
    }

    if ((header->subject() != NULL) && (header->subject()->length() > 0)) {
        result->setObjectForKey(MCSTR("EXTRACTEDSUBJECT"), header->partialExtractedSubject()->htmlEncodedString());
        result->setObjectForKey(MCSTR("SUBJECT"), header->subject()->htmlEncodedString());
        result->setObjectForKey(MCSTR("HASSUBJECT"), mailcore::HashMap::hashMap());
    }
    else {
        result->setObjectForKey(MCSTR("NOSUBJECT"), mailcore::HashMap::hashMap());
    }

    mailcore::String * dateString;
    static mailcore::DateFormatter * fullFormatter = NULL;
    if (fullFormatter == NULL) {
        fullFormatter = new mailcore::DateFormatter();
        fullFormatter->setDateStyle(mailcore::DateFormatStyleFull);
        fullFormatter->setTimeStyle(mailcore::DateFormatStyleFull);
    }
    dateString = fullFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("FULLDATE"), dateString->htmlEncodedString());
    }
    static mailcore::DateFormatter * longFormatter = NULL;
    if (longFormatter == NULL) {
        longFormatter = new mailcore::DateFormatter();
        longFormatter->setDateStyle(mailcore::DateFormatStyleLong);
        longFormatter->setTimeStyle(mailcore::DateFormatStyleLong);
    }
    dateString = longFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("LONGDATE"), dateString->htmlEncodedString());
    }
    static mailcore::DateFormatter * mediumFormatter = NULL;
    if (mediumFormatter == NULL) {
        mediumFormatter = new mailcore::DateFormatter();
        mediumFormatter->setDateStyle(mailcore::DateFormatStyleMedium);
        mediumFormatter->setTimeStyle(mailcore::DateFormatStyleMedium);
    }
    dateString = mediumFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("MEDIUMDATE"), dateString->htmlEncodedString());
    }
    static mailcore::DateFormatter * shortFormatter = NULL;
    if (shortFormatter == NULL) {
        shortFormatter = new mailcore::DateFormatter();
        shortFormatter->setDateStyle(mailcore::DateFormatStyleShort);
        shortFormatter->setTimeStyle(mailcore::DateFormatStyleShort);
    }
    dateString = shortFormatter->stringFromDate(header->date());
    if (dateString != NULL) {
        result->setObjectForKey(MCSTR("SHORTDATE"), dateString->htmlEncodedString());
    }

    return result;
}

mailcore::HashMap * HTMLRendererTemplateCallback::templateValuesForPart(mailcore::AbstractPart * part)
{
    mailcore::HashMap * result = mailcore::HashMap::hashMap();
    mailcore::String * filename = NULL;

    if (part->filename() != NULL) {
        filename = part->filename()->lastPathComponent();
    }

    if (filename != NULL) {
        result->setObjectForKey(MCSTR("FILENAME"), filename->htmlEncodedString());
    }

    if (part->className()->isEqual(MCSTR("mailcore::IMAPPart"))) {
        mailcore::IMAPPart * imapPart = (mailcore::IMAPPart *) part;
        mailcore::String * value = mailcore::SizeFormatter::stringWithSize(imapPart->decodedSize());
        result->setObjectForKey(MCSTR("SIZE"), value);
        result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap());
    }
    else if (part->className()->isEqual(MCSTR("mailcore::Attachment"))) {
        mailcore::Attachment * attachment = (mailcore::Attachment *) part;
        mailcore::String * value = mailcore::SizeFormatter::stringWithSize(attachment->data()->length());
        result->setObjectForKey(MCSTR("SIZE"), value);
        result->setObjectForKey(MCSTR("HASSIZE"), mailcore::HashMap::hashMap());
    }
    else {
        result->setObjectForKey(MCSTR("NOSIZE"), mailcore::HashMap::hashMap());
    }

    if (part->contentID() != NULL) {
        result->setObjectForKey(MCSTR("CONTENTID"), part->contentID());
    }
    if (part->uniqueID() != NULL) {
        result->setObjectForKey(MCSTR("UNIQUEID"), part->uniqueID());
    }

    return result;
}

mailcore::String * HTMLRendererTemplateCallback::templateForMainHeader(MessageHeader * header)
{
    return MCSTR("
\
                 {{#HASFROM}}\

From: {{FROM}}
\
                 {{/HASFROM}}\
                 {{#HASTO}}\

To: {{TO}}
\
                 {{/HASTO}}\
                 {{#HASCC}}\

Cc: {{CC}}
\
                 {{/HASCC}}\
                 {{#HASBCC}}\

Bcc: {{BCC}}
\
                 {{/HASBCC}}\
                 {{#NORECIPIENT}}\

To: Undisclosed recipient
\
                 {{/NORECIPIENT}}\
                 {{#HASSUBJECT}}\

Subject: {{EXTRACTEDSUBJECT}}
\
                 {{/HASSUBJECT}}\
                 {{#NOSUBJECT}}\

Subject: No Subject
\
                 {{/NOSUBJECT}}\

Date: {{LONGDATE}}
\

");
}

mailcore::String * HTMLRendererTemplateCallback::templateForEmbeddedMessageHeader(MessageHeader * header)
{
    return templateForMainHeader(header);
}

mailcore::String * HTMLRendererTemplateCallback::templateForImage(AbstractPart * part)
{
    return MCSTR("");
}

mailcore::String * HTMLRendererTemplateCallback::templateForAttachment(AbstractPart * part)
{
    return MCSTR("{{#HASSIZE}}\

- {{FILENAME}}, {{SIZE}}
\
                 {{/HASSIZE}}\
                 {{#NOSIZE}}\

- {{FILENAME}}
\
                 {{/NOSIZE}}\
                 ");
}

mailcore::String * HTMLRendererTemplateCallback::templateForMessage(AbstractMessage * message)
{
    return MCSTR("
{{HEADER}}

{{BODY}}
");
}

mailcore::String * HTMLRendererTemplateCallback::templateForEmbeddedMessage(AbstractMessagePart * part)
{
    return MCSTR("
{{HEADER}}

{{BODY}}
");
}

mailcore::String * HTMLRendererTemplateCallback::templateForAttachmentSeparator()
{
    return MCSTR("
");
}

mailcore::String * HTMLRendererTemplateCallback::filterHTMLForMessage(mailcore::String * html)
{
    return html;
}

mailcore::String * HTMLRendererTemplateCallback::filterHTMLForPart(mailcore::String * html)
{
    return html;
}

bool HTMLRendererTemplateCallback::canPreviewPart(AbstractPart * part)
{
    return false;
}

bool HTMLRendererTemplateCallback::shouldShowPart(AbstractPart * part)
{
    return true;
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Vittorio Romeo
// License: Academic Free License ("AFL") v. 3.0
// AFL License page: http://opensource.org/licenses/AFL-3.0
// http://vittorioromeo.info | vittorio.romeo@outlook.com

#pragma once

#include <scelta.hpp>

namespace example
{
    // First available variant type.
    template <typename... Ts>
    using variant =
#if defined(SCELTA_SUPPORT_VARIANT_STD)
        std::variant
#elif defined(SCELTA_SUPPORT_VARIANT_BOOST)
        boost::variant
#elif defined(SCELTA_SUPPORT_VARIANT_EGGS)
        eggs::variant
#else
#error "No variant type available."
#endif
        <Ts...>;

    // First available optional type.
    template <typename... Ts>
    using optional =
#if defined(SCELTA_SUPPORT_OPTIONAL_STD)
        std::optional
#elif defined(SCELTA_SUPPORT_OPTIONAL_BOOST)
        boost::optional
#else
#error "No optional type available."
#endif
        <Ts...>;
}<commit_msg>Add mpark variant automatic support<commit_after>// Copyright (c) 2017 Vittorio Romeo
// License: Academic Free License ("AFL") v. 3.0
// AFL License page: http://opensource.org/licenses/AFL-3.0
// http://vittorioromeo.info | vittorio.romeo@outlook.com

#pragma once

#include <scelta.hpp>

namespace example
{
    // First available variant type.
    template <typename... Ts>
    using variant =
#if defined(SCELTA_SUPPORT_VARIANT_STD)
        ::std::variant
#elif defined(SCELTA_SUPPORT_VARIANT_BOOST)
        ::boost::variant
#elif defined(SCELTA_SUPPORT_VARIANT_EGGS)
        ::eggs::variant
#elif defined(SCELTA_SUPPORT_VARIANT_MPARK)
        ::mpark::variant
#else
#error "No variant type available."
#endif
        <Ts...>;

    // First available optional type.
    template <typename... Ts>
    using optional =
#if defined(SCELTA_SUPPORT_OPTIONAL_STD)
        ::std::optional
#elif defined(SCELTA_SUPPORT_OPTIONAL_BOOST)
        ::boost::optional
#else
#error "No optional type available."
#endif
        <Ts...>;
}<|endoftext|>


<commit_before>#include "constants.hpp"
#include <string>
#include <math.h>
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>
#include <tf/transform_broadcaster.h>
#include <boost/shared_ptr.hpp>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <sstream>
#include <limits>

using namespace std;

// A serial interface used to send commands to the Arduino that controls
// the motor controllers. (Yeah, recursion!)
// (C file descriptor)
int tty;
std::stringstream ss;

// for odometry
ros::Time currentTime;
ros::Time lastTime;
ros::Publisher odomPub;
boost::shared_ptr<tf::TransformBroadcaster> odomBroadcaster;
double x = 0;
double y = 0;
double theta = 0;
double vx = 0;
double vy = 0;
double vtheta = 0;
// Make current speeds always available (and query them only once per cycle)
double vLeftCur  = 0.0;
double vRightCur = 0.0;
// Cache speeds to only send data if they change
double vLeftLast     = 0.0;
double vRightLast    = 0.0;
double vRotLeftLast  = 0.0;
double vRotRightLast = 0.0;

// Used to form the Arduino commands
const char MOTOR_LEFT = 'l';
const char MOTOR_RIGHT = 'r';
const char MOTOR_FORWARD = 'f';
const char MOTOR_BACKWARD = 'b';
const char MOTOR_STOP = 's';

// The motors are stopped (not just set to speed 0.0) below this input speed.
const float STOP_THRESHOLD = 0.01f;

bool initTty()
{
	// http://timmurphy.org/2009/08/04/baud-rate-and-other-serial-comm-settings-in-c/
	tty = open("/dev/ttyACM0", O_RDWR | O_NOCTTY/* | O_NDELAY*/);
	if(tty < 0) {
		perror("open(\"/dev/ttyACM0\")");
		return false;
	}
	struct termios settings;
	tcgetattr(tty, &settings);
	cfsetospeed(&settings, B115200);
	cfsetispeed(&settings, B0 /*same as output*/);
	settings.c_cflag &= ~PARENB;	// no parity
	settings.c_cflag &= ~CSTOPB;	// one stop bit
	settings.c_cflag &= ~CSIZE;		// 8 bits per character
	settings.c_cflag |= CS8;
	settings.c_cflag &= ~CRTSCTS;	// Disable hardware flow control
	// settings.c_cflag &= ~HUPCL;		// Send modem disconnect when closing the fd
	settings.c_cflag |= CREAD;		// Enable receiver
	// settings.c_cflag |= CLOCAL;		// Ignore modem status lines
	settings.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable start/stop I/O control
	settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Disable user terminal features
	settings.c_oflag &= ~OPOST;		// Disable output postprocessing
	settings.c_cc[VMIN]  = 0;
	settings.c_cc[VTIME] = 0;
	if(tcsetattr(tty, TCSANOW, &settings) != 0) {
		perror("tcsetattr");
		return false;
	}
	tcflush(tty, TCOFLUSH);
	return true;
}

int readLine(char* const line, const ssize_t LINE_LENGTH)
{
	ssize_t bytesRead = 0;
	bool lineComplete = false;
	while(!lineComplete && bytesRead < LINE_LENGTH) {
		// Read bytes into temporary buffer
		char buffer[LINE_LENGTH];
		// ROS_INFO("a");
		ssize_t newBytesRead = read(tty, buffer, LINE_LENGTH);
		// ROS_INFO("b");
		if(newBytesRead < 0) {
			perror("read");
		}
		// Copy new bytes to 'line'
		for(ssize_t i = 0; i < newBytesRead && bytesRead < LINE_LENGTH; i++, bytesRead++) {
			line[bytesRead] = buffer[i];
			if(buffer[i] == '\n') {
				lineComplete = true;
			}
		}
	}
	return bytesRead;
}

void setDrive(const char motor, const char direction, const float spd = 0.0f)
{
	ss.str("");
	ss << "sd" << motor << direction;
	if(direction != MOTOR_STOP) {
		ss << std::hex << (int8_t)(spd * 255);
	}
	ss << std::endl;
	const char* output = ss.str().c_str();
	write(tty, output, ss.str().length());
	// ROS_INFO("%s", output);
	// check response
	char line[2];
	const int lineLength = readLine(line, 2);
	if(atoi(line) != 0) {
		ROS_INFO("Command failed: %s", output);
	}
}

void setRotation(const char motor, const char direction, const float spd = 0.0f)
{
	ss.str("");
	ss << "sr" << motor << direction;
	if(direction != MOTOR_STOP) {
		ss << std::hex << (int8_t)(spd * 255);
	}
	ss << std::endl;
	const char* output = ss.str().c_str();
	write(tty, output, ss.str().length());
	// check response
	char line[2];
	const int lineLength = readLine(line, 2);
	if(atoi(line) != 0) {
		ROS_INFO("Command failed: %s", output);
	}
}

/*
 * Returns the speed in m/s the given motor is moving the robot at.
 */
float getSpeed(const char motor)
{
	// Write command
	ss.str("");
	// "get drive left/right rate"
	ss << "gd" << motor << 'r' << std::endl;
	const char* output = ss.str().c_str();
	write(tty, output, ss.str().length());
	// ROS_INFO("%s", ss.str().c_str());

	// Read response
	// Expected: max. 11 characters (-2,147,483,647) + \n
	const int LINE_LENGTH = 11;
	char line[LINE_LENGTH] = {0};
	const int lineLength = readLine(line, LINE_LENGTH);

	// We receive the interval in µs bewtween two motor monitor ticks
	const int interval = atoi(line);
	// Compute motor revolution freq (Hz) from motor tick interval (µs)
	// Filter out division by zero and "stop" state
	const double freq = (interval == 0 || interval == 1000000) ? 0 : 1000000 / interval;
	// if(motor == MOTOR_RIGHT)
		// ROS_INFO("interval %c: %i freq: %f", motor, interval, freq);
	// Return the resulting robot speed for this motor (m/s)
	return freq * WHEEL_DIAMETER * M_PI / (3.0 * WHEEL_REDUCTION);
}

void velocityCallback(const geometry_msgs::Twist& msg) {
	// Store current motor speeds for later reference
	vLeftCur   = getSpeed(MOTOR_LEFT);
	vRightCur  = getSpeed(MOTOR_RIGHT);

	// Compute the motor speeds necessary to achieve the desired linear and angular motion
	// Adapted from:
	// https://code.google.com/p/differential-drive/source/browse/nodes/twist_to_motors.py
	// self.right = 1.0 * self.dx + self.dr * self.w / 2
	// self.left = 1.0 * self.dx - self.dr * self.w / 2
	double vLeft  = msg.linear.x - msg.angular.z * WHEEL_DISTANCE / (2.0);
	double vRight = msg.linear.x + msg.angular.z * WHEEL_DISTANCE / (2.0);
	double vRotLeft = msg.angular.y;
	double vRotRight = msg.angular.y;

	// Only send new commands to the Arduino if the input actually changed
	if(vLeft == vLeftLast && vRight == vRightLast
		&& vRotLeft == vRotLeftLast && vRotRight == vRotRightLast) {
		return;
	}
	vLeftLast     = vLeft;
	vRightLast    = vRight;
	vRotLeftLast  = vRotLeft;
	vRotRightLast = vRotLeft;

	// ROS_INFO("tl: %f tr: %f z: %f", vLeft, vRight, msg.angular.z);
	// Determine rotation directions
	char dLeft  = vLeft  > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;
	char dRight = vRight > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;

	// Map [-MAX_DRV_SPEED, MAX_DRV_SPEED] -> [0, 1] as we've extracted the directional component
	vLeft  = vLeft  < 0 ? vLeft  * -1.0 : vLeft;
	vRight = vRight < 0 ? vRight * -1.0 : vRight;
	vLeft  = min(1.0, max(0.0, vLeft  / MAX_DRV_SPEED));
	vRight = min(1.0, max(0.0, vRight / MAX_DRV_SPEED));
	// Stop the motors when stopping
	if(vLeft < STOP_THRESHOLD) {
		dLeft = MOTOR_STOP;
	}
	if(vRight < STOP_THRESHOLD) {
		dRight = MOTOR_STOP;
	}
	// Apply!
	setDrive(MOTOR_LEFT, dLeft, vLeft);
	setDrive(MOTOR_RIGHT, dRight, vRight);

	// Wheel disc rotation
	// Extract direction
	char dRotLeft = vRotLeft > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;
	char dRotRight = vRotRight > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;
	// Map speeds to [0, 1]
	vRotLeft  = vRotLeft < 0 ? vRotLeft * -1.0 : vRotLeft;
	vRotRight = vRotRight < 0 ? vRotRight * -1.0 : vRotRight;
	vRotLeft  = min(1.0, max(0.0, vRotLeft  / MAX_ROT_SPEED));
	vRotRight = min(1.0, max(0.0, vRotRight / MAX_ROT_SPEED));
	if(vRotLeft < STOP_THRESHOLD) {
		dRotLeft = MOTOR_STOP;
	}
	if(vRotRight < STOP_THRESHOLD) {
		dRotRight = MOTOR_STOP;
	}
	setRotation(MOTOR_LEFT, dRotLeft, vRotLeft);
	setRotation(MOTOR_RIGHT, dRotRight, vRotRight);
}

void publishOdometry(const ros::TimerEvent&) {
// 	// Source: http://wiki.ros.org/navigation/Tutorials/RobotSetup/Odom
// 	// Store odometry input values
	vx = (vLeftCur + vRightCur) / 2.0;
	// vtheta = (vRight - vLeft) / WHEEL_OFFSET;

	// Compute input values
	double dt = (currentTime - lastTime).toSec();
	lastTime = currentTime;
	currentTime = ros::Time::now();
	double dx = (vx * cos(theta) - vy * sin(theta)) * dt;
	double dy = (vx * sin(theta) - vy * cos(theta)) * dt;
	vtheta = (dx - dy) / WHEEL_DISTANCE;
	double dtheta = vtheta * dt;
	x += dx;
	y += dy;
	theta += dtheta;
	// ROS_INFO("vl: %f vr: %f vx: %f vtheta: %f", vLeftCur, vRightCur, vx, vtheta);

	// Transform frame
	//since all odometry is 6DOF we'll need a quaternion created from yaw
	geometry_msgs::Quaternion odomQuat = tf::createQuaternionMsgFromYaw(theta);

	geometry_msgs::TransformStamped odomTrans;
	odomTrans.header.stamp = currentTime;
	odomTrans.header.frame_id = "odom";
	odomTrans.child_frame_id = "base_link";

	odomTrans.transform.translation.x = x;
	odomTrans.transform.translation.y = y;
	odomTrans.transform.translation.z = 0.0;
	odomTrans.transform.rotation = odomQuat;

	odomBroadcaster->sendTransform(odomTrans);

	// Odometry message
	nav_msgs::Odometry odom;
	odom.header.stamp = currentTime;
	odom.header.frame_id = "odom";

	//set the position
	odom.pose.pose.position.x = x;
	odom.pose.pose.position.y = y;
	odom.pose.pose.position.z = 0.0;
	odom.pose.pose.orientation = odomQuat;

	//set the velocity
	odom.child_frame_id = "base_link";
	odom.twist.twist.linear.x = vx;
	odom.twist.twist.linear.y = vy;
	odom.twist.twist.angular.z = vtheta;

	odomPub.publish(odom);

	// Test TF
	// This circumvents problems that might be introduced because static_transform_publisher
	// seems to offset its transforms into the future.
	// <node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.1 0.1 0.15 0.0 0.0 0.0 /base_link /laser 50" />
	geometry_msgs::Quaternion laserQuat = tf::createQuaternionMsgFromYaw(0.0);
	geometry_msgs::TransformStamped laserTrans;
	laserTrans.header.stamp = ros::Time::now();
	laserTrans.header.frame_id = "base_link";
	laserTrans.child_frame_id = "laser";
	laserTrans.transform.translation.x = 0.1;
	laserTrans.transform.translation.y = 0.1;
	laserTrans.transform.translation.z = 0.15;
	laserTrans.transform.rotation = laserQuat;
	odomBroadcaster->sendTransform(laserTrans);
}

int main(int argc, char **argv) {
	ros::init(argc, argv, "enginecontrol");
	ros::NodeHandle n;
	currentTime = ros::Time::now();
	lastTime = ros::Time::now();
	if(!initTty()) {
		return 1;
	}

	// Just to make sure we're not going anywhere...
	setDrive(MOTOR_LEFT, MOTOR_STOP);
	setDrive(MOTOR_RIGHT, MOTOR_STOP);
	setRotation(MOTOR_LEFT, MOTOR_STOP);
	setRotation(MOTOR_RIGHT, MOTOR_STOP);

	// This is correct - we're borrowing the turtle's topics
	ros::Subscriber sub = n.subscribe("cmd_vel", 1, velocityCallback);
	odomPub = n.advertise<nav_msgs::Odometry>("odom", 50);
	odomBroadcaster = boost::make_shared<tf::TransformBroadcaster>();
	//ros::Timer odoTimer = n.createTimer(ros::Duration(1.0/10.0/*10 Hz*/), publishOdometry);
	ROS_INFO("enginecontrol up and running.");
	ros::spin();
	close(tty);
	return 0;
}
<commit_msg>enginecontrol: disabled odom publisher<commit_after>#include "constants.hpp"
#include <string>
#include <math.h>
#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <nav_msgs/Odometry.h>
#include <tf/transform_broadcaster.h>
#include <boost/shared_ptr.hpp>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include <sstream>
#include <limits>

using namespace std;

// A serial interface used to send commands to the Arduino that controls
// the motor controllers. (Yeah, recursion!)
// (C file descriptor)
int tty;
std::stringstream ss;

// for odometry
ros::Time currentTime;
ros::Time lastTime;
ros::Publisher odomPub;
boost::shared_ptr<tf::TransformBroadcaster> odomBroadcaster;
double x = 0;
double y = 0;
double theta = 0;
double vx = 0;
double vy = 0;
double vtheta = 0;
// Make current speeds always available (and query them only once per cycle)
double vLeftCur  = 0.0;
double vRightCur = 0.0;
// Cache speeds to only send data if they change
double vLeftLast     = 0.0;
double vRightLast    = 0.0;
double vRotLeftLast  = 0.0;
double vRotRightLast = 0.0;

// Used to form the Arduino commands
const char MOTOR_LEFT = 'l';
const char MOTOR_RIGHT = 'r';
const char MOTOR_FORWARD = 'f';
const char MOTOR_BACKWARD = 'b';
const char MOTOR_STOP = 's';

// The motors are stopped (not just set to speed 0.0) below this input speed.
const float STOP_THRESHOLD = 0.01f;

bool initTty()
{
	// http://timmurphy.org/2009/08/04/baud-rate-and-other-serial-comm-settings-in-c/
	tty = open("/dev/ttyACM0", O_RDWR | O_NOCTTY/* | O_NDELAY*/);
	if(tty < 0) {
		perror("open(\"/dev/ttyACM0\")");
		return false;
	}
	struct termios settings;
	tcgetattr(tty, &settings);
	cfsetospeed(&settings, B115200);
	cfsetispeed(&settings, B0 /*same as output*/);
	settings.c_cflag &= ~PARENB;	// no parity
	settings.c_cflag &= ~CSTOPB;	// one stop bit
	settings.c_cflag &= ~CSIZE;		// 8 bits per character
	settings.c_cflag |= CS8;
	settings.c_cflag &= ~CRTSCTS;	// Disable hardware flow control
	// settings.c_cflag &= ~HUPCL;		// Send modem disconnect when closing the fd
	settings.c_cflag |= CREAD;		// Enable receiver
	// settings.c_cflag |= CLOCAL;		// Ignore modem status lines
	settings.c_iflag &= ~(IXON | IXOFF | IXANY); // Disable start/stop I/O control
	settings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // Disable user terminal features
	settings.c_oflag &= ~OPOST;		// Disable output postprocessing
	settings.c_cc[VMIN]  = 0;
	settings.c_cc[VTIME] = 0;
	if(tcsetattr(tty, TCSANOW, &settings) != 0) {
		perror("tcsetattr");
		return false;
	}
	tcflush(tty, TCOFLUSH);
	return true;
}

int readLine(char* const line, const ssize_t LINE_LENGTH)
{
	ssize_t bytesRead = 0;
	bool lineComplete = false;
	while(!lineComplete && bytesRead < LINE_LENGTH) {
		// Read bytes into temporary buffer
		char buffer[LINE_LENGTH];
		// ROS_INFO("a");
		ssize_t newBytesRead = read(tty, buffer, LINE_LENGTH);
		// ROS_INFO("b");
		if(newBytesRead < 0) {
			perror("read");
		}
		// Copy new bytes to 'line'
		for(ssize_t i = 0; i < newBytesRead && bytesRead < LINE_LENGTH; i++, bytesRead++) {
			line[bytesRead] = buffer[i];
			if(buffer[i] == '\n') {
				lineComplete = true;
			}
		}
	}
	return bytesRead;
}

void setDrive(const char motor, const char direction, const float spd = 0.0f)
{
	ss.str("");
	ss << "sd" << motor << direction;
	if(direction != MOTOR_STOP) {
		ss << std::hex << (int8_t)(spd * 255);
	}
	ss << std::endl;
	const char* output = ss.str().c_str();
	write(tty, output, ss.str().length());
	// ROS_INFO("%s", output);
	// check response
	char line[2];
	const int lineLength = readLine(line, 2);
	if(atoi(line) != 0) {
		ROS_INFO("Command failed: %s", output);
	}
}

void setRotation(const char motor, const char direction, const float spd = 0.0f)
{
	ss.str("");
	ss << "sr" << motor << direction;
	if(direction != MOTOR_STOP) {
		ss << std::hex << (int8_t)(spd * 255);
	}
	ss << std::endl;
	const char* output = ss.str().c_str();
	write(tty, output, ss.str().length());
	// check response
	char line[2];
	const int lineLength = readLine(line, 2);
	if(atoi(line) != 0) {
		ROS_INFO("Command failed: %s", output);
	}
}

/*
 * Returns the speed in m/s the given motor is moving the robot at.
 */
float getSpeed(const char motor)
{
	// Write command
	ss.str("");
	// "get drive left/right rate"
	ss << "gd" << motor << 'r' << std::endl;
	const char* output = ss.str().c_str();
	write(tty, output, ss.str().length());
	// ROS_INFO("%s", ss.str().c_str());

	// Read response
	// Expected: max. 11 characters (-2,147,483,647) + \n
	const int LINE_LENGTH = 11;
	char line[LINE_LENGTH] = {0};
	const int lineLength = readLine(line, LINE_LENGTH);

	// We receive the interval in µs bewtween two motor monitor ticks
	const int interval = atoi(line);
	// Compute motor revolution freq (Hz) from motor tick interval (µs)
	// Filter out division by zero and "stop" state
	const double freq = (interval == 0 || interval == 1000000) ? 0 : 1000000 / interval;
	// if(motor == MOTOR_RIGHT)
		// ROS_INFO("interval %c: %i freq: %f", motor, interval, freq);
	// Return the resulting robot speed for this motor (m/s)
	return freq * WHEEL_DIAMETER * M_PI / (3.0 * WHEEL_REDUCTION);
}

void velocityCallback(const geometry_msgs::Twist& msg) {
	// Store current motor speeds for later reference
	vLeftCur   = getSpeed(MOTOR_LEFT);
	vRightCur  = getSpeed(MOTOR_RIGHT);

	// Compute the motor speeds necessary to achieve the desired linear and angular motion
	// Adapted from:
	// https://code.google.com/p/differential-drive/source/browse/nodes/twist_to_motors.py
	// self.right = 1.0 * self.dx + self.dr * self.w / 2
	// self.left = 1.0 * self.dx - self.dr * self.w / 2
	double vLeft  = msg.linear.x - msg.angular.z * WHEEL_DISTANCE / (2.0);
	double vRight = msg.linear.x + msg.angular.z * WHEEL_DISTANCE / (2.0);
	double vRotLeft = msg.angular.y;
	double vRotRight = msg.angular.y;

	// Only send new commands to the Arduino if the input actually changed
	if(vLeft == vLeftLast && vRight == vRightLast
		&& vRotLeft == vRotLeftLast && vRotRight == vRotRightLast) {
		return;
	}
	vLeftLast     = vLeft;
	vRightLast    = vRight;
	vRotLeftLast  = vRotLeft;
	vRotRightLast = vRotLeft;

	// ROS_INFO("tl: %f tr: %f z: %f", vLeft, vRight, msg.angular.z);
	// Determine rotation directions
	char dLeft  = vLeft  > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;
	char dRight = vRight > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;

	// Map [-MAX_DRV_SPEED, MAX_DRV_SPEED] -> [0, 1] as we've extracted the directional component
	vLeft  = vLeft  < 0 ? vLeft  * -1.0 : vLeft;
	vRight = vRight < 0 ? vRight * -1.0 : vRight;
	vLeft  = min(1.0, max(0.0, vLeft  / MAX_DRV_SPEED));
	vRight = min(1.0, max(0.0, vRight / MAX_DRV_SPEED));
	// Stop the motors when stopping
	if(vLeft < STOP_THRESHOLD) {
		dLeft = MOTOR_STOP;
	}
	if(vRight < STOP_THRESHOLD) {
		dRight = MOTOR_STOP;
	}
	// Apply!
	setDrive(MOTOR_LEFT, dLeft, vLeft);
	setDrive(MOTOR_RIGHT, dRight, vRight);

	// Wheel disc rotation
	// Extract direction
	char dRotLeft = vRotLeft > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;
	char dRotRight = vRotRight > 0 ? MOTOR_FORWARD : MOTOR_BACKWARD;
	// Map speeds to [0, 1]
	vRotLeft  = vRotLeft < 0 ? vRotLeft * -1.0 : vRotLeft;
	vRotRight = vRotRight < 0 ? vRotRight * -1.0 : vRotRight;
	vRotLeft  = min(1.0, max(0.0, vRotLeft  / MAX_ROT_SPEED));
	vRotRight = min(1.0, max(0.0, vRotRight / MAX_ROT_SPEED));
	if(vRotLeft < STOP_THRESHOLD) {
		dRotLeft = MOTOR_STOP;
	}
	if(vRotRight < STOP_THRESHOLD) {
		dRotRight = MOTOR_STOP;
	}
	setRotation(MOTOR_LEFT, dRotLeft, vRotLeft);
	setRotation(MOTOR_RIGHT, dRotRight, vRotRight);
}

void publishOdometry(const ros::TimerEvent&) {
// 	// Source: http://wiki.ros.org/navigation/Tutorials/RobotSetup/Odom
// 	// Store odometry input values
	vx = (vLeftCur + vRightCur) / 2.0;
	// vtheta = (vRight - vLeft) / WHEEL_OFFSET;

	// Compute input values
	double dt = (currentTime - lastTime).toSec();
	lastTime = currentTime;
	currentTime = ros::Time::now();
	double dx = (vx * cos(theta) - vy * sin(theta)) * dt;
	double dy = (vx * sin(theta) - vy * cos(theta)) * dt;
	vtheta = (dx - dy) / WHEEL_DISTANCE;
	double dtheta = vtheta * dt;
	x += dx;
	y += dy;
	theta += dtheta;
	// ROS_INFO("vl: %f vr: %f vx: %f vtheta: %f", vLeftCur, vRightCur, vx, vtheta);

	// Transform frame
	//since all odometry is 6DOF we'll need a quaternion created from yaw
	geometry_msgs::Quaternion odomQuat = tf::createQuaternionMsgFromYaw(theta);

	geometry_msgs::TransformStamped odomTrans;
	odomTrans.header.stamp = currentTime;
	odomTrans.header.frame_id = "odom";
	odomTrans.child_frame_id = "base_link";

	odomTrans.transform.translation.x = x;
	odomTrans.transform.translation.y = y;
	odomTrans.transform.translation.z = 0.0;
	odomTrans.transform.rotation = odomQuat;

	odomBroadcaster->sendTransform(odomTrans);

	// Odometry message
	nav_msgs::Odometry odom;
	odom.header.stamp = currentTime;
	odom.header.frame_id = "odom";

	//set the position
	odom.pose.pose.position.x = x;
	odom.pose.pose.position.y = y;
	odom.pose.pose.position.z = 0.0;
	odom.pose.pose.orientation = odomQuat;

	//set the velocity
	odom.child_frame_id = "base_link";
	odom.twist.twist.linear.x = vx;
	odom.twist.twist.linear.y = vy;
	odom.twist.twist.angular.z = vtheta;

	odomPub.publish(odom);

	// Test TF
	// This circumvents problems that might be introduced because static_transform_publisher
	// seems to offset its transforms into the future.
	// <node pkg="tf" type="static_transform_publisher" name="base_link_to_laser" args="0.1 0.1 0.15 0.0 0.0 0.0 /base_link /laser 50" />
	geometry_msgs::Quaternion laserQuat = tf::createQuaternionMsgFromYaw(0.0);
	geometry_msgs::TransformStamped laserTrans;
	laserTrans.header.stamp = ros::Time::now();
	laserTrans.header.frame_id = "base_link";
	laserTrans.child_frame_id = "laser";
	laserTrans.transform.translation.x = 0.1;
	laserTrans.transform.translation.y = 0.1;
	laserTrans.transform.translation.z = 0.15;
	laserTrans.transform.rotation = laserQuat;
	odomBroadcaster->sendTransform(laserTrans);
}

int main(int argc, char **argv) {
	ros::init(argc, argv, "enginecontrol");
	ros::NodeHandle n;
	currentTime = ros::Time::now();
	lastTime = ros::Time::now();
	if(!initTty()) {
		return 1;
	}

	// Just to make sure we're not going anywhere...
	setDrive(MOTOR_LEFT, MOTOR_STOP);
	setDrive(MOTOR_RIGHT, MOTOR_STOP);
	setRotation(MOTOR_LEFT, MOTOR_STOP);
	setRotation(MOTOR_RIGHT, MOTOR_STOP);

	// This is correct - we're borrowing the turtle's topics
	ros::Subscriber sub = n.subscribe("cmd_vel", 1, velocityCallback);
	//odomPub = n.advertise<nav_msgs::Odometry>("odom", 50);
	//odomBroadcaster = boost::make_shared<tf::TransformBroadcaster>();
	//ros::Timer odoTimer = n.createTimer(ros::Duration(1.0/10.0/*10 Hz*/), publishOdometry);
	ROS_INFO("enginecontrol up and running.");
	ros::spin();
	close(tty);
	return 0;
}
<|endoftext|>


<commit_before>#include <cmath>
#include <ctime>
#include <iostream>
#include <fstream>

#include <util/PlatformUtils.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>

#include <DOMSupport/DOMSupportDefault.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPath.hpp>
#include <XPath/XPathSupportDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

#include <XercesParserLiaison/XercesParserLiaison.hpp>

#include <XercesPlatformSupport/TextFileOutputStream.hpp>
#include <XercesPlatformSupport/XercesDOMPrintWriter.hpp>

// This class defines a function that will return the square root
// of its argument.
class FunctionSquareRoot : public Function
{
public:

	/**
	 * Execute an XPath function object.  The function must return a valid
	 * object.
	 *
	 * @param executionContext executing context
	 * @param context          current context node
	 * @param opPos            current op position
	 * @param args             vector of pointers to XObject arguments
	 * @return                 pointer to the result XObject
	 */
	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								opPos,
			const XObjectArgVectorType&		args)
	{
		if (args.size() != 1)
		{
			executionContext.error("The square-root() function takes one argument!", context);
		}

		assert(args[0] != 0);

		return executionContext.getXObjectFactory().createNumber(sqrt(args[0]->num()));
	}

	/**
	 * Create a copy of the function object.
	 *
	 * @return pointer to the new object
	 */
#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionSquareRoot*
#endif
	clone() const
	{
		return new FunctionSquareRoot(*this);
	}

private:

	// Not implemented...
	FunctionSquareRoot&
	operator=(const FunctionSquareRoot&);

	bool
	operator==(const FunctionSquareRoot&) const;
};

// This class defines a function that will return the cube
// of its argument.
class FunctionCube : public Function
{
public:

	/**
	 * Execute an XPath function object.  The function must return a valid
	 * object.
	 *
	 * @param executionContext executing context
	 * @param context          current context node
	 * @param opPos            current op position
	 * @param args             vector of pointers to XObject arguments
	 * @return                 pointer to the result XObject
	 */
	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								opPos,
			const XObjectArgVectorType&		args)
	{
		if (args.size() != 1)
		{
			executionContext.error("The cube() function takes one argument!", context);
		}

		assert(args[0] != 0);

		return executionContext.getXObjectFactory().createNumber(pow(args[0]->num(), 3));
	}

	/**
	 * Create a copy of the function object.
	 *
	 * @return pointer to the new object
	 */
#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionCube*
#endif
	clone() const
	{
		return new FunctionCube(*this);
	}

private:

	// Not implemented...
	FunctionCube&
	operator=(const FunctionCube&);

	bool
	operator==(const FunctionCube&) const;
};

// This class defines a function that runs the C function
// asctime() using the current system time.
class FunctionAsctime : public Function
{
public:

	/**
	 * Execute an XPath function object.  The function must return a valid
	 * object.
	 *
	 * @param executionContext executing context
	 * @param context          current context node
	 * @param opPos            current op position
	 * @param args             vector of pointers to XObject arguments
	 * @return                 pointer to the result XObject
	 */
	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								opPos,
			const XObjectArgVectorType&		args)
	{
		if (args.size() != 0)
		{
			executionContext.error("The asctime() function takes no arguments!", context);
		}

		time_t	theTime;

		time(&theTime);

		char* const	theTimeString = asctime(localtime(&theTime));

		// The resulting string has a newline character at the end,
		// so get rid of it.
		theTimeString[strlen(theTimeString) - 1] = '\0';

		return executionContext.getXObjectFactory().createString(XalanDOMString(theTimeString));
	}

	/**
	 * Create a copy of the function object.
	 *
	 * @return pointer to the new object
	 */
#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionAsctime*
#endif
	clone() const
	{
		return new FunctionAsctime(*this);
	}

private:

	// Not implemented...
	FunctionAsctime&
	operator=(const FunctionAsctime&);

	bool
	operator==(const FunctionAsctime&) const;
};

int
main(
			int				argc,
			const char*		/* argv */[])
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::endl;
	using std::ofstream;
#endif

	if (argc != 1)
	{
		cerr << "Usage: ExternalFunction"
			 << endl
			 << endl;
	}
	else
	{
		try
		{
			// Call the static initializers...
			XMLPlatformUtils::Initialize();
			XSLTEngineImpl::Initialize();

			// Create the support objects that are necessary for running the processor...
			DOMSupportDefault				theDOMSupport;
			XercesParserLiaison				theParserLiaison(theDOMSupport);
			XPathSupportDefault				theXPathSupport(theDOMSupport);
			XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
			XObjectFactoryDefault			theXObjectFactory(theXSLTProcessorEnvSupport, theXPathSupport);
			XPathFactoryDefault				theXPathFactory;

			// Create a processor...
			XSLTEngineImpl	theProcessor(
					theParserLiaison,
					theXPathSupport,
					theXSLTProcessorEnvSupport,
					theXObjectFactory,
					theXPathFactory);

			// Connect the processor to the support object...
			theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

			// Create a stylesheet construction context, and a stylesheet
			// execution context...
			StylesheetConstructionContextDefault	theConstructionContext(
						theProcessor,
						theXSLTProcessorEnvSupport,
						theXObjectFactory,
						theXPathFactory);

			StylesheetExecutionContextDefault		theExecutionContext(
						theProcessor,
						theXSLTProcessorEnvSupport,
						theXPathSupport,
						theXObjectFactory);

			// Our input files...
			// WARNING!!! You may need to modify these absolute paths depending on where
			// you've put the Xalan sources.
			const XalanDOMString		theXMLFileName("foo.xml");
			const XalanDOMString		theXSLFileName("foo.xsl");

			// Our input sources...
			XSLTInputSource		theInputSource(c_wstr(theXMLFileName));
			XSLTInputSource		theStylesheetSource(c_wstr(theXSLFileName));

			// Our output target...
			TextFileOutputStream	theOutputStream("foo.out");
			XercesDOMPrintWriter	theResultWriter(theOutputStream);
			XSLTResultTarget		theResultTarget(&theResultWriter);

			// Install the function directly into the XPath
			// function table.  We don't recommend doing this,
			// but you can if you want to be evil! ;-)  Since
			// the function is in the XPath table, the XPath
			// parser will treat it like any other XPath
			// function.  Therefore, it cannot have a namespace
			// prefix.  It will also be available to every
			// processor in the executable's process, since there
			// is one static XPath function table.
			XPath::installFunction(
				"asctime",
				FunctionAsctime());

			// The namespace for our functions...
			const XalanDOMString	theNamespace("http://ExternalFunction.xalan-c++.xml.apache.org");

			// Install the function in the global space.  All
			// instances will know about the function, so all
			// processors which use an instance of this the
			// class XPathEnvSupportDefault will be able to
			// use the function.
			XSLTProcessorEnvSupportDefault::installExternalFunctionGlobal(
				theNamespace,
				"square-root",
				FunctionSquareRoot());

			// Install the function in the local space.  It will only
			// be installed in this instance, so no other instances
			// will know about the function...
			theXSLTProcessorEnvSupport.installExternalFunctionLocal(
				theNamespace,
				"cube",
				FunctionCube());

			theProcessor.process(
						theInputSource,
						theStylesheetSource,
						theResultTarget,
						theConstructionContext,
						theExecutionContext);
		}
		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}
	}

	return 0;
}
<commit_msg>Commented out unused formal parameters.<commit_after>#include <cmath>
#include <ctime>
#include <iostream>
#include <fstream>

#include <util/PlatformUtils.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>

#include <DOMSupport/DOMSupportDefault.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPath.hpp>
#include <XPath/XPathSupportDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

#include <XercesParserLiaison/XercesParserLiaison.hpp>

#include <XercesPlatformSupport/TextFileOutputStream.hpp>
#include <XercesPlatformSupport/XercesDOMPrintWriter.hpp>

// This class defines a function that will return the square root
// of its argument.
class FunctionSquareRoot : public Function
{
public:

	/**
	 * Execute an XPath function object.  The function must return a valid
	 * object.
	 *
	 * @param executionContext executing context
	 * @param context          current context node
	 * @param opPos            current op position
	 * @param args             vector of pointers to XObject arguments
	 * @return                 pointer to the result XObject
	 */
	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								/* opPos */,
			const XObjectArgVectorType&		args)
	{
		if (args.size() != 1)
		{
			executionContext.error("The square-root() function takes one argument!", context);
		}

		assert(args[0] != 0);

		return executionContext.getXObjectFactory().createNumber(sqrt(args[0]->num()));
	}

	/**
	 * Create a copy of the function object.
	 *
	 * @return pointer to the new object
	 */
#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionSquareRoot*
#endif
	clone() const
	{
		return new FunctionSquareRoot(*this);
	}

private:

	// Not implemented...
	FunctionSquareRoot&
	operator=(const FunctionSquareRoot&);

	bool
	operator==(const FunctionSquareRoot&) const;
};

// This class defines a function that will return the cube
// of its argument.
class FunctionCube : public Function
{
public:

	/**
	 * Execute an XPath function object.  The function must return a valid
	 * object.
	 *
	 * @param executionContext executing context
	 * @param context          current context node
	 * @param opPos            current op position
	 * @param args             vector of pointers to XObject arguments
	 * @return                 pointer to the result XObject
	 */
	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								/* opPos */,
			const XObjectArgVectorType&		args)
	{
		if (args.size() != 1)
		{
			executionContext.error("The cube() function takes one argument!", context);
		}

		assert(args[0] != 0);

		return executionContext.getXObjectFactory().createNumber(pow(args[0]->num(), 3));
	}

	/**
	 * Create a copy of the function object.
	 *
	 * @return pointer to the new object
	 */
#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionCube*
#endif
	clone() const
	{
		return new FunctionCube(*this);
	}

private:

	// Not implemented...
	FunctionCube&
	operator=(const FunctionCube&);

	bool
	operator==(const FunctionCube&) const;
};

// This class defines a function that runs the C function
// asctime() using the current system time.
class FunctionAsctime : public Function
{
public:

	/**
	 * Execute an XPath function object.  The function must return a valid
	 * object.
	 *
	 * @param executionContext executing context
	 * @param context          current context node
	 * @param opPos            current op position
	 * @param args             vector of pointers to XObject arguments
	 * @return                 pointer to the result XObject
	 */
	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								/* opPos */,
			const XObjectArgVectorType&		args)
	{
		if (args.size() != 0)
		{
			executionContext.error("The asctime() function takes no arguments!", context);
		}

		time_t	theTime;

		time(&theTime);

		char* const	theTimeString = asctime(localtime(&theTime));

		// The resulting string has a newline character at the end,
		// so get rid of it.
		theTimeString[strlen(theTimeString) - 1] = '\0';

		return executionContext.getXObjectFactory().createString(XalanDOMString(theTimeString));
	}

	/**
	 * Create a copy of the function object.
	 *
	 * @return pointer to the new object
	 */
#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionAsctime*
#endif
	clone() const
	{
		return new FunctionAsctime(*this);
	}

private:

	// Not implemented...
	FunctionAsctime&
	operator=(const FunctionAsctime&);

	bool
	operator==(const FunctionAsctime&) const;
};

int
main(
			int				argc,
			const char*		/* argv */[])
{
#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::endl;
	using std::ofstream;
#endif

	if (argc != 1)
	{
		cerr << "Usage: ExternalFunction"
			 << endl
			 << endl;
	}
	else
	{
		try
		{
			// Call the static initializers...
			XMLPlatformUtils::Initialize();
			XSLTEngineImpl::Initialize();

			// Create the support objects that are necessary for running the processor...
			DOMSupportDefault				theDOMSupport;
			XercesParserLiaison				theParserLiaison(theDOMSupport);
			XPathSupportDefault				theXPathSupport(theDOMSupport);
			XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
			XObjectFactoryDefault			theXObjectFactory(theXSLTProcessorEnvSupport, theXPathSupport);
			XPathFactoryDefault				theXPathFactory;

			// Create a processor...
			XSLTEngineImpl	theProcessor(
					theParserLiaison,
					theXPathSupport,
					theXSLTProcessorEnvSupport,
					theXObjectFactory,
					theXPathFactory);

			// Connect the processor to the support object...
			theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

			// Create a stylesheet construction context, and a stylesheet
			// execution context...
			StylesheetConstructionContextDefault	theConstructionContext(
						theProcessor,
						theXSLTProcessorEnvSupport,
						theXObjectFactory,
						theXPathFactory);

			StylesheetExecutionContextDefault		theExecutionContext(
						theProcessor,
						theXSLTProcessorEnvSupport,
						theXPathSupport,
						theXObjectFactory);

			// Our input files...
			// WARNING!!! You may need to modify these absolute paths depending on where
			// you've put the Xalan sources.
			const XalanDOMString		theXMLFileName("foo.xml");
			const XalanDOMString		theXSLFileName("foo.xsl");

			// Our input sources...
			XSLTInputSource		theInputSource(c_wstr(theXMLFileName));
			XSLTInputSource		theStylesheetSource(c_wstr(theXSLFileName));

			// Our output target...
			TextFileOutputStream	theOutputStream("foo.out");
			XercesDOMPrintWriter	theResultWriter(theOutputStream);
			XSLTResultTarget		theResultTarget(&theResultWriter);

			// Install the function directly into the XPath
			// function table.  We don't recommend doing this,
			// but you can if you want to be evil! ;-)  Since
			// the function is in the XPath table, the XPath
			// parser will treat it like any other XPath
			// function.  Therefore, it cannot have a namespace
			// prefix.  It will also be available to every
			// processor in the executable's process, since there
			// is one static XPath function table.
			XPath::installFunction(
				"asctime",
				FunctionAsctime());

			// The namespace for our functions...
			const XalanDOMString	theNamespace("http://ExternalFunction.xalan-c++.xml.apache.org");

			// Install the function in the global space.  All
			// instances will know about the function, so all
			// processors which use an instance of this the
			// class XPathEnvSupportDefault will be able to
			// use the function.
			XSLTProcessorEnvSupportDefault::installExternalFunctionGlobal(
				theNamespace,
				"square-root",
				FunctionSquareRoot());

			// Install the function in the local space.  It will only
			// be installed in this instance, so no other instances
			// will know about the function...
			theXSLTProcessorEnvSupport.installExternalFunctionLocal(
				theNamespace,
				"cube",
				FunctionCube());

			theProcessor.process(
						theInputSource,
						theStylesheetSource,
						theResultTarget,
						theConstructionContext,
						theExecutionContext);
		}
		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <jni.h>
#include <string>
#include <vector>

#include "AudioEngine.h"

AudioEngine *engine;

std::vector<int> convertJavaArrayToVector(JNIEnv *env, jintArray intArray){

    std::vector<int> v;
    jsize length = env->GetArrayLength(intArray);

    if (length > 0) {
        jboolean isCopy;
        jint *elements = env->GetIntArrayElements(intArray, &isCopy);
        for (int i = 0; i < length; i++) {
            v.push_back(elements[i]);
        }
    }
    return v;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_oboe_megadrone_MainActivity_startEngine(JNIEnv *env, jobject instance,
                                                         jintArray jCpuIds) {
    engine = new AudioEngine;
    std::vector<int> cpuIds = convertJavaArrayToVector(env, jCpuIds);
    engine->start(cpuIds);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_oboe_megadrone_MainActivity_stopEngine(JNIEnv *env, jobject instance) {

    engine->stop();
    delete engine;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_oboe_megadrone_MainActivity_tap(JNIEnv *env, jobject instance, jboolean b) {

    engine->tap(b);
}<commit_msg>Changing engine to be a unique_ptr<commit_after>/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <jni.h>
#include <string>
#include <vector>

#include "AudioEngine.h"

std::unique_ptr<AudioEngine> engine;

std::vector<int> convertJavaArrayToVector(JNIEnv *env, jintArray intArray){

    std::vector<int> v;
    jsize length = env->GetArrayLength(intArray);

    if (length > 0) {
        jboolean isCopy;
        jint *elements = env->GetIntArrayElements(intArray, &isCopy);
        for (int i = 0; i < length; i++) {
            v.push_back(elements[i]);
        }
    }
    return v;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_oboe_megadrone_MainActivity_startEngine(JNIEnv *env, jobject instance,
                                                         jintArray jCpuIds) {
    engine = std::make_unique<AudioEngine>();
    std::vector<int> cpuIds = convertJavaArrayToVector(env, jCpuIds);
    engine->start(cpuIds);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_oboe_megadrone_MainActivity_stopEngine(JNIEnv *env, jobject instance) {

    engine->stop();
}

extern "C"
JNIEXPORT void JNICALL
Java_com_example_oboe_megadrone_MainActivity_tap(JNIEnv *env, jobject instance, jboolean b) {

    engine->tap(b);
}<|endoftext|>