<commit_before>/****************************************************************************
 *
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "ADSBVehicleManager.h"
#include "QGCLoggingCategory.h"
#include "QGCApplication.h"
#include "SettingsManager.h"
#include "ADSBVehicleManagerSettings.h"

#include <QDebug>

ADSBVehicleManager::ADSBVehicleManager(QGCApplication* app, QGCToolbox* toolbox)
    : QGCTool(app, toolbox)
{
}

void ADSBVehicleManager::setToolbox(QGCToolbox* toolbox)
{
    QGCTool::setToolbox(toolbox);

    connect(&_adsbVehicleCleanupTimer, &QTimer::timeout, this, &ADSBVehicleManager::_cleanupStaleVehicles);
    _adsbVehicleCleanupTimer.setSingleShot(false);
    _adsbVehicleCleanupTimer.start(1000);

    ADSBVehicleManagerSettings* settings = qgcApp()->toolbox()->settingsManager()->adsbVehicleManagerSettings();
    if (settings->adsbServerConnectEnabled()->rawValue().toBool()) {
        _tcpLink = new ADSBTCPLink(settings->adsbServerHostAddress()->rawValue().toString(), settings->adsbServerPort()->rawValue().toInt(), this);
        connect(_tcpLink, &ADSBTCPLink::adsbVehicleUpdate,  this, &ADSBVehicleManager::adsbVehicleUpdate,   Qt::QueuedConnection);
        connect(_tcpLink, &ADSBTCPLink::error,              this, &ADSBVehicleManager::_tcpError,           Qt::QueuedConnection);
    }
}

void ADSBVehicleManager::_cleanupStaleVehicles()
{
    // Remove all expired ADSB vehicles
    for (int i=_adsbVehicles.count()-1; i>=0; i--) {
        ADSBVehicle* adsbVehicle = _adsbVehicles.value<ADSBVehicle*>(i);
        if (adsbVehicle->expired()) {
            qCDebug(ADSBVehicleManagerLog) << "Expired" << QStringLiteral("%1").arg(adsbVehicle->icaoAddress(), 0, 16);
            _adsbVehicles.removeAt(i);
            adsbVehicle->deleteLater();
        }
    }
}

void ADSBVehicleManager::adsbVehicleUpdate(const ADSBVehicle::VehicleInfo_t vehicleInfo)
{
    uint32_t icaoAddress = vehicleInfo.icaoAddress;

    if (_adsbICAOMap.contains(icaoAddress)) {
        _adsbICAOMap[icaoAddress]->update(vehicleInfo);
    } else {
        if (vehicleInfo.availableFlags & ADSBVehicle::LocationAvailable) {
            ADSBVehicle* adsbVehicle = new ADSBVehicle(vehicleInfo, this);
            _adsbICAOMap[icaoAddress] = adsbVehicle;
            _adsbVehicles.append(adsbVehicle);
        }
    }
}

void ADSBVehicleManager::_tcpError(const QString errorMsg)
{
    qgcApp()->showAppMessage(tr("ADSB Server Error: %1").arg(errorMsg));
}

ADSBTCPLink::ADSBTCPLink(const QString& hostAddress, int port, QObject* parent)
    : QThread       (parent)
    , _hostAddress  (hostAddress)
    , _port         (port)
{
    moveToThread(this);
    start();
}

ADSBTCPLink::~ADSBTCPLink(void)
{
    if (_socket) {
        _socket->disconnectFromHost();
        _socket->deleteLater();
        _socket = nullptr;
    }
    quit();
    wait();
}

void ADSBTCPLink::run(void)
{
    _hardwareConnect();
    exec();
}

void ADSBTCPLink::_hardwareConnect()
{
    _socket = new QTcpSocket();

    QObject::connect(_socket, &QTcpSocket::readyRead, this, &ADSBTCPLink::_readBytes);

    _socket->connectToHost(_hostAddress, static_cast<quint16>(_port));

    // Give the socket a second to connect to the other side otherwise error out
    if (!_socket->waitForConnected(1000)) {
        qCDebug(ADSBVehicleManagerLog) << "ADSB Socket failed to connect";
        emit error(_socket->errorString());
        delete _socket;
        _socket = nullptr;
        return;
    }

    qCDebug(ADSBVehicleManagerLog) << "ADSB Socket connected";
}

void ADSBTCPLink::_readBytes(void)
{
    if (_socket) {
        QByteArray bytes = _socket->readLine();
        _parseLine(QString::fromLocal8Bit(bytes));
    }
}

void ADSBTCPLink::_parseLine(const QString& line)
{
    if (line.startsWith(QStringLiteral("MSG"))) {
        qCDebug(ADSBVehicleManagerLog) << "ADSB SBS-1" << line;

        QStringList values = line.split(QStringLiteral(","));

        if (values[1] == QStringLiteral("3")) {
            bool icaoOk, altOk, latOk, lonOk;

            uint32_t    icaoAddress =   values[4].toUInt(&icaoOk, 16);
            int         modeCAltitude = values[11].toInt(&altOk);
            double      lat =           values[14].toDouble(&latOk);
            double      lon =           values[15].toDouble(&lonOk);
            QString     callsign =      values[10];

            if (!icaoOk || !altOk || !latOk || !lonOk) {
                return;
            }
            if (lat == 0 && lon == 0) {
                return;
            }

            double altitude = modeCAltitude / 3.048;
            QGeoCoordinate location(lat, lon);

            ADSBVehicle::VehicleInfo_t adsbInfo;
            adsbInfo.icaoAddress = icaoAddress;
            adsbInfo.callsign = callsign;
            adsbInfo.location = location;
            adsbInfo.altitude = altitude;
            adsbInfo.availableFlags = ADSBVehicle::CallsignAvailable | ADSBVehicle::LocationAvailable | ADSBVehicle::AltitudeAvailable;
            emit adsbVehicleUpdate(adsbInfo);
        } else if (values[1] == QStringLiteral("4")) {
            bool icaoOk, headingOk;

            uint32_t    icaoAddress =   values[4].toUInt(&icaoOk, 16);
            double      heading =       values[13].toDouble(&headingOk);

            if (!icaoOk || !headingOk) {
                return;
            }

            ADSBVehicle::VehicleInfo_t adsbInfo;
            adsbInfo.icaoAddress = icaoAddress;
            adsbInfo.heading = heading;
            adsbInfo.availableFlags = ADSBVehicle::HeadingAvailable;
            emit adsbVehicleUpdate(adsbInfo);
        } else if (values[1] == QStringLiteral("1")) {
            bool icaoOk;

            uint32_t icaoAddress = values[4].toUInt(&icaoOk, 16);
            if (!icaoOk) {
                return;
            }

            ADSBVehicle::VehicleInfo_t adsbInfo;
            adsbInfo.icaoAddress = icaoAddress;
            adsbInfo.callsign = values[10];
            adsbInfo.availableFlags = ADSBVehicle::CallsignAvailable;
            emit adsbVehicleUpdate(adsbInfo);
        }
    }
}
<commit_msg>Fix ADSB crash<commit_after>/****************************************************************************
 *
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

#include "ADSBVehicleManager.h"
#include "QGCLoggingCategory.h"
#include "QGCApplication.h"
#include "SettingsManager.h"
#include "ADSBVehicleManagerSettings.h"

#include <QDebug>

ADSBVehicleManager::ADSBVehicleManager(QGCApplication* app, QGCToolbox* toolbox)
    : QGCTool(app, toolbox)
{
}

void ADSBVehicleManager::setToolbox(QGCToolbox* toolbox)
{
    QGCTool::setToolbox(toolbox);

    connect(&_adsbVehicleCleanupTimer, &QTimer::timeout, this, &ADSBVehicleManager::_cleanupStaleVehicles);
    _adsbVehicleCleanupTimer.setSingleShot(false);
    _adsbVehicleCleanupTimer.start(1000);

    ADSBVehicleManagerSettings* settings = qgcApp()->toolbox()->settingsManager()->adsbVehicleManagerSettings();
    if (settings->adsbServerConnectEnabled()->rawValue().toBool()) {
        _tcpLink = new ADSBTCPLink(settings->adsbServerHostAddress()->rawValue().toString(), settings->adsbServerPort()->rawValue().toInt(), this);
        connect(_tcpLink, &ADSBTCPLink::adsbVehicleUpdate,  this, &ADSBVehicleManager::adsbVehicleUpdate,   Qt::QueuedConnection);
        connect(_tcpLink, &ADSBTCPLink::error,              this, &ADSBVehicleManager::_tcpError,           Qt::QueuedConnection);
    }
}

void ADSBVehicleManager::_cleanupStaleVehicles()
{
    // Remove all expired ADSB vehicles
    for (int i=_adsbVehicles.count()-1; i>=0; i--) {
        ADSBVehicle* adsbVehicle = _adsbVehicles.value<ADSBVehicle*>(i);
        if (adsbVehicle->expired()) {
            qCDebug(ADSBVehicleManagerLog) << "Expired" << QStringLiteral("%1").arg(adsbVehicle->icaoAddress(), 0, 16);
            _adsbVehicles.removeAt(i);
            _adsbICAOMap.remove(adsbVehicle->icaoAddress());
            adsbVehicle->deleteLater();
        }
    }
}

void ADSBVehicleManager::adsbVehicleUpdate(const ADSBVehicle::VehicleInfo_t vehicleInfo)
{
    uint32_t icaoAddress = vehicleInfo.icaoAddress;

    if (_adsbICAOMap.contains(icaoAddress)) {
        _adsbICAOMap[icaoAddress]->update(vehicleInfo);
    } else {
        if (vehicleInfo.availableFlags & ADSBVehicle::LocationAvailable) {
            ADSBVehicle* adsbVehicle = new ADSBVehicle(vehicleInfo, this);
            _adsbICAOMap[icaoAddress] = adsbVehicle;
            _adsbVehicles.append(adsbVehicle);
        }
    }
}

void ADSBVehicleManager::_tcpError(const QString errorMsg)
{
    qgcApp()->showAppMessage(tr("ADSB Server Error: %1").arg(errorMsg));
}

ADSBTCPLink::ADSBTCPLink(const QString& hostAddress, int port, QObject* parent)
    : QThread       (parent)
    , _hostAddress  (hostAddress)
    , _port         (port)
{
    moveToThread(this);
    start();
}

ADSBTCPLink::~ADSBTCPLink(void)
{
    if (_socket) {
        _socket->disconnectFromHost();
        _socket->deleteLater();
        _socket = nullptr;
    }
    quit();
    wait();
}

void ADSBTCPLink::run(void)
{
    _hardwareConnect();
    exec();
}

void ADSBTCPLink::_hardwareConnect()
{
    _socket = new QTcpSocket();

    QObject::connect(_socket, &QTcpSocket::readyRead, this, &ADSBTCPLink::_readBytes);

    _socket->connectToHost(_hostAddress, static_cast<quint16>(_port));

    // Give the socket a second to connect to the other side otherwise error out
    if (!_socket->waitForConnected(1000)) {
        qCDebug(ADSBVehicleManagerLog) << "ADSB Socket failed to connect";
        emit error(_socket->errorString());
        delete _socket;
        _socket = nullptr;
        return;
    }

    qCDebug(ADSBVehicleManagerLog) << "ADSB Socket connected";
}

void ADSBTCPLink::_readBytes(void)
{
    if (_socket) {
        QByteArray bytes = _socket->readLine();
        _parseLine(QString::fromLocal8Bit(bytes));
    }
}

void ADSBTCPLink::_parseLine(const QString& line)
{
    if (line.startsWith(QStringLiteral("MSG"))) {
        qCDebug(ADSBVehicleManagerLog) << "ADSB SBS-1" << line;

        QStringList values = line.split(QStringLiteral(","));

        if (values[1] == QStringLiteral("3")) {
            bool icaoOk, altOk, latOk, lonOk;

            uint32_t    icaoAddress =   values[4].toUInt(&icaoOk, 16);
            int         modeCAltitude = values[11].toInt(&altOk);
            double      lat =           values[14].toDouble(&latOk);
            double      lon =           values[15].toDouble(&lonOk);
            QString     callsign =      values[10];

            if (!icaoOk || !altOk || !latOk || !lonOk) {
                return;
            }
            if (lat == 0 && lon == 0) {
                return;
            }

            double altitude = modeCAltitude / 3.048;
            QGeoCoordinate location(lat, lon);

            ADSBVehicle::VehicleInfo_t adsbInfo;
            adsbInfo.icaoAddress = icaoAddress;
            adsbInfo.callsign = callsign;
            adsbInfo.location = location;
            adsbInfo.altitude = altitude;
            adsbInfo.availableFlags = ADSBVehicle::CallsignAvailable | ADSBVehicle::LocationAvailable | ADSBVehicle::AltitudeAvailable;
            emit adsbVehicleUpdate(adsbInfo);
        } else if (values[1] == QStringLiteral("4")) {
            bool icaoOk, headingOk;

            uint32_t    icaoAddress =   values[4].toUInt(&icaoOk, 16);
            double      heading =       values[13].toDouble(&headingOk);

            if (!icaoOk || !headingOk) {
                return;
            }

            ADSBVehicle::VehicleInfo_t adsbInfo;
            adsbInfo.icaoAddress = icaoAddress;
            adsbInfo.heading = heading;
            adsbInfo.availableFlags = ADSBVehicle::HeadingAvailable;
            emit adsbVehicleUpdate(adsbInfo);
        } else if (values[1] == QStringLiteral("1")) {
            bool icaoOk;

            uint32_t icaoAddress = values[4].toUInt(&icaoOk, 16);
            if (!icaoOk) {
                return;
            }

            ADSBVehicle::VehicleInfo_t adsbInfo;
            adsbInfo.icaoAddress = icaoAddress;
            adsbInfo.callsign = values[10];
            adsbInfo.availableFlags = ADSBVehicle::CallsignAvailable;
            emit adsbVehicleUpdate(adsbInfo);
        }
    }
}
<|endoftext|>


<commit_before>//===-- sanitizer_symbolizer_linux.cc -------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
// Linux-specific implementation of symbolizer parts.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_symbolizer.h"

#include <elf.h>
#include <errno.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#if !SANITIZER_ANDROID
#include <link.h>
#endif

namespace __sanitizer {

static const int kSymbolizerStartupTimeMillis = 10;

bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
                               int *input_fd, int *output_fd) {
  if (!FileExists(path_to_symbolizer)) {
    Report("WARNING: invalid path to external symbolizer!\n");
    return false;
  }

  int *infd = NULL;
  int *outfd = NULL;
  // The client program may close its stdin and/or stdout and/or stderr
  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
  // In this case the communication between the forked processes may be
  // broken if either the parent or the child tries to close or duplicate
  // these descriptors. The loop below produces two pairs of file
  // descriptors, each greater than 2 (stderr).
  int sock_pair[5][2];
  for (int i = 0; i < 5; i++) {
    if (pipe(sock_pair[i]) == -1) {
      for (int j = 0; j < i; j++) {
        internal_close(sock_pair[j][0]);
        internal_close(sock_pair[j][1]);
      }
      Report("WARNING: Can't create a socket pair to start "
             "external symbolizer (errno: %d)\n", errno);
      return false;
    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
      if (infd == NULL) {
        infd = sock_pair[i];
      } else {
        outfd = sock_pair[i];
        for (int j = 0; j < i; j++) {
          if (sock_pair[j] == infd) continue;
          internal_close(sock_pair[j][0]);
          internal_close(sock_pair[j][1]);
        }
        break;
      }
    }
  }
  CHECK(infd);
  CHECK(outfd);

  int pid = fork();
  if (pid == -1) {
    // Fork() failed.
    internal_close(infd[0]);
    internal_close(infd[1]);
    internal_close(outfd[0]);
    internal_close(outfd[1]);
    Report("WARNING: failed to fork external symbolizer "
           " (errno: %d)\n", errno);
    return false;
  } else if (pid == 0) {
    // Child subprocess.
    internal_close(STDOUT_FILENO);
    internal_close(STDIN_FILENO);
    internal_dup2(outfd[0], STDIN_FILENO);
    internal_dup2(infd[1], STDOUT_FILENO);
    internal_close(outfd[0]);
    internal_close(outfd[1]);
    internal_close(infd[0]);
    internal_close(infd[1]);
    for (int fd = getdtablesize(); fd > 2; fd--)
      internal_close(fd);
    execl(path_to_symbolizer, path_to_symbolizer, (char*)0);
    internal__exit(1);
  }

  // Continue execution in parent process.
  internal_close(outfd[0]);
  internal_close(infd[1]);
  *input_fd = infd[0];
  *output_fd = outfd[1];

  // Check that symbolizer subprocess started successfully.
  int pid_status;
  SleepForMillis(kSymbolizerStartupTimeMillis);
  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
  if (exited_pid != 0) {
    // Either waitpid failed, or child has already exited.
    Report("WARNING: external symbolizer didn't start up correctly!\n");
    return false;
  }

  return true;
}

#if SANITIZER_ANDROID
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                      string_predicate_t filter) {
  return 0;
}
#else  // SANITIZER_ANDROID
typedef ElfW(Phdr) Elf_Phdr;

struct DlIteratePhdrData {
  LoadedModule *modules;
  uptr current_n;
  bool first;
  uptr max_n;
  string_predicate_t filter;
};

static const uptr kMaxPathLength = 512;

static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
  DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
  if (data->current_n == data->max_n)
    return 0;
  InternalScopedBuffer<char> module_name(kMaxPathLength);
  module_name.data()[0] = '\0';
  if (data->first) {
    data->first = false;
    // First module is the binary itself.
    uptr module_name_len = internal_readlink(
        "/proc/self/exe", module_name.data(), module_name.size());
    if (internal_iserror(module_name_len)) {
      // We can't read /proc/self/exe for some reason, assume the name of the
      // binary is unknown.
      module_name_len = internal_snprintf(module_name.data(),
                                          module_name.size(), "/proc/self/exe");
    }
    CHECK_LT(module_name_len, module_name.size());
    module_name[module_name_len] = '\0';
  } else if (info->dlpi_name) {
    internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
  }
  if (module_name.data()[0] == '\0')
    return 0;
  if (data->filter && !data->filter(module_name.data()))
    return 0;
  void *mem = &data->modules[data->current_n];
  LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
                                                   info->dlpi_addr);
  data->current_n++;
  for (int i = 0; i < info->dlpi_phnum; i++) {
    const Elf_Phdr *phdr = &info->dlpi_phdr[i];
    if (phdr->p_type == PT_LOAD) {
      uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
      uptr cur_end = cur_beg + phdr->p_memsz;
      cur_module->addAddressRange(cur_beg, cur_end);
    }
  }
  return 0;
}

uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                      string_predicate_t filter) {
  CHECK(modules);
  DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
  dl_iterate_phdr(dl_iterate_phdr_cb, &data);
  return data.current_n;
}
#endif  // SANITIZER_ANDROID

}  // namespace __sanitizer

#endif  // SANITIZER_LINUX
<commit_msg>[sanitizer] Fix build with Android NDK r8e.<commit_after>//===-- sanitizer_symbolizer_linux.cc -------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is shared between AddressSanitizer and ThreadSanitizer
// run-time libraries.
// Linux-specific implementation of symbolizer parts.
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"
#if SANITIZER_LINUX
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_symbolizer.h"

// Android NDK r8e elf.h depends on stdint.h without including the latter.
#include <stdint.h>

#include <elf.h>
#include <errno.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#if !SANITIZER_ANDROID
#include <link.h>
#endif

namespace __sanitizer {

static const int kSymbolizerStartupTimeMillis = 10;

bool StartSymbolizerSubprocess(const char *path_to_symbolizer,
                               int *input_fd, int *output_fd) {
  if (!FileExists(path_to_symbolizer)) {
    Report("WARNING: invalid path to external symbolizer!\n");
    return false;
  }

  int *infd = NULL;
  int *outfd = NULL;
  // The client program may close its stdin and/or stdout and/or stderr
  // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
  // In this case the communication between the forked processes may be
  // broken if either the parent or the child tries to close or duplicate
  // these descriptors. The loop below produces two pairs of file
  // descriptors, each greater than 2 (stderr).
  int sock_pair[5][2];
  for (int i = 0; i < 5; i++) {
    if (pipe(sock_pair[i]) == -1) {
      for (int j = 0; j < i; j++) {
        internal_close(sock_pair[j][0]);
        internal_close(sock_pair[j][1]);
      }
      Report("WARNING: Can't create a socket pair to start "
             "external symbolizer (errno: %d)\n", errno);
      return false;
    } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
      if (infd == NULL) {
        infd = sock_pair[i];
      } else {
        outfd = sock_pair[i];
        for (int j = 0; j < i; j++) {
          if (sock_pair[j] == infd) continue;
          internal_close(sock_pair[j][0]);
          internal_close(sock_pair[j][1]);
        }
        break;
      }
    }
  }
  CHECK(infd);
  CHECK(outfd);

  int pid = fork();
  if (pid == -1) {
    // Fork() failed.
    internal_close(infd[0]);
    internal_close(infd[1]);
    internal_close(outfd[0]);
    internal_close(outfd[1]);
    Report("WARNING: failed to fork external symbolizer "
           " (errno: %d)\n", errno);
    return false;
  } else if (pid == 0) {
    // Child subprocess.
    internal_close(STDOUT_FILENO);
    internal_close(STDIN_FILENO);
    internal_dup2(outfd[0], STDIN_FILENO);
    internal_dup2(infd[1], STDOUT_FILENO);
    internal_close(outfd[0]);
    internal_close(outfd[1]);
    internal_close(infd[0]);
    internal_close(infd[1]);
    for (int fd = getdtablesize(); fd > 2; fd--)
      internal_close(fd);
    execl(path_to_symbolizer, path_to_symbolizer, (char*)0);
    internal__exit(1);
  }

  // Continue execution in parent process.
  internal_close(outfd[0]);
  internal_close(infd[1]);
  *input_fd = infd[0];
  *output_fd = outfd[1];

  // Check that symbolizer subprocess started successfully.
  int pid_status;
  SleepForMillis(kSymbolizerStartupTimeMillis);
  int exited_pid = waitpid(pid, &pid_status, WNOHANG);
  if (exited_pid != 0) {
    // Either waitpid failed, or child has already exited.
    Report("WARNING: external symbolizer didn't start up correctly!\n");
    return false;
  }

  return true;
}

#if SANITIZER_ANDROID
uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                      string_predicate_t filter) {
  return 0;
}
#else  // SANITIZER_ANDROID
typedef ElfW(Phdr) Elf_Phdr;

struct DlIteratePhdrData {
  LoadedModule *modules;
  uptr current_n;
  bool first;
  uptr max_n;
  string_predicate_t filter;
};

static const uptr kMaxPathLength = 512;

static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
  DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
  if (data->current_n == data->max_n)
    return 0;
  InternalScopedBuffer<char> module_name(kMaxPathLength);
  module_name.data()[0] = '\0';
  if (data->first) {
    data->first = false;
    // First module is the binary itself.
    uptr module_name_len = internal_readlink(
        "/proc/self/exe", module_name.data(), module_name.size());
    if (internal_iserror(module_name_len)) {
      // We can't read /proc/self/exe for some reason, assume the name of the
      // binary is unknown.
      module_name_len = internal_snprintf(module_name.data(),
                                          module_name.size(), "/proc/self/exe");
    }
    CHECK_LT(module_name_len, module_name.size());
    module_name[module_name_len] = '\0';
  } else if (info->dlpi_name) {
    internal_strncpy(module_name.data(), info->dlpi_name, module_name.size());
  }
  if (module_name.data()[0] == '\0')
    return 0;
  if (data->filter && !data->filter(module_name.data()))
    return 0;
  void *mem = &data->modules[data->current_n];
  LoadedModule *cur_module = new(mem) LoadedModule(module_name.data(),
                                                   info->dlpi_addr);
  data->current_n++;
  for (int i = 0; i < info->dlpi_phnum; i++) {
    const Elf_Phdr *phdr = &info->dlpi_phdr[i];
    if (phdr->p_type == PT_LOAD) {
      uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
      uptr cur_end = cur_beg + phdr->p_memsz;
      cur_module->addAddressRange(cur_beg, cur_end);
    }
  }
  return 0;
}

uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
                      string_predicate_t filter) {
  CHECK(modules);
  DlIteratePhdrData data = {modules, 0, true, max_modules, filter};
  dl_iterate_phdr(dl_iterate_phdr_cb, &data);
  return data.current_n;
}
#endif  // SANITIZER_ANDROID

}  // namespace __sanitizer

#endif  // SANITIZER_LINUX
<|endoftext|>


<commit_before>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018-19  David Shah <david@symbioticeda.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <algorithm>
#include <iterator>
#include <unordered_set>
#include "cells.h"
#include "design_utils.h"
#include "log.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

// Pack LUTs and LUT-FF pairs
static void pack_lut_lutffs(Context *ctx)
{
    log_info("Packing LUT-FFs..\n");

    std::unordered_set<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;
    for (auto cell : sorted(ctx->cells)) {
        CellInfo *ci = cell.second;
        if (ctx->verbose)
            log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
        if (is_lut(ctx, ci)) {
            std::unique_ptr<CellInfo> packed =
                    create_machxo2_cell(ctx, ctx->id("FACADE_SLICE"), ci->name.str(ctx) + "_LC");
            std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin()));

            packed_cells.insert(ci->name);
            if (ctx->verbose)
                log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
            // See if we can pack into a DFF. Both LUT4 and FF outputs are
            // available for a given slice, so we can pack a FF even if the
            // LUT4 drives more than one FF.
            NetInfo *o = ci->ports.at(ctx->id("Z")).net;
            CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("DI"), false);
            auto lut_bel = ci->attrs.find(ctx->id("BEL"));
            bool packed_dff = false;

            if (dff) {
                if (ctx->verbose)
                    log_info("found attached dff %s\n", dff->name.c_str(ctx));
                auto dff_bel = dff->attrs.find(ctx->id("BEL"));
                if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) {
                    // Locations don't match, can't pack
                } else {
                    lut_to_lc(ctx, ci, packed.get(), false);
                    dff_to_lc(ctx, dff, packed.get(), false);
                    if (dff_bel != dff->attrs.end())
                        packed->attrs[ctx->id("BEL")] = dff_bel->second;
                    packed_cells.insert(dff->name);
                    if (ctx->verbose)
                        log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx));
                    packed_dff = true;
                }
            }
            if (!packed_dff) {
                lut_to_lc(ctx, ci, packed.get(), true);
            }
            new_cells.push_back(std::move(packed));
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

// Merge a net into a constant net
static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
{
    (void) constval;

    orig->driver.cell = nullptr;
    for (auto user : orig->users) {
        if (user.cell != nullptr) {
            CellInfo *uc = user.cell;
            if (ctx->verbose)
                log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));

            uc->ports[user.port].net = constnet;
            constnet->users.push_back(user);
        }
    }
    orig->users.clear();
}

// Pack constants (based on simple implementation in generic).
// VCC/GND cells provided by nextpnr automatically.
static void pack_constants(Context *ctx)
{
    log_info("Packing constants..\n");

    std::unique_ptr<CellInfo> const_cell = create_machxo2_cell(ctx, id_FACADE_SLICE, "$PACKER_CONST");
    const_cell->params[id_LUT0_INITVAL] = Property(0, 16);
    const_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16);

    std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo);
    gnd_net->name = ctx->id("$PACKER_GND_NET");
    gnd_net->driver.cell = const_cell.get();
    gnd_net->driver.port = id_F0;
    const_cell->ports.at(id_F0).net = gnd_net.get();

    std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo);
    vcc_net->name = ctx->id("$PACKER_VCC_NET");
    vcc_net->driver.cell = const_cell.get();
    vcc_net->driver.port = id_F1;
    const_cell->ports.at(id_F1).net = vcc_net.get();

    std::vector<IdString> dead_nets;

    for (auto net : sorted(ctx->nets)) {
        NetInfo *ni = net.second;
        if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, gnd_net.get(), false);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, vcc_net.get(), true);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        }
    }

    ctx->cells[const_cell->name] = std::move(const_cell);
    ctx->nets[gnd_net->name] = std::move(gnd_net);
    ctx->nets[vcc_net->name] = std::move(vcc_net);

    for (auto dn : dead_nets) {
        ctx->nets.erase(dn);
    }
}

static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
{
    return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
           cell->type == ctx->id("$nextpnr_iobuf");
}

static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("FACADE_IO"); }

// Pack IO buffers- Right now, all this does is remove $nextpnr_[io]buf cells.
// User is expected to manually instantiate FACADE_IO with BEL/IO_TYPE
// attributes.
static void pack_io(Context *ctx)
{
    std::unordered_set<IdString> packed_cells;

    log_info("Packing IOs..\n");

    for (auto cell : sorted(ctx->cells)) {
        CellInfo *ci = cell.second;
        if (is_nextpnr_iob(ctx, ci)) {
            for (auto &p : ci->ports)
                disconnect_port(ctx, ci, p.first);
            packed_cells.insert(ci->name);
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
}

// Main pack function
bool Arch::pack()
{
    Context *ctx = getCtx();
    log_info("Packing implementation goes here..");
    try {
        log_break();
        pack_constants(ctx);
        pack_io(ctx);
        pack_lut_lutffs(ctx);
        ctx->settings[ctx->id("pack")] = 1;
        ctx->assignArchInfo();
        log_info("Checksum: 0x%08x\n", ctx->checksum());
        return true;
    } catch (log_execution_error_exception) {
        return false;
    }
}

NEXTPNR_NAMESPACE_END
<commit_msg>machxo2: Clean up packing pass a bit.<commit_after>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018-19  David Shah <david@symbioticeda.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <algorithm>
#include <iterator>
#include <unordered_set>
#include "cells.h"
#include "design_utils.h"
#include "log.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

// Pack LUTs and LUT-FF pairs
static void pack_lut_lutffs(Context *ctx)
{
    log_info("Packing LUT-FFs..\n");

    std::unordered_set<IdString> packed_cells;
    std::vector<std::unique_ptr<CellInfo>> new_cells;
    for (auto cell : sorted(ctx->cells)) {
        CellInfo *ci = cell.second;
        if (ctx->verbose)
            log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx));
        if (is_lut(ctx, ci)) {
            std::unique_ptr<CellInfo> packed =
                    create_machxo2_cell(ctx, id_FACADE_SLICE, ci->name.str(ctx) + "_LC");
            std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin()));

            packed_cells.insert(ci->name);
            if (ctx->verbose)
                log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx));
            // See if we can pack into a DFF. Both LUT4 and FF outputs are
            // available for a given slice, so we can pack a FF even if the
            // LUT4 drives more than one FF.
            NetInfo *o = ci->ports.at(id_Z).net;
            CellInfo *dff = net_only_drives(ctx, o, is_ff, id_DI, false);
            auto lut_bel = ci->attrs.find(ctx->id("BEL"));
            bool packed_dff = false;

            if (dff) {
                if (ctx->verbose)
                    log_info("found attached dff %s\n", dff->name.c_str(ctx));
                auto dff_bel = dff->attrs.find(ctx->id("BEL"));
                if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) {
                    // Locations don't match, can't pack
                } else {
                    lut_to_lc(ctx, ci, packed.get(), false);
                    dff_to_lc(ctx, dff, packed.get(), false);
                    if (dff_bel != dff->attrs.end())
                        packed->attrs[ctx->id("BEL")] = dff_bel->second;
                    packed_cells.insert(dff->name);
                    if (ctx->verbose)
                        log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx));
                    packed_dff = true;
                }
            }
            if (!packed_dff) {
                lut_to_lc(ctx, ci, packed.get(), true);
            }
            new_cells.push_back(std::move(packed));
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
    for (auto &ncell : new_cells) {
        ctx->cells[ncell->name] = std::move(ncell);
    }
}

// Merge a net into a constant net
static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval)
{
    (void) constval;

    orig->driver.cell = nullptr;
    for (auto user : orig->users) {
        if (user.cell != nullptr) {
            CellInfo *uc = user.cell;
            if (ctx->verbose)
                log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx));

            uc->ports[user.port].net = constnet;
            constnet->users.push_back(user);
        }
    }
    orig->users.clear();
}

// Pack constants (based on simple implementation in generic).
// VCC/GND cells provided by nextpnr automatically.
static void pack_constants(Context *ctx)
{
    log_info("Packing constants..\n");

    std::unique_ptr<CellInfo> const_cell = create_machxo2_cell(ctx, id_FACADE_SLICE, "$PACKER_CONST");
    const_cell->params[id_LUT0_INITVAL] = Property(0, 16);
    const_cell->params[id_LUT1_INITVAL] = Property(0xFFFF, 16);

    std::unique_ptr<NetInfo> gnd_net = std::unique_ptr<NetInfo>(new NetInfo);
    gnd_net->name = ctx->id("$PACKER_GND_NET");
    gnd_net->driver.cell = const_cell.get();
    gnd_net->driver.port = id_F0;
    const_cell->ports.at(id_F0).net = gnd_net.get();

    std::unique_ptr<NetInfo> vcc_net = std::unique_ptr<NetInfo>(new NetInfo);
    vcc_net->name = ctx->id("$PACKER_VCC_NET");
    vcc_net->driver.cell = const_cell.get();
    vcc_net->driver.port = id_F1;
    const_cell->ports.at(id_F1).net = vcc_net.get();

    std::vector<IdString> dead_nets;

    for (auto net : sorted(ctx->nets)) {
        NetInfo *ni = net.second;
        if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, gnd_net.get(), false);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) {
            IdString drv_cell = ni->driver.cell->name;
            set_net_constant(ctx, ni, vcc_net.get(), true);
            dead_nets.push_back(net.first);
            ctx->cells.erase(drv_cell);
        }
    }

    ctx->cells[const_cell->name] = std::move(const_cell);
    ctx->nets[gnd_net->name] = std::move(gnd_net);
    ctx->nets[vcc_net->name] = std::move(vcc_net);

    for (auto dn : dead_nets) {
        ctx->nets.erase(dn);
    }
}

static bool is_nextpnr_iob(Context *ctx, CellInfo *cell)
{
    return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") ||
           cell->type == ctx->id("$nextpnr_iobuf");
}

static bool is_facade_iob(const Context *ctx, const CellInfo *cell) { return cell->type == id_FACADE_IO; }

// Pack IO buffers- Right now, all this does is remove $nextpnr_[io]buf cells.
// User is expected to manually instantiate FACADE_IO with BEL/IO_TYPE
// attributes.
static void pack_io(Context *ctx)
{
    std::unordered_set<IdString> packed_cells;

    log_info("Packing IOs..\n");

    for (auto cell : sorted(ctx->cells)) {
        CellInfo *ci = cell.second;
        if (is_nextpnr_iob(ctx, ci)) {
            for (auto &p : ci->ports)
                disconnect_port(ctx, ci, p.first);
            packed_cells.insert(ci->name);
        }
    }

    for (auto pcell : packed_cells) {
        ctx->cells.erase(pcell);
    }
}

// Main pack function
bool Arch::pack()
{
    Context *ctx = getCtx();
    try {
        log_break();
        pack_constants(ctx);
        pack_io(ctx);
        pack_lut_lutffs(ctx);
        ctx->settings[ctx->id("pack")] = 1;
        ctx->assignArchInfo();
        log_info("Checksum: 0x%08x\n", ctx->checksum());
        return true;
    } catch (log_execution_error_exception) {
        return false;
    }
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


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

#include <graphene/app/api_access.hpp>
#include <graphene/net/node.hpp>
#include <graphene/chain/database.hpp>

#include <boost/program_options.hpp>

namespace graphene { namespace app {
   namespace detail { class application_impl; }
   using std::string;

   class abstract_plugin;

   class application_options
   {
      public:
         bool enable_subscribe_to_all = false;
         bool has_market_history_plugin = false;
   };

   class application
   {
      public:
         application();
         ~application();

         void set_program_options( boost::program_options::options_description& command_line_options,
                                   boost::program_options::options_description& configuration_file_options )const;
         void initialize(const fc::path& data_dir, const boost::program_options::variables_map&options);
         void initialize_plugins( const boost::program_options::variables_map& options );
         void startup();
         void shutdown();
         void startup_plugins();
         void shutdown_plugins();

         template<typename PluginType>
         std::shared_ptr<PluginType> register_plugin()
         {
            auto plug = std::make_shared<PluginType>();
            plug->plugin_set_app(this);

            boost::program_options::options_description plugin_cli_options(plug->plugin_name() + " plugin. " + plug->plugin_description() + "\nOptions"), plugin_cfg_options;
            //boost::program_options::options_description plugin_cli_options("Options for plugin " + plug->plugin_name()), plugin_cfg_options;
            plug->plugin_set_program_options(plugin_cli_options, plugin_cfg_options);
            if( !plugin_cli_options.options().empty() )
               _cli_options.add(plugin_cli_options);
            if( !plugin_cfg_options.options().empty() )
               _cfg_options.add(plugin_cfg_options);

            add_available_plugin( plug );
            return plug;
         }
         std::shared_ptr<abstract_plugin> get_plugin( const string& name )const;

         template<typename PluginType>
         std::shared_ptr<PluginType> get_plugin( const string& name ) const
         {
            std::shared_ptr<abstract_plugin> abs_plugin = get_plugin( name );
            std::shared_ptr<PluginType> result = std::dynamic_pointer_cast<PluginType>( abs_plugin );
            FC_ASSERT( result != std::shared_ptr<PluginType>(), "Unable to load plugin '${p}'", ("p",name) );
            return result;
         }

         net::node_ptr                    p2p_node();
         std::shared_ptr<chain::database> chain_database()const;

         void set_block_production(bool producing_blocks);
         fc::optional< api_access_info > get_api_access_info( const string& username )const;
         void set_api_access_info(const string& username, api_access_info&& permissions);

         bool is_finished_syncing()const;
         /// Emitted when syncing finishes (is_finished_syncing will return true)
         boost::signals2::signal<void()> syncing_finished;

         const application_options& get_options();

      private:
         void enable_plugin( const string& name );
         void add_available_plugin( std::shared_ptr<abstract_plugin> p );
         std::shared_ptr<detail::application_impl> my;

         boost::program_options::options_description _cli_options;
         boost::program_options::options_description _cfg_options;
   };

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

#include <graphene/app/api_access.hpp>
#include <graphene/net/node.hpp>
#include <graphene/chain/database.hpp>

#include <boost/program_options.hpp>

namespace graphene { namespace app {
   namespace detail { class application_impl; }
   using std::string;

   class abstract_plugin;

   class application_options
   {
      public:
         bool enable_subscribe_to_all = false;
         bool has_market_history_plugin = false;
   };

   class application
   {
      public:
         application();
         ~application();

         void set_program_options(boost::program_options::options_description& command_line_options,
                                  boost::program_options::options_description& configuration_file_options)const;
         void initialize(const fc::path& data_dir, const boost::program_options::variables_map& options);
         void initialize_plugins(const boost::program_options::variables_map& options);
         void startup();
         void shutdown();
         void startup_plugins();
         void shutdown_plugins();

         template<typename PluginType>
         std::shared_ptr<PluginType> register_plugin(bool auto_load = false) {
            auto plug = std::make_shared<PluginType>();
            plug->plugin_set_app(this);

            boost::program_options::options_description plugin_cli_options(plug->plugin_name() + " plugin. " + plug->plugin_description() + "\nOptions"), plugin_cfg_options;
            //boost::program_options::options_description plugin_cli_options("Options for plugin " + plug->plugin_name()), plugin_cfg_options;
            plug->plugin_set_program_options(plugin_cli_options, plugin_cfg_options);
            if( !plugin_cli_options.options().empty() )
               _cli_options.add(plugin_cli_options);
            if( !plugin_cfg_options.options().empty() )
               _cfg_options.add(plugin_cfg_options);

            add_available_plugin( plug );

            if (auto_load)
                enable_plugin(plug->plugin_name());

            return plug;
         }
         std::shared_ptr<abstract_plugin> get_plugin( const string& name )const;

         template<typename PluginType>
         std::shared_ptr<PluginType> get_plugin( const string& name ) const
         {
            std::shared_ptr<abstract_plugin> abs_plugin = get_plugin( name );
            std::shared_ptr<PluginType> result = std::dynamic_pointer_cast<PluginType>( abs_plugin );
            FC_ASSERT( result != std::shared_ptr<PluginType>(), "Unable to load plugin '${p}'", ("p",name) );
            return result;
         }

         net::node_ptr                    p2p_node();
         std::shared_ptr<chain::database> chain_database()const;

         void set_block_production(bool producing_blocks);
         fc::optional< api_access_info > get_api_access_info( const string& username )const;
         void set_api_access_info(const string& username, api_access_info&& permissions);

         bool is_finished_syncing()const;
         /// Emitted when syncing finishes (is_finished_syncing will return true)
         boost::signals2::signal<void()> syncing_finished;

         const application_options& get_options();

      private:
         void enable_plugin( const string& name );
         void add_available_plugin( std::shared_ptr<abstract_plugin> p );
         std::shared_ptr<detail::application_impl> my;

         boost::program_options::options_description _cli_options;
         boost::program_options::options_description _cfg_options;
   };

} }
<|endoftext|>


<commit_before>#include "GameController.h"
#include "MapController.h"
#include "MoveController.h"

#include <algorithm>

enum {
  kTagTileMap = 1,
};

cocos2d::Scene* tsg::game::GameController::createScene() {
  // 'scene' is an autorelease object
  auto scene = cocos2d::Scene::create();

  // 'layer' is an autorelease object
  auto layer = GameController::create();

  // add layer as a child to scene
  scene->addChild(layer);

  // return the scene
  return scene;
}

void tsg::game::GameController::registerListener(IGameEventListener* listener) {
  this->listeners.push_back(listener);
}

bool tsg::game::GameController::init() {
  if (!Layer::init()) {
    return false;
  }
  CCLOG("initializing controllers");
    this->mapController = new map::MapController(dynamic_cast<cocos2d::Layer*>(this));
  this->moveController = new move::MoveController();
  CCLOG("controllers initialized");
  for_each(listeners.begin(), listeners.end(),
           [](IGameEventListener* l) { l->onInit(); });
    mapController->loadMap("map1.tmx");
  return true;
}
<commit_msg>Remove unneeded public methods<commit_after>#include "GameController.h"
#include "MapController.h"
#include "MoveController.h"

#include <algorithm>

enum {
  kTagTileMap = 1,
};

cocos2d::Scene* tsg::game::GameController::createScene() {
  // 'scene' is an autorelease object
  auto scene = cocos2d::Scene::create();

  // 'layer' is an autorelease object
  auto layer = GameController::create();

  // add layer as a child to scene
  scene->addChild(layer);

  // return the scene
  return scene;
}

void tsg::game::GameController::registerListener(IGameEventListener* listener) {
  this->listeners.push_back(listener);
}

bool tsg::game::GameController::init() {
  if (!Layer::init()) {
    return false;
  }
  CCLOG("initializing controllers");
    this->mapController = new map::MapController(dynamic_cast<cocos2d::Layer*>(this));
  this->moveController = new move::MoveController();
  CCLOG("controllers initialized");
  for_each(listeners.begin(), listeners.end(),
           [](IGameEventListener* l) { l->onInit(); });
    mapController->loadMap("data/map1.tmx");
  return true;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Map.h"
#include "ShapefileHelper.h"
#include "EditorHelper.h"
#include "ShapeStyleHelper.h"
#include "SelectionHelper.h"

// ************************************************************
//		GetProjectedTolerance
// ************************************************************
double CMapView::GetProjectedTolerance(double xScreen, double yScreen, double tolerance)
{
	double x, y, x2, y2;
	this->PixelToProjection(xScreen, yScreen, x, y);
	this->PixelToProjection(xScreen + tolerance, yScreen + tolerance, x2, y2);
	return sqrt(pow(x - x2, 2.0) + pow(y - y2, 2.0));
}

// ************************************************************
//		FindSnapPointCore
// ************************************************************
VARIANT_BOOL CMapView::FindSnapPointCore(double xScreen, double yScreen, double* xFound, double* yFound)
{
	return FindSnapPoint(GetMouseTolerance(ToleranceSnap, false), xScreen, yScreen, xFound, yFound);
}

// ************************************************************
//		FindSnapPoint
// ************************************************************
VARIANT_BOOL CMapView::FindSnapPoint(double tolerance, double xScreen, double yScreen, double* xFound, double* yFound)
{
	double maxDist = GetProjectedTolerance(xScreen, yScreen, tolerance);
	double x, y;
	this->PixelToProjection(xScreen, yScreen, x, y);

	long shapeIndex;
	long pointIndex;
	VARIANT_BOOL vb;
	double distance;

	double minDist = DBL_MAX;
	IShapefile* foundShapefile = NULL;
	long foundShapeIndex;
	long foundPointIndex;

	bool digitizing = EditorHelper::IsDigitizingCursor((tkCursorMode)m_cursorMode);
	tkLayerSelection behavior;
	_shapeEditor->get_SnapBehavior(&behavior);
	long currentHandle = -1;
	bool currentLayerOnly = behavior == lsActiveLayer && digitizing;
	if (currentLayerOnly)
		_shapeEditor->get_LayerHandle(&currentHandle);

	for (long i = 0; i < this->GetNumLayers(); i++)
	{
		long layerHandle = this->GetLayerHandle(i);
		if (currentLayerOnly && layerHandle != currentHandle)
			continue;

		Layer* l = GetLayer(layerHandle);
		if (!l || !l->wasRendered) continue;

		CComPtr<IShapefile> sf = NULL;
		sf.Attach(this->GetShapefile(layerHandle));
		if (sf)
		{
			VARIANT_BOOL snappable;
			sf->get_Snappable(&snappable);
			if (snappable)
			{
				sf->GetClosestVertex(x, y, maxDist, &shapeIndex, &pointIndex, &distance, &vb);
				if (vb)
				{
					if (distance < minDist)
					{
						minDist = distance;
						foundShapefile = sf;
						foundPointIndex = pointIndex;
						foundShapeIndex = shapeIndex;
					}
				}
			}
		}
	}

	bool result = false;
	if (minDist != DBL_MAX && foundShapefile)
	{
		IShape* shape = NULL;
		foundShapefile->get_Shape(foundShapeIndex, &shape);
		if (shape)
		{
			shape->get_XY(foundPointIndex, xFound, yFound, &vb);
			shape->Release();
			result = true;
		}
	}
	return result;
}

// ************************************************************
//		SelectLayerHandles
// ************************************************************
bool CMapView::SelectLayerHandles(LayerSelector selector, std::vector<int>& layers)
{
	if (selector == slctIdentify)
	{
		// for single layer identification, request the selected layer from the client
		tkIdentifierMode mode;
		_identifier->get_IdentifierMode(&mode);
		if (mode == imSingleLayer)
		{
			long layerHandle = -1;
			FireChooseLayer(0, 0, &layerHandle);
			if (layerHandle != -1)
			{
				Layer* layer = GetLayer(layerHandle);
				if (layer && layer->wasRendered)
				{
					layers.push_back(layerHandle);
				}
				return true;
			}
			return false;
		}
	}

	IShapefile * sf = NULL;
	for (int i = 0; i < (int)_activeLayers.size(); i++)
	{
		int handle = GetLayerHandle(i);
		bool result = CheckLayer(selector, handle);
		if (result) {
			layers.push_back(handle);
		}
	}
	return layers.size() > 0;
}

// ************************************************************
//		LayerIsIdentifiable
// ************************************************************
VARIANT_BOOL CMapView::LayerIsIdentifiable(long layerHandle, IShapefile* sf)
{
	VARIANT_BOOL result = VARIANT_FALSE;
	tkIdentifierMode mode;
	_identifier->get_IdentifierMode(&mode);
	sf->get_Identifiable(&result);
	return result;
}

// ************************************************************
//		CheckShapefileLayer
// ************************************************************
bool CMapView::CheckShapefileLayer(LayerSelector selector, int layerHandle, IShapefile* sf)
{
	VARIANT_BOOL result = VARIANT_FALSE;
	switch (selector)
	{
		case slctShapefiles:
			return true;
		case slctIdentify:
			result = LayerIsIdentifiable(layerHandle, sf);
			break;
		case slctHotTracking:
			if (m_cursorMode == cmIdentify)
			{
				VARIANT_BOOL hotTracking;
				_identifier->get_HotTracking(&hotTracking);
				if (hotTracking)
				{
					result = LayerIsIdentifiable(layerHandle, sf);
				}
			}
			else
			{
				VARIANT_BOOL interactive;
				sf->get_InteractiveEditing(&interactive);

				tkLayerSelection highlighting;
				_shapeEditor->get_HighlightVertices(&highlighting);

				bool editorEmpty = EditorHelper::IsEmpty(_shapeEditor);
				bool editing = m_cursorMode == cmEditShape && !editorEmpty;
				bool selection = m_cursorMode == cmEditShape && editorEmpty;

				if (selection)
				{
					// we are looking for new shape to select which can be at any editable layer
					if (interactive && highlighting != lsNoLayer)
						result = VARIANT_TRUE;
				}
				else if ((!editorEmpty && m_cursorMode == cmEditShape) ||
					EditorHelper::IsDigitizingCursor((tkCursorMode)m_cursorMode))
				{
					// highlight vertices for easier snapping
					switch (highlighting) {
						case lsAllLayers:
							return true;
						case lsActiveLayer:
							long handle;
							_shapeEditor->get_LayerHandle(&handle);
							return handle == layerHandle;
						case lsNoLayer:
							return false;
					}
				}
			}
			break;
		case slctInMemorySf:
			sf->get_EditingShapes(&result);
			break;
		case slctInteractiveEditing:
			sf->get_InteractiveEditing(&result);
			break;
	}
	return result ? true : false;
}

// ************************************************************
//		CheckLayer
// ************************************************************
bool CMapView::CheckLayer(LayerSelector selector, int layerHandle)
{
	CComPtr<IShapefile> sf = NULL;
	Layer* layer = _allLayers[layerHandle];

	if (!layer->wasRendered) return false;

	if (layer->IsShapefile())
	{
		if (layer->QueryShapefile(&sf))
		{
			CheckShapefileLayer(selector, layerHandle, sf);
		}
	}
	else if (layer->IsImage())
	{
		// it's raster
		switch (selector)
		{
			case slctIdentify:
				return true;			// TODO: check layer is identifiable
		}

		return false;
	}

	return false;
}

// ************************************************************
//		GetMouseTolerance
// ************************************************************
// Mouse tolerance in projected units
double CMapView::GetMouseTolerance(MouseTolerance tolerance, bool proj)
{
	double tol = 0;
	switch (tolerance)
	{
		case ToleranceSnap:
			_shapeEditor->get_SnapTolerance(&tol);
			break;
		case ToleranceSelect:
			tol = m_globalSettings.mouseTolerance;
			break;
		case ToleranceInsert:
			tol = 10;
			break;
	}

	if (proj)
	{
		tol /= this->PixelsPerMapUnit();
	}

	return tol;
}

// ************************************************************
//		DrillDownSelect
// ************************************************************
bool CMapView::DrillDownSelect(double projX, double projY, long& layerHandle, long& shapeIndex)
{
	vector<int> handles;
	SelectLayerHandles(slctIdentify, handles);
	for (int i = handles.size() - 1; i >= 0; i--)
	{
		CComPtr<IShapefile> sf = NULL;
		sf.Attach(GetShapefile(handles[i]));
		if (sf) {
			Extent box = GetPointSelectionBox(sf, projX, projY);

			if (SelectionHelper::SelectSingleShape(sf, box, shapeIndex))
			{
				layerHandle = handles[i];
				return true;
			}
		}
	}
	return false;
}

// ************************************************************
//		DrillDownSelect
// ************************************************************
bool CMapView::DrillDownSelect(double projX, double projY, ISelectionList* list, bool stopOnFirst)
{
	vector<int> handles;
	SelectLayerHandles(slctIdentify, handles);

	vector<long> results;

	for (int i = handles.size() - 1; i >= 0; i--)
	{
		Layer* layer = GetLayer(handles[i]);

		if (!layer)
		{
			CallbackHelper::AssertionFailed("Invalid layer handler in DrillDownSelect.");
			continue;
		}

		if (!layer->PointWithinExtents(projX, projY))		// TODO: use tolerance
		{
			continue;
		}

		if (layer->IsShapefile())
		{
			CComPtr<IShapefile> sf = NULL;
			sf.Attach(GetShapefile(handles[i]));

			if (sf)
			{
				Extent box = GetPointSelectionBox(sf, projX, projY);

				results.clear();

				if (SelectionHelper::SelectShapes(sf, box, SelectMode::INTERSECTION, results))
				{
					for (size_t j = 0; j < results.size(); j++)
					{
						VARIANT_BOOL visible;
						sf->get_ShapeVisible(results[j], &visible);

						if (visible)
						{
							list->AddShape(handles[i], results[j]);
						}
					}

					if (results.size() > 0 && stopOnFirst) {
						return true;
					}
				}
			}
		}
		else if (layer->IsImage())
		{
			CComPtr<IImage> img = NULL;
			img.Attach(GetImage(handles[i]));
			if (img)
			{
				long rasterX, rasterY;
				img->ProjectionToImage(projX, projY, &rasterX, &rasterY);
				list->AddPixel(handles[i], rasterX, rasterY);
			}
		}
	}

	long numLayers;
	list->get_Count(&numLayers);
	return numLayers > 0;
}

// ************************************************************
//		FindShapeAtScreenPoint
// ************************************************************
LayerShape CMapView::FindShapeAtScreenPoint(CPoint point, LayerSelector selector)
{
	double pixX = point.x;
	double pixY = point.y;
	double prjX, prjY;
	this->PixelToProj(pixX, pixY, &prjX, &prjY);

	std::vector<int> layers;
	if (SelectLayerHandles(selector, layers))
	{
		return FindShapeAtProjPoint(prjX, prjY, layers);
	}
	return LayerShape();
}

// ************************************************************
//		FindShapeCore
// ************************************************************
LayerShape CMapView::FindShapeAtProjPoint(double prjX, double prjY, std::vector<int>& layers)
{
	IShapefile * sf = NULL;
	for (int i = (int)layers.size() - 1; i >= 0; i--)
	{
		CComPtr<IShapefile> sf = NULL;
		sf.Attach(GetShapefile(layers[i]));
		if (sf) {
			double tol = 0.0;
			ShpfileType type = ShapefileHelper::GetShapeType2D(sf);
			if (type == SHP_MULTIPOINT || type == SHP_POINT || type == SHP_POLYLINE)
				tol = GetMouseTolerance(ToleranceSelect);

			SelectMode mode = type == SHP_POLYGON ? INCLUSION : INTERSECTION;

			long shapeIndex;
			if (SelectionHelper::SelectSingleShape(sf, Extent(prjX, prjY, tol), mode, shapeIndex)) {
				return LayerShape(layers[i], shapeIndex);
			}
		}
	}
	return LayerShape();
}

// ************************************************************
//		SelectShapeForEditing
// ************************************************************
bool CMapView::SelectShapeForEditing(int x, int y, long& layerHandle, long& shapeIndex)
{
	LayerShape info = FindShapeAtScreenPoint(CPoint(x, y), slctInteractiveEditing);
	if (!info.IsEmpty())
	{
		tkMwBoolean cancel = blnFalse;
		FireBeforeShapeEdit(info.LayerHandle, info.ShapeIndex, &cancel);
		layerHandle = info.LayerHandle;
		shapeIndex = info.ShapeIndex;
		return cancel == blnFalse;
	}
	return false;
}

// ************************************************************
//		RecalcHotTracking
// ************************************************************
HotTrackingResult CMapView::RecalcHotTracking(CPoint point, LayerShape& result)
{
	bool cursorCheck = EditorHelper::IsSnappableCursor((tkCursorMode)m_cursorMode) || m_cursorMode == cmEditShape || m_cursorMode == cmIdentify;
	if (!cursorCheck) return NoShape;

	if (_shapeCountInView < m_globalSettings.hotTrackingMaxShapeCount && HasHotTracking())
	{
		result = FindShapeAtScreenPoint(point, slctHotTracking);
		if (!result.IsEmpty()) {
			return _hotTracking.IsSame(result) ? SameShape : NewShape;
		}
	}
	return HotTrackingResult::NoShape;
}

// ************************************************************
//		ClearHotTracking
// ************************************************************
void CMapView::ClearHotTracking()
{
	if (!_hotTracking.IsEmpty())
	{
		_canUseMainBuffer = false;
		_hotTracking.Clear();
		this->FireShapeHighlighted(-1, -1);
	}
}

// ************************************************************
//		UpdateHotTracking
// ************************************************************
void CMapView::UpdateHotTracking(LayerShape info, bool fireEvent)
{
	CComPtr<IShapefile> sf = NULL;
	sf.Attach(GetShapefile(info.LayerHandle));
	if (sf) {
		CComPtr<IShape> shape = NULL;
		sf->get_Shape(info.ShapeIndex, &shape);
		if (shape)
		{
			CComPtr<IShape> shpClone = NULL;
			shape->Clone(&shpClone);
			_hotTracking.Update(sf, shpClone, info.LayerHandle, info.ShapeIndex);

			OLE_COLOR color;
			_identifier->get_OutlineColor(&color);

			CComPtr<IShapeDrawingOptions> options = NULL;
			options.Attach(ShapeStyleHelper::GetHotTrackingStyle(sf, color, m_cursorMode == cmIdentify));
			if (options) {
				_hotTracking.UpdateStyle(options);
			}

			if (fireEvent)
				this->FireShapeHighlighted(_hotTracking.LayerHandle, _hotTracking.ShapeIndex);
			_canUseMainBuffer = false;
		}
	}
}<commit_msg>Another fix of identifier.<commit_after>#include "stdafx.h"
#include "Map.h"
#include "ShapefileHelper.h"
#include "EditorHelper.h"
#include "ShapeStyleHelper.h"
#include "SelectionHelper.h"

// ************************************************************
//		GetProjectedTolerance
// ************************************************************
double CMapView::GetProjectedTolerance(double xScreen, double yScreen, double tolerance)
{
	double x, y, x2, y2;
	this->PixelToProjection(xScreen, yScreen, x, y);
	this->PixelToProjection(xScreen + tolerance, yScreen + tolerance, x2, y2);
	return sqrt(pow(x - x2, 2.0) + pow(y - y2, 2.0));
}

// ************************************************************
//		FindSnapPointCore
// ************************************************************
VARIANT_BOOL CMapView::FindSnapPointCore(double xScreen, double yScreen, double* xFound, double* yFound)
{
	return FindSnapPoint(GetMouseTolerance(ToleranceSnap, false), xScreen, yScreen, xFound, yFound);
}

// ************************************************************
//		FindSnapPoint
// ************************************************************
VARIANT_BOOL CMapView::FindSnapPoint(double tolerance, double xScreen, double yScreen, double* xFound, double* yFound)
{
	double maxDist = GetProjectedTolerance(xScreen, yScreen, tolerance);
	double x, y;
	this->PixelToProjection(xScreen, yScreen, x, y);

	long shapeIndex;
	long pointIndex;
	VARIANT_BOOL vb;
	double distance;

	double minDist = DBL_MAX;
	IShapefile* foundShapefile = NULL;
	long foundShapeIndex;
	long foundPointIndex;

	bool digitizing = EditorHelper::IsDigitizingCursor((tkCursorMode)m_cursorMode);
	tkLayerSelection behavior;
	_shapeEditor->get_SnapBehavior(&behavior);
	long currentHandle = -1;
	bool currentLayerOnly = behavior == lsActiveLayer && digitizing;
	if (currentLayerOnly)
		_shapeEditor->get_LayerHandle(&currentHandle);

	for (long i = 0; i < this->GetNumLayers(); i++)
	{
		long layerHandle = this->GetLayerHandle(i);
		if (currentLayerOnly && layerHandle != currentHandle)
			continue;

		Layer* l = GetLayer(layerHandle);
		if (!l || !l->wasRendered) continue;

		CComPtr<IShapefile> sf = NULL;
		sf.Attach(this->GetShapefile(layerHandle));
		if (sf)
		{
			VARIANT_BOOL snappable;
			sf->get_Snappable(&snappable);
			if (snappable)
			{
				sf->GetClosestVertex(x, y, maxDist, &shapeIndex, &pointIndex, &distance, &vb);
				if (vb)
				{
					if (distance < minDist)
					{
						minDist = distance;
						foundShapefile = sf;
						foundPointIndex = pointIndex;
						foundShapeIndex = shapeIndex;
					}
				}
			}
		}
	}

	bool result = false;
	if (minDist != DBL_MAX && foundShapefile)
	{
		IShape* shape = NULL;
		foundShapefile->get_Shape(foundShapeIndex, &shape);
		if (shape)
		{
			shape->get_XY(foundPointIndex, xFound, yFound, &vb);
			shape->Release();
			result = true;
		}
	}
	return result;
}

// ************************************************************
//		SelectLayerHandles
// ************************************************************
bool CMapView::SelectLayerHandles(LayerSelector selector, std::vector<int>& layers)
{
	if (selector == slctIdentify)
	{
		// for single layer identification, request the selected layer from the client
		tkIdentifierMode mode;
		_identifier->get_IdentifierMode(&mode);
		if (mode == imSingleLayer)
		{
			long layerHandle = -1;
			FireChooseLayer(0, 0, &layerHandle);
			if (layerHandle != -1)
			{
				Layer* layer = GetLayer(layerHandle);
				if (layer && layer->wasRendered)
				{
					layers.push_back(layerHandle);
				}
				return true;
			}
			return false;
		}
	}

	IShapefile * sf = NULL;
	for (int i = 0; i < (int)_activeLayers.size(); i++)
	{
		int handle = GetLayerHandle(i);
		bool result = CheckLayer(selector, handle);
		if (result) {
			layers.push_back(handle);
		}
	}
	return layers.size() > 0;
}

// ************************************************************
//		LayerIsIdentifiable
// ************************************************************
VARIANT_BOOL CMapView::LayerIsIdentifiable(long layerHandle, IShapefile* sf)
{
	VARIANT_BOOL result = VARIANT_FALSE;
	tkIdentifierMode mode;
	_identifier->get_IdentifierMode(&mode);
	sf->get_Identifiable(&result);
	return result;
}

// ************************************************************
//		CheckShapefileLayer
// ************************************************************
bool CMapView::CheckShapefileLayer(LayerSelector selector, int layerHandle, IShapefile* sf)
{
	VARIANT_BOOL result = VARIANT_FALSE;
	switch (selector)
	{
		case slctShapefiles:
			return true;
		case slctIdentify:
			result = LayerIsIdentifiable(layerHandle, sf);
			break;
		case slctHotTracking:
			if (m_cursorMode == cmIdentify)
			{
				VARIANT_BOOL hotTracking;
				_identifier->get_HotTracking(&hotTracking);
				if (hotTracking)
				{
					result = LayerIsIdentifiable(layerHandle, sf);
				}
			}
			else
			{
				VARIANT_BOOL interactive;
				sf->get_InteractiveEditing(&interactive);

				tkLayerSelection highlighting;
				_shapeEditor->get_HighlightVertices(&highlighting);

				bool editorEmpty = EditorHelper::IsEmpty(_shapeEditor);
				bool editing = m_cursorMode == cmEditShape && !editorEmpty;
				bool selection = m_cursorMode == cmEditShape && editorEmpty;

				if (selection)
				{
					// we are looking for new shape to select which can be at any editable layer
					if (interactive && highlighting != lsNoLayer)
						result = VARIANT_TRUE;
				}
				else if ((!editorEmpty && m_cursorMode == cmEditShape) ||
					EditorHelper::IsDigitizingCursor((tkCursorMode)m_cursorMode))
				{
					// highlight vertices for easier snapping
					switch (highlighting) {
						case lsAllLayers:
							return true;
						case lsActiveLayer:
							long handle;
							_shapeEditor->get_LayerHandle(&handle);
							return handle == layerHandle;
						case lsNoLayer:
							return false;
					}
				}
			}
			break;
		case slctInMemorySf:
			sf->get_EditingShapes(&result);
			break;
		case slctInteractiveEditing:
			sf->get_InteractiveEditing(&result);
			break;
	}
	return result ? true : false;
}

// ************************************************************
//		CheckLayer
// ************************************************************
bool CMapView::CheckLayer(LayerSelector selector, int layerHandle)
{
	CComPtr<IShapefile> sf = NULL;
	Layer* layer = _allLayers[layerHandle];

	if (!layer->wasRendered) return false;

	if (layer->IsShapefile())
	{
		if (layer->QueryShapefile(&sf))
		{
			return CheckShapefileLayer(selector, layerHandle, sf);
		}
	}
	else if (layer->IsImage())
	{
		// it's raster
		switch (selector)
		{
			case slctIdentify:
				return true;			// TODO: check layer is identifiable
		}

		return false;
	}

	return false;
}

// ************************************************************
//		GetMouseTolerance
// ************************************************************
// Mouse tolerance in projected units
double CMapView::GetMouseTolerance(MouseTolerance tolerance, bool proj)
{
	double tol = 0;
	switch (tolerance)
	{
		case ToleranceSnap:
			_shapeEditor->get_SnapTolerance(&tol);
			break;
		case ToleranceSelect:
			tol = m_globalSettings.mouseTolerance;
			break;
		case ToleranceInsert:
			tol = 10;
			break;
	}

	if (proj)
	{
		tol /= this->PixelsPerMapUnit();
	}

	return tol;
}

// ************************************************************
//		DrillDownSelect
// ************************************************************
bool CMapView::DrillDownSelect(double projX, double projY, long& layerHandle, long& shapeIndex)
{
	vector<int> handles;
	SelectLayerHandles(slctIdentify, handles);
	for (int i = handles.size() - 1; i >= 0; i--)
	{
		CComPtr<IShapefile> sf = NULL;
		sf.Attach(GetShapefile(handles[i]));
		if (sf) {
			Extent box = GetPointSelectionBox(sf, projX, projY);

			if (SelectionHelper::SelectSingleShape(sf, box, shapeIndex))
			{
				layerHandle = handles[i];
				return true;
			}
		}
	}
	return false;
}

// ************************************************************
//		DrillDownSelect
// ************************************************************
bool CMapView::DrillDownSelect(double projX, double projY, ISelectionList* list, bool stopOnFirst)
{
	vector<int> handles;
	SelectLayerHandles(slctIdentify, handles);

	vector<long> results;

	for (int i = handles.size() - 1; i >= 0; i--)
	{
		Layer* layer = GetLayer(handles[i]);

		if (!layer)
		{
			CallbackHelper::AssertionFailed("Invalid layer handler in DrillDownSelect.");
			continue;
		}

		if (!layer->PointWithinExtents(projX, projY))		// TODO: use tolerance
		{
			continue;
		}

		if (layer->IsShapefile())
		{
			CComPtr<IShapefile> sf = NULL;
			sf.Attach(GetShapefile(handles[i]));

			if (sf)
			{
				Extent box = GetPointSelectionBox(sf, projX, projY);

				results.clear();

				if (SelectionHelper::SelectShapes(sf, box, SelectMode::INTERSECTION, results))
				{
					for (size_t j = 0; j < results.size(); j++)
					{
						VARIANT_BOOL visible;
						sf->get_ShapeVisible(results[j], &visible);

						if (visible)
						{
							list->AddShape(handles[i], results[j]);
						}
					}

					if (results.size() > 0 && stopOnFirst) {
						return true;
					}
				}
			}
		}
		else if (layer->IsImage())
		{
			CComPtr<IImage> img = NULL;
			img.Attach(GetImage(handles[i]));
			if (img)
			{
				long rasterX, rasterY;
				img->ProjectionToImage(projX, projY, &rasterX, &rasterY);
				list->AddPixel(handles[i], rasterX, rasterY);
			}
		}
	}

	long numLayers;
	list->get_Count(&numLayers);
	return numLayers > 0;
}

// ************************************************************
//		FindShapeAtScreenPoint
// ************************************************************
LayerShape CMapView::FindShapeAtScreenPoint(CPoint point, LayerSelector selector)
{
	double pixX = point.x;
	double pixY = point.y;
	double prjX, prjY;
	this->PixelToProj(pixX, pixY, &prjX, &prjY);

	std::vector<int> layers;
	if (SelectLayerHandles(selector, layers))
	{
		return FindShapeAtProjPoint(prjX, prjY, layers);
	}
	return LayerShape();
}

// ************************************************************
//		FindShapeCore
// ************************************************************
LayerShape CMapView::FindShapeAtProjPoint(double prjX, double prjY, std::vector<int>& layers)
{
	IShapefile * sf = NULL;
	for (int i = (int)layers.size() - 1; i >= 0; i--)
	{
		CComPtr<IShapefile> sf = NULL;
		sf.Attach(GetShapefile(layers[i]));
		if (sf) {
			double tol = 0.0;
			ShpfileType type = ShapefileHelper::GetShapeType2D(sf);
			if (type == SHP_MULTIPOINT || type == SHP_POINT || type == SHP_POLYLINE)
				tol = GetMouseTolerance(ToleranceSelect);

			SelectMode mode = type == SHP_POLYGON ? INCLUSION : INTERSECTION;

			long shapeIndex;
			if (SelectionHelper::SelectSingleShape(sf, Extent(prjX, prjY, tol), mode, shapeIndex)) {
				return LayerShape(layers[i], shapeIndex);
			}
		}
	}
	return LayerShape();
}

// ************************************************************
//		SelectShapeForEditing
// ************************************************************
bool CMapView::SelectShapeForEditing(int x, int y, long& layerHandle, long& shapeIndex)
{
	LayerShape info = FindShapeAtScreenPoint(CPoint(x, y), slctInteractiveEditing);
	if (!info.IsEmpty())
	{
		tkMwBoolean cancel = blnFalse;
		FireBeforeShapeEdit(info.LayerHandle, info.ShapeIndex, &cancel);
		layerHandle = info.LayerHandle;
		shapeIndex = info.ShapeIndex;
		return cancel == blnFalse;
	}
	return false;
}

// ************************************************************
//		RecalcHotTracking
// ************************************************************
HotTrackingResult CMapView::RecalcHotTracking(CPoint point, LayerShape& result)
{
	bool cursorCheck = EditorHelper::IsSnappableCursor((tkCursorMode)m_cursorMode) || m_cursorMode == cmEditShape || m_cursorMode == cmIdentify;
	if (!cursorCheck) return NoShape;

	if (_shapeCountInView < m_globalSettings.hotTrackingMaxShapeCount && HasHotTracking())
	{
		result = FindShapeAtScreenPoint(point, slctHotTracking);
		if (!result.IsEmpty()) {
			return _hotTracking.IsSame(result) ? SameShape : NewShape;
		}
	}
	return HotTrackingResult::NoShape;
}

// ************************************************************
//		ClearHotTracking
// ************************************************************
void CMapView::ClearHotTracking()
{
	if (!_hotTracking.IsEmpty())
	{
		_canUseMainBuffer = false;
		_hotTracking.Clear();
		this->FireShapeHighlighted(-1, -1);
	}
}

// ************************************************************
//		UpdateHotTracking
// ************************************************************
void CMapView::UpdateHotTracking(LayerShape info, bool fireEvent)
{
	CComPtr<IShapefile> sf = NULL;
	sf.Attach(GetShapefile(info.LayerHandle));
	if (sf) {
		CComPtr<IShape> shape = NULL;
		sf->get_Shape(info.ShapeIndex, &shape);
		if (shape)
		{
			CComPtr<IShape> shpClone = NULL;
			shape->Clone(&shpClone);
			_hotTracking.Update(sf, shpClone, info.LayerHandle, info.ShapeIndex);

			OLE_COLOR color;
			_identifier->get_OutlineColor(&color);

			CComPtr<IShapeDrawingOptions> options = NULL;
			options.Attach(ShapeStyleHelper::GetHotTrackingStyle(sf, color, m_cursorMode == cmIdentify));
			if (options) {
				_hotTracking.UpdateStyle(options);
			}

			if (fireEvent)
				this->FireShapeHighlighted(_hotTracking.LayerHandle, _hotTracking.ShapeIndex);
			_canUseMainBuffer = false;
		}
	}
}<|endoftext|>