<commit_before>// *****************************************************************************
//
// Copyright (c) 2014, Southwest Research Institute® (SwRI®)
// 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 Southwest Research Institute® (SwRI®) 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 <COPYRIGHT HOLDER> 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 <mapviz/map_canvas.h>

// C++ standard libraries
#include <cmath>

namespace mapviz
{
bool compare_plugins(MapvizPluginPtr a, MapvizPluginPtr b)
{
  return a->DrawOrder() < b->DrawOrder();
}

MapCanvas::MapCanvas(QWidget* parent) :
  QGLWidget(parent),
  has_pixel_buffers_(false),
  pixel_buffer_size_(0),
  pixel_buffer_index_(0),
  capture_frames_(false),
  initialized_(false),
  fix_orientation_(false),
  mouse_pressed_(false),
  mouse_x_(0),
  mouse_y_(0),
  mouse_hovering_(false),
  mouse_hover_x_(0),
  mouse_hover_y_(0),
  offset_x_(0),
  offset_y_(0),
  drag_x_(0),
  drag_y_(0),
  view_center_x_(0),
  view_center_y_(0),
  view_scale_(1),
  view_left_(-25),
  view_right_(25),
  view_top_(10),
  view_bottom_(-10),
  scene_left_(-10),
  scene_right_(10),
  scene_top_(10),
  scene_bottom_(-10)
{
  ROS_INFO("View scale: %f meters/pixel", view_scale_);
  setMouseTracking(true);

  transform_.setIdentity();
}

MapCanvas::~MapCanvas()
{
  if(pixel_buffer_size_ != 0)
  {
    glDeleteBuffersARB(2, pixel_buffer_ids_);
  }
}

void MapCanvas::InitializeTf(boost::shared_ptr<tf::TransformListener> tf)
{
  tf_ = tf;
}

void MapCanvas::InitializePixelBuffers()
{
  if(has_pixel_buffers_)
  {
    int32_t buffer_size = width() * height() * 4;

    if (pixel_buffer_size_ != buffer_size)
    {
      if (pixel_buffer_size_ != 0)
      {
        glDeleteBuffersARB(2, pixel_buffer_ids_);
      }

      glGenBuffersARB(2, pixel_buffer_ids_);
      glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[0]);
      glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffer_size, 0, GL_STREAM_READ_ARB);
      glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[1]);
      glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffer_size, 0, GL_STREAM_READ_ARB);
      glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);

      pixel_buffer_size_ = buffer_size;
    }
  }
}

void MapCanvas::initializeGL()
{
  GLenum err = glewInit();
  if (GLEW_OK != err)
  {
    ROS_ERROR("Error: %s\n", glewGetErrorString(err));
  }
  else
  {
    // Check if pixel buffers are available for asynchronous capturing
    std::string extensions = (const char*)glGetString(GL_EXTENSIONS);
    has_pixel_buffers_ = extensions.find("GL_ARB_pixel_buffer_object") != std::string::npos;
  }

  glClearColor(0.58f, 0.56f, 0.5f, 1);
  glEnable(GL_POINT_SMOOTH);
  glEnable(GL_LINE_SMOOTH);
  glDisable(GL_POLYGON_SMOOTH);
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glDepthFunc(GL_NEVER);
  glDisable(GL_DEPTH_TEST);

  initialized_ = true;
}

void MapCanvas::resizeGL(int w, int h)
{
  UpdateView();
}

void MapCanvas::CaptureFrame(bool force)
{
  // Ensure the pixel size is actually 4
  glPixelStorei(GL_PACK_ALIGNMENT, 4);

  if (has_pixel_buffers_ && !force)
  {
    InitializePixelBuffers();

    pixel_buffer_index_ = (pixel_buffer_index_ + 1) % 2;
    int32_t next_index = (pixel_buffer_index_ + 1) % 2;

    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[pixel_buffer_index_]);
    glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, 0);
    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[next_index]);
    GLubyte* data = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
    if(data)
    {
      capture_buffer_.clear();
      capture_buffer_.resize(pixel_buffer_size_);

      memcpy(&capture_buffer_[0], data, pixel_buffer_size_);

      glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
    }
    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
  }
  else
  {
    int32_t buffer_size = width() * height() * 4;
    capture_buffer_.clear();
    capture_buffer_.resize(buffer_size);

    glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, &capture_buffer_[0]);
  }
}

void MapCanvas::paintGL()
{
  if (capture_frames_)
  {
    CaptureFrame();
  }

  glClearColor(bg_color_.redF(), bg_color_.greenF(), bg_color_.blueF(), 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix();
  TransformTarget();

  // Draw test pattern
  glLineWidth(3);
  glBegin(GL_LINES);
    // Red line to the right
    glColor3f(1, 0, 0);
    glVertex2f(0, 0);
    glVertex2f(20, 0);

    // Green line to the top
    glColor3f(0, 1, 0);
    glVertex2f(0, 0);
    glVertex2f(0, 20);
  glEnd();

  std::list<MapvizPluginPtr>::iterator it;
  for (it = plugins_.begin(); it != plugins_.end(); ++it)
  {
    (*it)->DrawPlugin(view_center_x_, view_center_y_, view_scale_);
  }

  glPopMatrix();
}

void MapCanvas::wheelEvent(QWheelEvent* e)
{
  float numDegrees = e->delta() / -8;

  view_scale_ *= std::pow(1.1, numDegrees / 10.0);

  UpdateView();
}

void MapCanvas::mousePressEvent(QMouseEvent* e)
{
  mouse_x_ = e->x();
  mouse_y_ = e->y();
  drag_x_ = 0;
  drag_y_ = 0;
  mouse_pressed_ = true;
}

void MapCanvas::mouseReleaseEvent(QMouseEvent* e)
{
  mouse_pressed_ = false;
  offset_x_ += drag_x_;
  offset_y_ += drag_y_;
  drag_x_ = 0;
  drag_y_ = 0;
}

void MapCanvas::mouseMoveEvent(QMouseEvent* e)
{
  if (mouse_pressed_ && ((mouse_x_ -  e->x()) != 0 || (mouse_y_ - e->y()) != 0))
  {
    drag_x_ = -((mouse_x_ - e->x()) * view_scale_);
    drag_y_ = ((mouse_y_ - e->y()) * view_scale_);
    update();
  }

  double center_x = -offset_x_ - drag_x_;
  double center_y = -offset_y_ - drag_y_;
  double x = center_x + (e->x() - width() / 2.0) * view_scale_;
  double y = center_y + (height() / 2.0  - e->y()) * view_scale_;

  tf::Point point(x, y, 0);
  point = transform_ * point;

  mouse_hovering_ = true;
  mouse_hover_x_ = e->x();
  mouse_hover_y_ = e->y();
  Q_EMIT Hover(point.x(), point.y(), view_scale_);
}

void MapCanvas::leaveEvent(QEvent* e)
{
  mouse_hovering_ = false;
  Q_EMIT Hover(0, 0, 0);
}

void MapCanvas::SetFixedFrame(const std::string& frame)
{
  fixed_frame_ = frame;
  std::list<MapvizPluginPtr>::iterator it;
  for (it = plugins_.begin(); it != plugins_.end(); ++it)
  {
    (*it)->SetTargetFrame(frame);
  }
  update();
}

void MapCanvas::SetTargetFrame(const std::string& frame)
{
  offset_x_ = 0;
  offset_y_ = 0;
  drag_x_ = 0;
  drag_y_ = 0;

  target_frame_ = frame;
  update();
}

void MapCanvas::ToggleFixOrientation(bool on)
{
  fix_orientation_ = on;
  update();
}

void MapCanvas::ToggleRotate90(bool on)
{
  rotate_90_ = on;
  update();
}

void MapCanvas::ToggleUseLatestTransforms(bool on)
{
  std::list<MapvizPluginPtr>::iterator it;
  for (it = plugins_.begin(); it != plugins_.end(); ++it)
  {
    (*it)->SetUseLatestTransforms(on);
  }

  update();
}

void MapCanvas::AddPlugin(MapvizPluginPtr plugin, int order)
{
  plugins_.push_back(plugin);
}

void MapCanvas::RemovePlugin(MapvizPluginPtr plugin)
{
  plugin->Shutdown();
  plugins_.remove(plugin);
  update();
}

void MapCanvas::TransformTarget()
{
  glTranslatef(offset_x_ + drag_x_, offset_y_ + drag_y_, 0);

  view_center_x_ = -offset_x_ - drag_x_;
  view_center_y_ = -offset_y_ - drag_y_;

  if (!tf_ || fixed_frame_.empty() || target_frame_.empty() || target_frame_ == "<none>")
    return;

  try
  {
    tf_->lookupTransform(fixed_frame_, target_frame_, ros::Time(0), transform_);

    double roll, pitch, yaw;
    transform_.getBasis().getRPY(roll, pitch, yaw);

    if (!fix_orientation_)
    {
      glRotatef(-yaw * 57.2957795, 0, 0, 1);
    }

    if (rotate_90_)
    {
      glRotatef(90, 0, 0, 1);
    }

    glTranslatef(-transform_.getOrigin().getX(), -transform_.getOrigin().getY(), 0);

    tf::Point point(view_center_x_, view_center_y_, 0);

    // If the viewer orientation is fixed don't rotate the center point.
    if (fix_orientation_)
    {
      transform_.setRotation(tf::Transform::getIdentity().getRotation());
    }

    tf::Point center = transform_ * point;

    view_center_x_ = center.getX();
    view_center_y_ = center.getY();

    if (mouse_hovering_)
    {
      double center_x = -offset_x_ - drag_x_;
      double center_y = -offset_y_ - drag_y_;
      double x = center_x + (mouse_hover_x_ - width() / 2.0) * view_scale_;
      double y = center_y + (height() / 2.0  - mouse_hover_y_) * view_scale_;

      tf::Point hover(x, y, 0);
      hover = transform_ * hover;

      Q_EMIT Hover(hover.x(), hover.y(), view_scale_);
    }
  }
  catch (const tf::LookupException& e)
  {
    ROS_ERROR_THROTTLE(2.0, "%s", e.what());
  }
  catch (const tf::ConnectivityException& e)
  {
    ROS_ERROR_THROTTLE(2.0, "%s", e.what());
  }
  catch (const tf::ExtrapolationException& e)
  {
    ROS_ERROR_THROTTLE(2.0, "%s", e.what());
  }
  catch (...)
  {
    ROS_ERROR_THROTTLE(2.0, "Error looking up transform");
  }
}

void MapCanvas::UpdateView()
{
  if (initialized_)
  {
    Recenter();

    glViewport(0, 0, width(), height());
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(view_left_, view_right_, view_top_, view_bottom_, -0.5f, 0.5f);

    update();
  }
}

void MapCanvas::ReorderDisplays()
{
  plugins_.sort(compare_plugins);
}

void MapCanvas::Recenter()
{
  // Recalculate the bounds of the view
  view_left_ = -(width() * view_scale_ * 0.5);
  view_top_ = -(height() * view_scale_ * 0.5);
  view_right_ = (width() * view_scale_ * 0.5);
  view_bottom_ = (height() * view_scale_ * 0.5);
}
}
<commit_msg>Fixing an issue that caused the 90 degree rotation to not be initialized properly.<commit_after>// *****************************************************************************
//
// Copyright (c) 2014, Southwest Research Institute® (SwRI®)
// 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 Southwest Research Institute® (SwRI®) 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 <COPYRIGHT HOLDER> 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 <mapviz/map_canvas.h>

// C++ standard libraries
#include <cmath>
#include <math_util/constants.h>

namespace mapviz
{
bool compare_plugins(MapvizPluginPtr a, MapvizPluginPtr b)
{
  return a->DrawOrder() < b->DrawOrder();
}

MapCanvas::MapCanvas(QWidget* parent) :
  QGLWidget(parent),
  has_pixel_buffers_(false),
  pixel_buffer_size_(0),
  pixel_buffer_index_(0),
  capture_frames_(false),
  initialized_(false),
  fix_orientation_(false),
  rotate_90_(false),
  mouse_pressed_(false),
  mouse_x_(0),
  mouse_y_(0),
  mouse_hovering_(false),
  mouse_hover_x_(0),
  mouse_hover_y_(0),
  offset_x_(0),
  offset_y_(0),
  drag_x_(0),
  drag_y_(0),
  view_center_x_(0),
  view_center_y_(0),
  view_scale_(1),
  view_left_(-25),
  view_right_(25),
  view_top_(10),
  view_bottom_(-10),
  scene_left_(-10),
  scene_right_(10),
  scene_top_(10),
  scene_bottom_(-10)
{
  ROS_INFO("View scale: %f meters/pixel", view_scale_);
  setMouseTracking(true);

  transform_.setIdentity();
}

MapCanvas::~MapCanvas()
{
  if(pixel_buffer_size_ != 0)
  {
    glDeleteBuffersARB(2, pixel_buffer_ids_);
  }
}

void MapCanvas::InitializeTf(boost::shared_ptr<tf::TransformListener> tf)
{
  tf_ = tf;
}

void MapCanvas::InitializePixelBuffers()
{
  if(has_pixel_buffers_)
  {
    int32_t buffer_size = width() * height() * 4;

    if (pixel_buffer_size_ != buffer_size)
    {
      if (pixel_buffer_size_ != 0)
      {
        glDeleteBuffersARB(2, pixel_buffer_ids_);
      }

      glGenBuffersARB(2, pixel_buffer_ids_);
      glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[0]);
      glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffer_size, 0, GL_STREAM_READ_ARB);
      glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[1]);
      glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffer_size, 0, GL_STREAM_READ_ARB);
      glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);

      pixel_buffer_size_ = buffer_size;
    }
  }
}

void MapCanvas::initializeGL()
{
  GLenum err = glewInit();
  if (GLEW_OK != err)
  {
    ROS_ERROR("Error: %s\n", glewGetErrorString(err));
  }
  else
  {
    // Check if pixel buffers are available for asynchronous capturing
    std::string extensions = (const char*)glGetString(GL_EXTENSIONS);
    has_pixel_buffers_ = extensions.find("GL_ARB_pixel_buffer_object") != std::string::npos;
  }

  glClearColor(0.58f, 0.56f, 0.5f, 1);
  glEnable(GL_POINT_SMOOTH);
  glEnable(GL_LINE_SMOOTH);
  glDisable(GL_POLYGON_SMOOTH);
  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glDepthFunc(GL_NEVER);
  glDisable(GL_DEPTH_TEST);

  initialized_ = true;
}

void MapCanvas::resizeGL(int w, int h)
{
  UpdateView();
}

void MapCanvas::CaptureFrame(bool force)
{
  // Ensure the pixel size is actually 4
  glPixelStorei(GL_PACK_ALIGNMENT, 4);

  if (has_pixel_buffers_ && !force)
  {
    InitializePixelBuffers();

    pixel_buffer_index_ = (pixel_buffer_index_ + 1) % 2;
    int32_t next_index = (pixel_buffer_index_ + 1) % 2;

    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[pixel_buffer_index_]);
    glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, 0);
    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pixel_buffer_ids_[next_index]);
    GLubyte* data = (GLubyte*)glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
    if(data)
    {
      capture_buffer_.clear();
      capture_buffer_.resize(pixel_buffer_size_);

      memcpy(&capture_buffer_[0], data, pixel_buffer_size_);

      glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
    }
    glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
  }
  else
  {
    int32_t buffer_size = width() * height() * 4;
    capture_buffer_.clear();
    capture_buffer_.resize(buffer_size);

    glReadPixels(0, 0, width(), height(), GL_BGRA, GL_UNSIGNED_BYTE, &capture_buffer_[0]);
  }
}

void MapCanvas::paintGL()
{
  if (capture_frames_)
  {
    CaptureFrame();
  }

  glClearColor(bg_color_.redF(), bg_color_.greenF(), bg_color_.blueF(), 1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  glPushMatrix();
  TransformTarget();

  // Draw test pattern
  glLineWidth(3);
  glBegin(GL_LINES);
    // Red line to the right
    glColor3f(1, 0, 0);
    glVertex2f(0, 0);
    glVertex2f(20, 0);

    // Green line to the top
    glColor3f(0, 1, 0);
    glVertex2f(0, 0);
    glVertex2f(0, 20);
  glEnd();

  std::list<MapvizPluginPtr>::iterator it;
  for (it = plugins_.begin(); it != plugins_.end(); ++it)
  {
    (*it)->DrawPlugin(view_center_x_, view_center_y_, view_scale_);
  }

  glPopMatrix();
}

void MapCanvas::wheelEvent(QWheelEvent* e)
{
  float numDegrees = e->delta() / -8;

  view_scale_ *= std::pow(1.1, numDegrees / 10.0);

  UpdateView();
}

void MapCanvas::mousePressEvent(QMouseEvent* e)
{
  mouse_x_ = e->x();
  mouse_y_ = e->y();
  drag_x_ = 0;
  drag_y_ = 0;
  mouse_pressed_ = true;
}

void MapCanvas::mouseReleaseEvent(QMouseEvent* e)
{
  mouse_pressed_ = false;
  offset_x_ += drag_x_;
  offset_y_ += drag_y_;
  drag_x_ = 0;
  drag_y_ = 0;
}

void MapCanvas::mouseMoveEvent(QMouseEvent* e)
{
  if (mouse_pressed_ && ((mouse_x_ -  e->x()) != 0 || (mouse_y_ - e->y()) != 0))
  {
    drag_x_ = -((mouse_x_ - e->x()) * view_scale_);
    drag_y_ = ((mouse_y_ - e->y()) * view_scale_);
    update();
  }

  double center_x = -offset_x_ - drag_x_;
  double center_y = -offset_y_ - drag_y_;
  double x = center_x + (e->x() - width() / 2.0) * view_scale_;
  double y = center_y + (height() / 2.0  - e->y()) * view_scale_;

  tf::Point point(x, y, 0);
  point = transform_ * point;

  mouse_hovering_ = true;
  mouse_hover_x_ = e->x();
  mouse_hover_y_ = e->y();
  Q_EMIT Hover(point.x(), point.y(), view_scale_);
}

void MapCanvas::leaveEvent(QEvent* e)
{
  mouse_hovering_ = false;
  Q_EMIT Hover(0, 0, 0);
}

void MapCanvas::SetFixedFrame(const std::string& frame)
{
  fixed_frame_ = frame;
  std::list<MapvizPluginPtr>::iterator it;
  for (it = plugins_.begin(); it != plugins_.end(); ++it)
  {
    (*it)->SetTargetFrame(frame);
  }
  update();
}

void MapCanvas::SetTargetFrame(const std::string& frame)
{
  offset_x_ = 0;
  offset_y_ = 0;
  drag_x_ = 0;
  drag_y_ = 0;

  target_frame_ = frame;
  update();
}

void MapCanvas::ToggleFixOrientation(bool on)
{
  fix_orientation_ = on;
  update();
}

void MapCanvas::ToggleRotate90(bool on)
{
  rotate_90_ = on;
  update();
}

void MapCanvas::ToggleUseLatestTransforms(bool on)
{
  std::list<MapvizPluginPtr>::iterator it;
  for (it = plugins_.begin(); it != plugins_.end(); ++it)
  {
    (*it)->SetUseLatestTransforms(on);
  }

  update();
}

void MapCanvas::AddPlugin(MapvizPluginPtr plugin, int order)
{
  plugins_.push_back(plugin);
}

void MapCanvas::RemovePlugin(MapvizPluginPtr plugin)
{
  plugin->Shutdown();
  plugins_.remove(plugin);
  update();
}

void MapCanvas::TransformTarget()
{
  glTranslatef(offset_x_ + drag_x_, offset_y_ + drag_y_, 0);

  view_center_x_ = -offset_x_ - drag_x_;
  view_center_y_ = -offset_y_ - drag_y_;

  if (!tf_ || fixed_frame_.empty() || target_frame_.empty() || target_frame_ == "<none>")
    return;

  try
  {
    tf_->lookupTransform(fixed_frame_, target_frame_, ros::Time(0), transform_);

    // If the viewer orientation is fixed don't rotate the center point.
    if (fix_orientation_)
    {
      transform_.setRotation(tf::Transform::getIdentity().getRotation());
    }

    if (rotate_90_)
    {
      transform_.setRotation(
          transform_.getRotation() + tf::createQuaternionFromYaw(math_util::_half_pi));
    }

    double roll, pitch, yaw;
    transform_.getBasis().getRPY(roll, pitch, yaw);

    glRotatef(-yaw * 57.2957795, 0, 0, 1);

    glTranslatef(-transform_.getOrigin().getX(), -transform_.getOrigin().getY(), 0);

    tf::Point point(view_center_x_, view_center_y_, 0);

    tf::Point center = transform_ * point;

    view_center_x_ = center.getX();
    view_center_y_ = center.getY();

    if (mouse_hovering_)
    {
      double center_x = -offset_x_ - drag_x_;
      double center_y = -offset_y_ - drag_y_;
      double x = center_x + (mouse_hover_x_ - width() / 2.0) * view_scale_;
      double y = center_y + (height() / 2.0  - mouse_hover_y_) * view_scale_;

      tf::Point hover(x, y, 0);
      hover = transform_ * hover;

      Q_EMIT Hover(hover.x(), hover.y(), view_scale_);
    }
  }
  catch (const tf::LookupException& e)
  {
    ROS_ERROR_THROTTLE(2.0, "%s", e.what());
  }
  catch (const tf::ConnectivityException& e)
  {
    ROS_ERROR_THROTTLE(2.0, "%s", e.what());
  }
  catch (const tf::ExtrapolationException& e)
  {
    ROS_ERROR_THROTTLE(2.0, "%s", e.what());
  }
  catch (...)
  {
    ROS_ERROR_THROTTLE(2.0, "Error looking up transform");
  }
}

void MapCanvas::UpdateView()
{
  if (initialized_)
  {
    Recenter();

    glViewport(0, 0, width(), height());
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(view_left_, view_right_, view_top_, view_bottom_, -0.5f, 0.5f);

    update();
  }
}

void MapCanvas::ReorderDisplays()
{
  plugins_.sort(compare_plugins);
}

void MapCanvas::Recenter()
{
  // Recalculate the bounds of the view
  view_left_ = -(width() * view_scale_ * 0.5);
  view_top_ = -(height() * view_scale_ * 0.5);
  view_right_ = (width() * view_scale_ * 0.5);
  view_bottom_ = (height() * view_scale_ * 0.5);
}
}
<|endoftext|>


<commit_before>#include "JITModule.h"
#include "Target.h"

#include "runtime/HalideRuntime.h"
#include "runtime/HalideRuntimeCuda.h"
#include "runtime/HalideRuntimeOpenCL.h"
#include "runtime/HalideRuntimeOpenGL.h"
#include "runtime/HalideRuntimeOpenGLCompute.h"

using namespace Halide;
using namespace Halide::Internal;

namespace {

template <typename fn_type>
bool lookup_runtime_routine(const char *name, const Target &target,
                            fn_type &result) {
    std::vector<JITModule> runtime(
        JITSharedRuntime::get(nullptr, target.with_feature(Target::JIT)));

    for (size_t i = 0; i < runtime.size(); i++) {
        std::map<std::string, JITModule::Symbol>::const_iterator f =
          runtime[i].exports().find(name);
        if (f != runtime[i].exports().end()) {
            result = reinterpret_bits<fn_type>(f->second.address);
            return true;
        }
    }
    return false;
}

}

extern "C" {

/** Release all data associated with the current GPU backend, in particular
 * all resources (memory, texture, context handles) allocated by Halide. Must
 * be called explicitly when using AOT compilation. */
void halide_device_release(void *user_context, const halide_device_interface *device_interface) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_release\n";
    Target target(get_host_target());
    void (*fn)(void *user_context, const halide_device_interface *device_interface);
    if (lookup_runtime_routine("halide_device_release", target, fn)) {
        (*fn)(user_context, device_interface);
    }
}

/** Copy image data from device memory to host memory. This must be called
 * explicitly to copy back the results of a GPU-based filter. */
int halide_copy_to_host(void *user_context, struct buffer_t *buf) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_copy_to_host\n";
    // Skip if there is no device buffer.
    if (buf->dev == 0)
        return 0;
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_copy_to_host", target, fn)) {
        return (*fn)(user_context, buf);
    }
    return -1;
}

/** Copy image data from host memory to device memory. This should not
 * be called directly; Halide handles copying to the device
 * automatically.  If interface is nullptr and the bug has a non-zero dev
 * field, the device associated with the dev handle will be
 * used. Otherwise if the dev field is 0 and interface is nullptr, an
 * error is returned. */
int halide_copy_to_device(void *user_context, struct buffer_t *buf,
                          const halide_device_interface *device_interface) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_copy_to_device\n";
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf, const halide_device_interface *device_interface);
    if (lookup_runtime_routine("halide_copy_to_device", target, fn)) {
      return (*fn)(user_context, buf, device_interface);
    }
    return -1;
}

/** Wait for current GPU operations to complete. Calling this explicitly
 * should rarely be necessary, except maybe for profiling. */
int halide_device_sync(void *user_context, struct buffer_t *buf) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_sync\n";
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_device_sync", target, fn)) {
      return (*fn)(user_context, buf);
    }
    return -1;
}

/** Allocate device memory to back a buffer_t. */
int halide_device_malloc(void *user_context, struct buffer_t *buf, const halide_device_interface *device_interface) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_malloc\n";
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf, const halide_device_interface *device_interface);
    if (lookup_runtime_routine("halide_device_malloc", target, fn)) {
      return (*fn)(user_context, buf, device_interface);
    }
    return -1;
}

int halide_device_free(void *user_context, struct buffer_t *buf) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_free\n";
    // Skip if there is no device buffer.
    if (buf->dev == 0) {
        return 0;
    }
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_device_free", target, fn)) {
        return (*fn)(user_context, buf);
    }
    if (buf->dev != 0) {
        return -1;
    } else {
        return 0;
    }
}

const struct halide_device_interface *halide_cuda_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::CUDA);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_cuda_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_opencl_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::OpenCL);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_opencl_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_opengl_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::OpenGL);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_opengl_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

int halide_opengl_wrap_texture(void *user_context, struct buffer_t *buf, uintptr_t tex) {
    Target target(get_host_target());
    target.set_feature(Target::OpenGL);
    int (*fn)(void *user_context, struct buffer_t *buf, uint ptr_ttex);
    if (lookup_runtime_routine("halide_opengl_wrap_texture", target, fn)) {
        return (*fn)(user_context, buf, tex);
    }
    return 0;
}

uintptr_t halide_opengl_detach_texture(void *user_context, struct buffer_t *buf) {
    Target target(get_host_target());
    target.set_feature(Target::OpenGL);
    uintptr_t (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_opengl_detach_texture", target, fn)) {
        return (*fn)(user_context, buf);
    }
    return 0;
}

const struct halide_device_interface *halide_openglcompute_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::OpenGLCompute);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_openglcompute_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_renderscript_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::Renderscript);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_renderscript_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_metal_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::Metal);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_metal_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

}
<commit_msg>Attempt to appease msvc<commit_after>#include "JITModule.h"
#include "Target.h"

#include "runtime/HalideRuntime.h"
#include "runtime/HalideRuntimeCuda.h"
#include "runtime/HalideRuntimeOpenCL.h"
#include "runtime/HalideRuntimeOpenGL.h"
#include "runtime/HalideRuntimeOpenGLCompute.h"

using namespace Halide;
using namespace Halide::Internal;

namespace {

template <typename fn_type>
bool lookup_runtime_routine(const char *name, const Target &target,
                            fn_type &result) {
    std::vector<JITModule> runtime(
        JITSharedRuntime::get(nullptr, target.with_feature(Target::JIT)));

    for (size_t i = 0; i < runtime.size(); i++) {
        std::map<std::string, JITModule::Symbol>::const_iterator f =
          runtime[i].exports().find(name);
        if (f != runtime[i].exports().end()) {
            result = reinterpret_bits<fn_type>(f->second.address);
            return true;
        }
    }
    return false;
}

}

extern "C" {

/** Release all data associated with the current GPU backend, in particular
 * all resources (memory, texture, context handles) allocated by Halide. Must
 * be called explicitly when using AOT compilation. */
void halide_device_release(void *user_context, const halide_device_interface *device_interface) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_release\n";
    Target target(get_host_target());
    void (*fn)(void *user_context, const halide_device_interface *device_interface);
    if (lookup_runtime_routine("halide_device_release", target, fn)) {
        (*fn)(user_context, device_interface);
    }
}

/** Copy image data from device memory to host memory. This must be called
 * explicitly to copy back the results of a GPU-based filter. */
int halide_copy_to_host(void *user_context, struct buffer_t *buf) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_copy_to_host\n";
    // Skip if there is no device buffer.
    if (buf->dev == 0)
        return 0;
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_copy_to_host", target, fn)) {
        return (*fn)(user_context, buf);
    }
    return -1;
}

/** Copy image data from host memory to device memory. This should not
 * be called directly; Halide handles copying to the device
 * automatically.  If interface is nullptr and the bug has a non-zero dev
 * field, the device associated with the dev handle will be
 * used. Otherwise if the dev field is 0 and interface is nullptr, an
 * error is returned. */
int halide_copy_to_device(void *user_context, struct buffer_t *buf,
                          const halide_device_interface *device_interface) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_copy_to_device\n";
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf, const halide_device_interface *device_interface);
    if (lookup_runtime_routine("halide_copy_to_device", target, fn)) {
      return (*fn)(user_context, buf, device_interface);
    }
    return -1;
}

/** Wait for current GPU operations to complete. Calling this explicitly
 * should rarely be necessary, except maybe for profiling. */
int halide_device_sync(void *user_context, struct buffer_t *buf) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_sync\n";
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_device_sync", target, fn)) {
      return (*fn)(user_context, buf);
    }
    return -1;
}

/** Allocate device memory to back a buffer_t. */
int halide_device_malloc(void *user_context, struct buffer_t *buf, const halide_device_interface *device_interface) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_malloc\n";
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf, const halide_device_interface *device_interface);
    if (lookup_runtime_routine("halide_device_malloc", target, fn)) {
      return (*fn)(user_context, buf, device_interface);
    }
    return -1;
}

int halide_device_free(void *user_context, struct buffer_t *buf) {
    user_assert(user_context == nullptr) << "Cannot provide user_context to libHalide.a halide_device_free\n";
    // Skip if there is no device buffer.
    if (buf->dev == 0) {
        return 0;
    }
    Target target(get_host_target());
    int (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_device_free", target, fn)) {
        return (*fn)(user_context, buf);
    }
    if (buf->dev != 0) {
        return -1;
    } else {
        return 0;
    }
}

const struct halide_device_interface *halide_cuda_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::CUDA);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_cuda_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_opencl_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::OpenCL);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_opencl_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_opengl_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::OpenGL);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_opengl_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

int halide_opengl_wrap_texture(void *user_context, struct buffer_t *buf, uintptr_t tex) {
    Target target(get_host_target());
    target.set_feature(Target::OpenGL);
    int (*fn)(void *, struct buffer_t *, uintptr_t);
    if (lookup_runtime_routine("halide_opengl_wrap_texture", target, fn)) {
        return (*fn)(user_context, buf, tex);
    }
    return 0;
}

uintptr_t halide_opengl_detach_texture(void *user_context, struct buffer_t *buf) {
    Target target(get_host_target());
    target.set_feature(Target::OpenGL);
    uintptr_t (*fn)(void *user_context, struct buffer_t *buf);
    if (lookup_runtime_routine("halide_opengl_detach_texture", target, fn)) {
        return (*fn)(user_context, buf);
    }
    return 0;
}

const struct halide_device_interface *halide_openglcompute_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::OpenGLCompute);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_openglcompute_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_renderscript_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::Renderscript);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_renderscript_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

const struct halide_device_interface *halide_metal_device_interface() {
    Target target(get_host_target());
    target.set_feature(Target::Metal);
    struct halide_device_interface *(*fn)();
    if (lookup_runtime_routine("halide_metal_device_interface", target, fn)) {
        return (*fn)();
    }
    return nullptr;
}

}
<|endoftext|>


<commit_before>#include "sanitizer_common/sanitizer_atomic.h"

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>

#ifdef KERNEL_USE
extern "C" void ubsan_message(const char *msg);
static void message(const char *msg) { ubsan_message(msg); }
#else
static void message(const char *msg) {
  write(2, msg, strlen(msg));
}
#endif

static const int kMaxCallerPcs = 20;
static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
// Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
// that "too many errors" has already been reported.
static __sanitizer::atomic_uint32_t caller_pcs_sz;

__attribute__((noinline)) static bool report_this_error(void *caller_p) {
  uintptr_t caller = reinterpret_cast<uintptr_t>(caller_p);
  if (caller == 0) return false;
  while (true) {
    unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz);
    if (sz > kMaxCallerPcs) return false;  // early exit
    // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg
    // succeeds in order to not print it multiple times.
    if (sz > 0 && sz < kMaxCallerPcs) {
      uintptr_t p;
      for (unsigned i = 0; i < sz; ++i) {
        p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]);
        if (p == 0) break;  // Concurrent update.
        if (p == caller) return false;
      }
      if (p == 0) continue;  // FIXME: yield?
    }

    if (!__sanitizer::atomic_compare_exchange_strong(
            &caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst))
      continue;  // Concurrent update! Try again from the start.

    if (sz == kMaxCallerPcs) {
      message("ubsan: too many errors\n");
      return false;
    }
    __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
    return true;
  }
}

#if defined(__ANDROID__)
extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
static void abort_with_message(const char *msg) {
  if (&android_set_abort_message) android_set_abort_message(msg);
  abort();
}
#else
static void abort_with_message(const char *) { abort(); }
#endif

#define INTERFACE extern "C" __attribute__((visibility("default")))

// FIXME: add caller pc to the error message (possibly as "ubsan: error-type
// @1234ABCD").
#define HANDLER_RECOVER(name, msg)                               \
  INTERFACE void __ubsan_handle_##name##_minimal() {             \
    if (!report_this_error(__builtin_return_address(0))) return; \
    message("ubsan: " msg "\n");                                 \
  }

#define HANDLER_NORECOVER(name, msg)                             \
  INTERFACE void __ubsan_handle_##name##_minimal_abort() {       \
    message("ubsan: " msg "\n");                                 \
    abort_with_message("ubsan: " msg);                           \
  }

#define HANDLER(name, msg)                                       \
  HANDLER_RECOVER(name, msg)                                     \
  HANDLER_NORECOVER(name, msg)

HANDLER(type_mismatch, "type-mismatch")
HANDLER(add_overflow, "add-overflow")
HANDLER(sub_overflow, "sub-overflow")
HANDLER(mul_overflow, "mul-overflow")
HANDLER(negate_overflow, "negate-overflow")
HANDLER(divrem_overflow, "divrem-overflow")
HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
HANDLER(out_of_bounds, "out-of-bounds")
HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
HANDLER_RECOVER(missing_return, "missing-return")
HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
HANDLER(float_cast_overflow, "float-cast-overflow")
HANDLER(load_invalid_value, "load-invalid-value")
HANDLER(invalid_builtin, "invalid-builtin")
HANDLER(function_type_mismatch, "function-type-mismatch")
HANDLER(nonnull_arg, "nonnull-arg")
HANDLER(nonnull_return, "nonnull-return")
HANDLER(nullability_arg, "nullability-arg")
HANDLER(nullability_return, "nullability-return")
HANDLER(pointer_overflow, "pointer-overflow")
HANDLER(cfi_check_fail, "cfi-check-fail")
<commit_msg>[ubsan-minimal] Fix the ubsan_minimal debug build (COMPILER_RT_DEBUG=1) on macOS.<commit_after>#include "sanitizer_common/sanitizer_atomic.h"

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>

#ifdef KERNEL_USE
extern "C" void ubsan_message(const char *msg);
static void message(const char *msg) { ubsan_message(msg); }
#else
static void message(const char *msg) {
  write(2, msg, strlen(msg));
}
#endif

static const int kMaxCallerPcs = 20;
static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
// Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
// that "too many errors" has already been reported.
static __sanitizer::atomic_uint32_t caller_pcs_sz;

__attribute__((noinline)) static bool report_this_error(void *caller_p) {
  uintptr_t caller = reinterpret_cast<uintptr_t>(caller_p);
  if (caller == 0) return false;
  while (true) {
    unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz);
    if (sz > kMaxCallerPcs) return false;  // early exit
    // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg
    // succeeds in order to not print it multiple times.
    if (sz > 0 && sz < kMaxCallerPcs) {
      uintptr_t p;
      for (unsigned i = 0; i < sz; ++i) {
        p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]);
        if (p == 0) break;  // Concurrent update.
        if (p == caller) return false;
      }
      if (p == 0) continue;  // FIXME: yield?
    }

    if (!__sanitizer::atomic_compare_exchange_strong(
            &caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst))
      continue;  // Concurrent update! Try again from the start.

    if (sz == kMaxCallerPcs) {
      message("ubsan: too many errors\n");
      return false;
    }
    __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
    return true;
  }
}

#if defined(__ANDROID__)
extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
static void abort_with_message(const char *msg) {
  if (&android_set_abort_message) android_set_abort_message(msg);
  abort();
}
#else
static void abort_with_message(const char *) { abort(); }
#endif

#if SANITIZER_DEBUG
namespace __sanitizer {
// The DCHECK macro needs this symbol to be defined.
void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
  message("Sanitizer CHECK failed: ");
  message(file);
  message(":?? : "); // FIXME: Show line number.
  message(cond);
  abort();
}
} // namespace __sanitizer
#endif

#define INTERFACE extern "C" __attribute__((visibility("default")))

// FIXME: add caller pc to the error message (possibly as "ubsan: error-type
// @1234ABCD").
#define HANDLER_RECOVER(name, msg)                               \
  INTERFACE void __ubsan_handle_##name##_minimal() {             \
    if (!report_this_error(__builtin_return_address(0))) return; \
    message("ubsan: " msg "\n");                                 \
  }

#define HANDLER_NORECOVER(name, msg)                             \
  INTERFACE void __ubsan_handle_##name##_minimal_abort() {       \
    message("ubsan: " msg "\n");                                 \
    abort_with_message("ubsan: " msg);                           \
  }

#define HANDLER(name, msg)                                       \
  HANDLER_RECOVER(name, msg)                                     \
  HANDLER_NORECOVER(name, msg)

HANDLER(type_mismatch, "type-mismatch")
HANDLER(add_overflow, "add-overflow")
HANDLER(sub_overflow, "sub-overflow")
HANDLER(mul_overflow, "mul-overflow")
HANDLER(negate_overflow, "negate-overflow")
HANDLER(divrem_overflow, "divrem-overflow")
HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
HANDLER(out_of_bounds, "out-of-bounds")
HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
HANDLER_RECOVER(missing_return, "missing-return")
HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
HANDLER(float_cast_overflow, "float-cast-overflow")
HANDLER(load_invalid_value, "load-invalid-value")
HANDLER(invalid_builtin, "invalid-builtin")
HANDLER(function_type_mismatch, "function-type-mismatch")
HANDLER(nonnull_arg, "nonnull-arg")
HANDLER(nonnull_return, "nonnull-return")
HANDLER(nullability_arg, "nullability-arg")
HANDLER(nullability_return, "nullability-return")
HANDLER(pointer_overflow, "pointer-overflow")
HANDLER(cfi_check_fail, "cfi-check-fail")
<|endoftext|>


<commit_before>/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "c2/protocols/RESTProtocol.h"

#include "core/TypedValues.h"
#include <algorithm>
#include <memory>
#include <utility>
#include <map>
#include <string>
#include <vector>
#include <list>

namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace c2 {

const C2Payload RESTProtocol::parseJsonResponse(const C2Payload &payload, const std::vector<char> &response) {
#ifndef WIN32
  rapidjson::Document root;

  try {
    rapidjson::ParseResult ok = root.Parse(response.data(), response.size());
    if (ok) {
      std::string requested_operation = getOperation(payload);

      std::string identifier;
      if (root.HasMember("operationid")) {
        identifier = root["operationid"].GetString();
      } else if (root.HasMember("operationId")) {
        identifier = root["operationId"].GetString();
      } else if (root.HasMember("identifier")) {
        identifier = root["identifier"].GetString();
      }
      if (root["requested_operations"].Size() == 0 && root["requestedOperations"].Size() == 0)
        return C2Payload(payload.getOperation(), state::UpdateState::READ_COMPLETE, true);

      C2Payload new_payload(payload.getOperation(), state::UpdateState::NESTED, true);

      if (!identifier.empty())
        new_payload.setIdentifier(identifier);
      auto array = root["requested_operations"].GetArray();
      if (root["requested_operations"].Size() == 0)
        array = root["requestedOperations"].GetArray();
      for (const rapidjson::Value& request : array) {
        Operation newOp = stringToOperation(request["operation"].GetString());
        C2Payload nested_payload(newOp, state::UpdateState::READ_COMPLETE, true);
        C2ContentResponse new_command(newOp);
        new_command.delay = 0;
        new_command.required = true;
        new_command.ttl = -1;

        // set the identifier if one exists
        if (request.HasMember("operationid")) {
          if (request["operationid"].IsNumber())
            new_command.ident = std::to_string(request["operationid"].GetInt64());
          else if (request["operationid"].IsString())
            new_command.ident = request["operationid"].GetString();
          else
            throw(Exception(SITE2SITE_EXCEPTION, "Invalid type for operationid"));
          nested_payload.setIdentifier(new_command.ident);
        } else if (request.HasMember("operationId")) {
          if (request["operationId"].IsNumber())
            new_command.ident = std::to_string(request["operationId"].GetInt64());
          else if (request["operationId"].IsString())
            new_command.ident = request["operationId"].GetString();
          else
            throw(Exception(SITE2SITE_EXCEPTION, "Invalid type for operationId"));
          nested_payload.setIdentifier(new_command.ident);
        } else if (request.HasMember("identifier")) {
          if (request["identifier"].IsNumber())
            new_command.ident = std::to_string(request["identifier"].GetInt64());
          else if (request["identifier"].IsString())
            new_command.ident = request["identifier"].GetString();
          else
            throw(Exception(SITE2SITE_EXCEPTION, "Invalid type for operationid"));
          nested_payload.setIdentifier(new_command.ident);
        }

        if (request.HasMember("name")) {
          new_command.name = request["name"].GetString();
        } else if (request.HasMember("operand")) {
          new_command.name = request["operand"].GetString();
        }

        if (request.HasMember("content") && request["content"].MemberCount() > 0) {
          if (request["content"].IsArray()) {
            for (const auto &member : request["content"].GetArray())
              new_command.operation_arguments[member.GetString()] = member.GetString();
          } else {
            for (const auto &member : request["content"].GetObject())
              new_command.operation_arguments[member.name.GetString()] = member.value.GetString();
          }
        } else if (request.HasMember("args") && request["args"].MemberCount() > 0) {
          if (request["args"].IsArray()) {
            for (const auto &member : request["args"].GetArray())
              new_command.operation_arguments[member.GetString()] = member.GetString();
          } else {
            for (const auto &member : request["args"].GetObject())
              new_command.operation_arguments[member.name.GetString()] = member.value.GetString();
          }
        }
        nested_payload.addContent(std::move(new_command));
        new_payload.addPayload(std::move(nested_payload));
      }

      // we have a response for this request
      return new_payload;
      // }
    }
  } catch (...) {
  }
#endif
  return C2Payload(payload.getOperation(), state::UpdateState::READ_COMPLETE, true);
}

void setJsonStr(const std::string& key, const state::response::ValueNode& value, rapidjson::Value& parent, rapidjson::Document::AllocatorType& alloc) {  // NOLINT
  rapidjson::Value keyVal;
  rapidjson::Value valueVal;
  const char* c_key = key.c_str();
  auto base_type = value.getValue();
  keyVal.SetString(c_key, key.length(), alloc);

  auto type_index = base_type->getTypeIndex();
  if (auto sub_type = std::dynamic_pointer_cast<core::TransformableValue>(base_type)) {
    auto str = base_type->getStringValue();
    const char* c_val = str.c_str();
    valueVal.SetString(c_val, str.length(), alloc);
  } else {
    if (type_index == state::response::Value::BOOL_TYPE) {
      bool value = false;
      base_type->convertValue(value);
      valueVal.SetBool(value);
    } else if (type_index == state::response::Value::INT_TYPE) {
      int value = 0;
      base_type->convertValue(value);
      valueVal.SetInt(value);
    } else if (type_index == state::response::Value::INT64_TYPE) {
      int64_t value = 0;
      base_type->convertValue(value);
      valueVal.SetInt64(value);
    } else if (type_index == state::response::Value::UINT64_TYPE) {
      int64_t value = 0;
      base_type->convertValue(value);
      valueVal.SetInt64(value);
    } else {
      auto str = base_type->getStringValue();
      const char* c_val = str.c_str();
      valueVal.SetString(c_val, str.length(), alloc);
    }
  }
  parent.AddMember(keyVal, valueVal, alloc);
}

rapidjson::Value RESTProtocol::getStringValue(const std::string& value, rapidjson::Document::AllocatorType& alloc) {  // NOLINT
  rapidjson::Value Val;
  Val.SetString(value.c_str(), value.length(), alloc);
  return Val;
}

void RESTProtocol::mergePayloadContent(rapidjson::Value &target, const C2Payload &payload, rapidjson::Document::AllocatorType &alloc) {
  const std::vector<C2ContentResponse> &content = payload.getContent();
  bool all_empty = !content.empty();
  bool is_parent_array = target.IsArray();

  for (const auto &payload_content : content) {
    for (const auto &op_arg : payload_content.operation_arguments) {
      if (!op_arg.second.empty()) {
        all_empty = false;
        break;
      }
    }
    if (!all_empty)
      break;
  }

  if (all_empty) {
    if (!is_parent_array) {
      target.SetArray();
      is_parent_array = true;
    }
    rapidjson::Value arr(rapidjson::kArrayType);
    for (const auto &payload_content : content) {
      for (const auto& op_arg : payload_content.operation_arguments) {
        rapidjson::Value keyVal;
        keyVal.SetString(op_arg.first.c_str(), op_arg.first.length(), alloc);
        if (is_parent_array) {
          target.PushBack(keyVal, alloc);
        } else {
          arr.PushBack(keyVal, alloc);
        }
      }
    }

    if (!is_parent_array) {
      rapidjson::Value sub_key = getStringValue(payload.getLabel(), alloc);
      target.AddMember(sub_key, arr, alloc);
    }
    return;
  }
  for (const auto &payload_content : content) {
    rapidjson::Value payload_content_values(rapidjson::kObjectType);
    bool use_sub_option = true;
    if (payload_content.op == payload.getOperation()) {
      for (const auto& op_arg : payload_content.operation_arguments) {
        if (!op_arg.second.empty()) {
          setJsonStr(op_arg.first, op_arg.second, target, alloc);
        }
      }
    } else {
    }
    if (use_sub_option) {
      rapidjson::Value sub_key = getStringValue(payload_content.name, alloc);
    }
  }
}

std::string RESTProtocol::serializeJsonRootPayload(const C2Payload& payload) {
  rapidjson::Document json_payload(payload.isContainer() ? rapidjson::kArrayType : rapidjson::kObjectType);
  rapidjson::Document::AllocatorType &alloc = json_payload.GetAllocator();

  rapidjson::Value opReqStrVal;
  std::string operation_request_str = getOperation(payload);
  opReqStrVal.SetString(operation_request_str.c_str(), operation_request_str.length(), alloc);
  json_payload.AddMember("operation", opReqStrVal, alloc);

  std::string operationid = payload.getIdentifier();
  if (operationid.length() > 0) {
    json_payload.AddMember("operationid", getStringValue(operationid, alloc), alloc);
    json_payload.AddMember("operationId", getStringValue(operationid, alloc), alloc);
    json_payload.AddMember("identifier", getStringValue(operationid, alloc), alloc);
  }

  mergePayloadContent(json_payload, payload, alloc);

  for (const auto &nested_payload : payload.getNestedPayloads()) {
    if (!minimize_updates_ || (minimize_updates_ && !containsPayload(nested_payload))) {
      rapidjson::Value np_key = getStringValue(nested_payload.getLabel(), alloc);
      rapidjson::Value np_value = serializeJsonPayload(nested_payload, alloc);
      if (minimize_updates_) {
        nested_payloads_.insert(std::pair<std::string, C2Payload>(nested_payload.getLabel(), nested_payload));
      }
      json_payload.AddMember(np_key, np_value, alloc);
    }
  }

  rapidjson::StringBuffer buffer;
  rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
  json_payload.Accept(writer);
  return buffer.GetString();
}

bool RESTProtocol::containsPayload(const C2Payload &o) {
  auto it = nested_payloads_.find(o.getLabel());
  if (it != nested_payloads_.end()) {
    return it->second == o;
  }
  return false;
}

rapidjson::Value RESTProtocol::serializeJsonPayload(const C2Payload &payload, rapidjson::Document::AllocatorType &alloc) {
// get the name from the content
  rapidjson::Value json_payload(payload.isContainer() ? rapidjson::kArrayType : rapidjson::kObjectType);

  std::vector<ValueObject> children;

  for (const auto &nested_payload : payload.getNestedPayloads()) {
    rapidjson::Value* child_payload = new rapidjson::Value(serializeJsonPayload(nested_payload, alloc));

    if (nested_payload.isCollapsible()) {
      bool combine = false;
      for (auto &subordinate : children) {
        if (subordinate.name == nested_payload.getLabel()) {
          subordinate.values.push_back(child_payload);
          combine = true;
          break;
        }
      }
      if (!combine) {
        ValueObject obj;
        obj.name = nested_payload.getLabel();
        obj.values.push_back(child_payload);
        children.push_back(obj);
      }
    } else {
      ValueObject obj;
      obj.name = nested_payload.getLabel();
      obj.values.push_back(child_payload);
      children.push_back(obj);
    }
  }

  for (auto child_vector : children) {
    rapidjson::Value children_json;
    rapidjson::Value newMemberKey = getStringValue(child_vector.name, alloc);
    if (child_vector.values.size() > 1) {
      children_json.SetArray();
      for (auto child : child_vector.values) {
        if (json_payload.IsArray())
          json_payload.PushBack(child->Move(), alloc);
        else
          children_json.PushBack(child->Move(), alloc);
      }
      if (!json_payload.IsArray())
        json_payload.AddMember(newMemberKey, children_json, alloc);
    } else if (child_vector.values.size() == 1) {
      rapidjson::Value* first = child_vector.values.front();
      if (first->IsObject() && first->HasMember(newMemberKey)) {
        if (json_payload.IsArray())
          json_payload.PushBack((*first)[newMemberKey].Move(), alloc);
        else
          json_payload.AddMember(newMemberKey, (*first)[newMemberKey].Move(), alloc);
      } else {
        if (json_payload.IsArray()) {
          json_payload.PushBack(first->Move(), alloc);
        } else {
          json_payload.AddMember(newMemberKey, first->Move(), alloc);
        }
      }
    }
    for (rapidjson::Value* child : child_vector.values)
      delete child;
  }

  mergePayloadContent(json_payload, payload, alloc);
  return json_payload;
}

std::string RESTProtocol::getOperation(const C2Payload &payload) {
  switch (payload.getOperation()) {
    case Operation::ACKNOWLEDGE:
      return "acknowledge";
    case Operation::HEARTBEAT:
      return "heartbeat";
    case Operation::RESTART:
      return "restart";
    case Operation::DESCRIBE:
      return "describe";
    case Operation::STOP:
      return "stop";
    case Operation::START:
      return "start";
    case Operation::UPDATE:
      return "update";
    default:
      return "heartbeat";
  }
}

Operation RESTProtocol::stringToOperation(const std::string str) {
  std::string op = str;
  std::transform(str.begin(), str.end(), op.begin(), ::tolower);
  if (op == "heartbeat") {
    return Operation::HEARTBEAT;
  } else if (op == "acknowledge") {
    return Operation::ACKNOWLEDGE;
  } else if (op == "update") {
    return Operation::UPDATE;
  } else if (op == "describe") {
    return Operation::DESCRIBE;
  } else if (op == "restart") {
    return Operation::RESTART;
  } else if (op == "clear") {
    return Operation::CLEAR;
  } else if (op == "stop") {
    return Operation::STOP;
  } else if (op == "start") {
    return Operation::START;
  }
  return Operation::HEARTBEAT;
}

} /* namespace c2 */
} /* namespace minifi */
} /* namespace nifi */
} /* namespace apache */
} /* namespace org */
<commit_msg>MINIFICPP-739: Resolve json checks for c2 responses<commit_after>/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "c2/protocols/RESTProtocol.h"

#include "core/TypedValues.h"
#include <algorithm>
#include <memory>
#include <utility>
#include <map>
#include <string>
#include <vector>
#include <list>

namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace c2 {

#ifdef WIN32
#pragma push_macro("GetObject")
#undef GetObject
#endif
const C2Payload RESTProtocol::parseJsonResponse(const C2Payload &payload, const std::vector<char> &response) {
  rapidjson::Document root;

  try {
    rapidjson::ParseResult ok = root.Parse(response.data(), response.size());
    if (ok) {

      std::string requested_operation = getOperation(payload);

      std::string identifier;

      if (root.HasMember("operationid")) {
        identifier = root["operationid"].GetString();
      } else if (root.HasMember("operationId")) {
        identifier = root["operationId"].GetString();
      } else if (root.HasMember("identifier")) {
        identifier = root["identifier"].GetString();
      }

      int size = 0;
      if (root.HasMember("requested_operations")) {
        size = root["requested_operations"].Size();
      }
      if (root.HasMember("requestedOperations")) {
        size = root["requestedOperations"].Size();
      }

      // neither must be there. We don't want assign array yet and cause an assertion error
      if (size == 0)
        return C2Payload(payload.getOperation(), state::UpdateState::READ_COMPLETE, true);

      C2Payload new_payload(payload.getOperation(), state::UpdateState::NESTED, true);
      if (!identifier.empty())
        new_payload.setIdentifier(identifier);

      auto array = root.HasMember("requested_operations") ? root["requested_operations"].GetArray() : root["requestedOperations"].GetArray();

      for (const rapidjson::Value& request : array) {
        Operation newOp = stringToOperation(request["operation"].GetString());
        C2Payload nested_payload(newOp, state::UpdateState::READ_COMPLETE, true);
        C2ContentResponse new_command(newOp);
        new_command.delay = 0;
        new_command.required = true;
        new_command.ttl = -1;

        // set the identifier if one exists
        if (request.HasMember("operationid")) {
          if (request["operationid"].IsNumber())
            new_command.ident = std::to_string(request["operationid"].GetInt64());
          else if (request["operationid"].IsString())
            new_command.ident = request["operationid"].GetString();
          else
            throw(Exception(SITE2SITE_EXCEPTION, "Invalid type for operationid"));
          nested_payload.setIdentifier(new_command.ident);
        } else if (request.HasMember("operationId")) {
          if (request["operationId"].IsNumber())
            new_command.ident = std::to_string(request["operationId"].GetInt64());
          else if (request["operationId"].IsString())
            new_command.ident = request["operationId"].GetString();
          else
            throw(Exception(SITE2SITE_EXCEPTION, "Invalid type for operationId"));
          nested_payload.setIdentifier(new_command.ident);
        } else if (request.HasMember("identifier")) {
          if (request["identifier"].IsNumber())
            new_command.ident = std::to_string(request["identifier"].GetInt64());
          else if (request["identifier"].IsString())
            new_command.ident = request["identifier"].GetString();
          else
            throw(Exception(SITE2SITE_EXCEPTION, "Invalid type for operationid"));
          nested_payload.setIdentifier(new_command.ident);
        }

        if (request.HasMember("name")) {
          new_command.name = request["name"].GetString();
        } else if (request.HasMember("operand")) {
          new_command.name = request["operand"].GetString();
        }

        if (request.HasMember("content") && request["content"].MemberCount() > 0) {
          if (request["content"].IsArray()) {
            for (const auto &member : request["content"].GetArray())
              new_command.operation_arguments[member.GetString()] = member.GetString();
          } else {
            for (const auto &member : request["content"].GetObject())
              new_command.operation_arguments[member.name.GetString()] = member.value.GetString();
          }
        } else if (request.HasMember("args") && request["args"].MemberCount() > 0) {
          if (request["args"].IsArray()) {
            for (const auto &member : request["args"].GetArray())
              new_command.operation_arguments[member.GetString()] = member.GetString();
          } else {
            for (const auto &member : request["args"].GetObject())
              new_command.operation_arguments[member.name.GetString()] = member.value.GetString();
          }
        }
        nested_payload.addContent(std::move(new_command));
        new_payload.addPayload(std::move(nested_payload));
      }

      // we have a response for this request
      return new_payload;
      // }
    }
  } catch (const std::exception &e) {

  } catch (...) {
  }
  return C2Payload(payload.getOperation(), state::UpdateState::READ_COMPLETE, true);
}

void setJsonStr(const std::string& key, const state::response::ValueNode& value, rapidjson::Value& parent, rapidjson::Document::AllocatorType& alloc) {  // NOLINT
  rapidjson::Value keyVal;
  rapidjson::Value valueVal;
  const char* c_key = key.c_str();
  auto base_type = value.getValue();
  keyVal.SetString(c_key, key.length(), alloc);

  auto type_index = base_type->getTypeIndex();
  if (auto sub_type = std::dynamic_pointer_cast<core::TransformableValue>(base_type)) {
    auto str = base_type->getStringValue();
    const char* c_val = str.c_str();
    valueVal.SetString(c_val, str.length(), alloc);
  } else {
    if (type_index == state::response::Value::BOOL_TYPE) {
      bool value = false;
      base_type->convertValue(value);
      valueVal.SetBool(value);
    } else if (type_index == state::response::Value::INT_TYPE) {
      int value = 0;
      base_type->convertValue(value);
      valueVal.SetInt(value);
    } else if (type_index == state::response::Value::INT64_TYPE) {
      int64_t value = 0;
      base_type->convertValue(value);
      valueVal.SetInt64(value);
    } else if (type_index == state::response::Value::UINT64_TYPE) {
      int64_t value = 0;
      base_type->convertValue(value);
      valueVal.SetInt64(value);
    } else {
      auto str = base_type->getStringValue();
      const char* c_val = str.c_str();
      valueVal.SetString(c_val, str.length(), alloc);
    }
  }
  parent.AddMember(keyVal, valueVal, alloc);
}

rapidjson::Value RESTProtocol::getStringValue(const std::string& value, rapidjson::Document::AllocatorType& alloc) {  // NOLINT
  rapidjson::Value Val;
  Val.SetString(value.c_str(), value.length(), alloc);
  return Val;
}

void RESTProtocol::mergePayloadContent(rapidjson::Value &target, const C2Payload &payload, rapidjson::Document::AllocatorType &alloc) {
  const std::vector<C2ContentResponse> &content = payload.getContent();
  bool all_empty = !content.empty();
  bool is_parent_array = target.IsArray();

  for (const auto &payload_content : content) {
    for (const auto &op_arg : payload_content.operation_arguments) {
      if (!op_arg.second.empty()) {
        all_empty = false;
        break;
      }
    }
    if (!all_empty)
      break;
  }

  if (all_empty) {
    if (!is_parent_array) {
      target.SetArray();
      is_parent_array = true;
    }
    rapidjson::Value arr(rapidjson::kArrayType);
    for (const auto &payload_content : content) {
      for (const auto& op_arg : payload_content.operation_arguments) {
        rapidjson::Value keyVal;
        keyVal.SetString(op_arg.first.c_str(), op_arg.first.length(), alloc);
        if (is_parent_array) {
          target.PushBack(keyVal, alloc);
        } else {
          arr.PushBack(keyVal, alloc);
        }
      }
    }

    if (!is_parent_array) {
      rapidjson::Value sub_key = getStringValue(payload.getLabel(), alloc);
      target.AddMember(sub_key, arr, alloc);
    }
    return;
  }
  for (const auto &payload_content : content) {
    rapidjson::Value payload_content_values(rapidjson::kObjectType);
    bool use_sub_option = true;
    if (payload_content.op == payload.getOperation()) {
      for (const auto& op_arg : payload_content.operation_arguments) {
        if (!op_arg.second.empty()) {
          setJsonStr(op_arg.first, op_arg.second, target, alloc);
        }
      }
    } else {
    }
    if (use_sub_option) {
      rapidjson::Value sub_key = getStringValue(payload_content.name, alloc);
    }
  }
}

std::string RESTProtocol::serializeJsonRootPayload(const C2Payload& payload) {
  rapidjson::Document json_payload(payload.isContainer() ? rapidjson::kArrayType : rapidjson::kObjectType);
  rapidjson::Document::AllocatorType &alloc = json_payload.GetAllocator();

  rapidjson::Value opReqStrVal;
  std::string operation_request_str = getOperation(payload);
  opReqStrVal.SetString(operation_request_str.c_str(), operation_request_str.length(), alloc);
  json_payload.AddMember("operation", opReqStrVal, alloc);

  std::string operationid = payload.getIdentifier();
  if (operationid.length() > 0) {
    json_payload.AddMember("operationid", getStringValue(operationid, alloc), alloc);
    json_payload.AddMember("operationId", getStringValue(operationid, alloc), alloc);
    json_payload.AddMember("identifier", getStringValue(operationid, alloc), alloc);
  }

  mergePayloadContent(json_payload, payload, alloc);

  for (const auto &nested_payload : payload.getNestedPayloads()) {
    if (!minimize_updates_ || (minimize_updates_ && !containsPayload(nested_payload))) {
      rapidjson::Value np_key = getStringValue(nested_payload.getLabel(), alloc);
      rapidjson::Value np_value = serializeJsonPayload(nested_payload, alloc);
      if (minimize_updates_) {
        nested_payloads_.insert(std::pair<std::string, C2Payload>(nested_payload.getLabel(), nested_payload));
      }
      json_payload.AddMember(np_key, np_value, alloc);
    }
  }

  rapidjson::StringBuffer buffer;
  rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
  json_payload.Accept(writer);
  return buffer.GetString();
}

bool RESTProtocol::containsPayload(const C2Payload &o) {
  auto it = nested_payloads_.find(o.getLabel());
  if (it != nested_payloads_.end()) {
    return it->second == o;
  }
  return false;
}

rapidjson::Value RESTProtocol::serializeJsonPayload(const C2Payload &payload, rapidjson::Document::AllocatorType &alloc) {
// get the name from the content
  rapidjson::Value json_payload(payload.isContainer() ? rapidjson::kArrayType : rapidjson::kObjectType);

  std::vector<ValueObject> children;

  for (const auto &nested_payload : payload.getNestedPayloads()) {
    rapidjson::Value* child_payload = new rapidjson::Value(serializeJsonPayload(nested_payload, alloc));

    if (nested_payload.isCollapsible()) {
      bool combine = false;
      for (auto &subordinate : children) {
        if (subordinate.name == nested_payload.getLabel()) {
          subordinate.values.push_back(child_payload);
          combine = true;
          break;
        }
      }
      if (!combine) {
        ValueObject obj;
        obj.name = nested_payload.getLabel();
        obj.values.push_back(child_payload);
        children.push_back(obj);
      }
    } else {
      ValueObject obj;
      obj.name = nested_payload.getLabel();
      obj.values.push_back(child_payload);
      children.push_back(obj);
    }
  }

  for (auto child_vector : children) {
    rapidjson::Value children_json;
    rapidjson::Value newMemberKey = getStringValue(child_vector.name, alloc);
    if (child_vector.values.size() > 1) {
      children_json.SetArray();
      for (auto child : child_vector.values) {
        if (json_payload.IsArray())
          json_payload.PushBack(child->Move(), alloc);
        else
          children_json.PushBack(child->Move(), alloc);
      }
      if (!json_payload.IsArray())
        json_payload.AddMember(newMemberKey, children_json, alloc);
    } else if (child_vector.values.size() == 1) {
      rapidjson::Value* first = child_vector.values.front();
      if (first->IsObject() && first->HasMember(newMemberKey)) {
        if (json_payload.IsArray())
          json_payload.PushBack((*first)[newMemberKey].Move(), alloc);
        else
          json_payload.AddMember(newMemberKey, (*first)[newMemberKey].Move(), alloc);
      } else {
        if (json_payload.IsArray()) {
          json_payload.PushBack(first->Move(), alloc);
        } else {
          json_payload.AddMember(newMemberKey, first->Move(), alloc);
        }
      }
    }
    for (rapidjson::Value* child : child_vector.values)
      delete child;
  }

  mergePayloadContent(json_payload, payload, alloc);
  return json_payload;
}

std::string RESTProtocol::getOperation(const C2Payload &payload) {
  switch (payload.getOperation()) {
    case Operation::ACKNOWLEDGE:
      return "acknowledge";
    case Operation::HEARTBEAT:
      return "heartbeat";
    case Operation::RESTART:
      return "restart";
    case Operation::DESCRIBE:
      return "describe";
    case Operation::STOP:
      return "stop";
    case Operation::START:
      return "start";
    case Operation::UPDATE:
      return "update";
    default:
      return "heartbeat";
  }
}

Operation RESTProtocol::stringToOperation(const std::string str) {
  std::string op = str;
  std::transform(str.begin(), str.end(), op.begin(), ::tolower);
  if (op == "heartbeat") {
    return Operation::HEARTBEAT;
  } else if (op == "acknowledge") {
    return Operation::ACKNOWLEDGE;
  } else if (op == "update") {
    return Operation::UPDATE;
  } else if (op == "describe") {
    return Operation::DESCRIBE;
  } else if (op == "restart") {
    return Operation::RESTART;
  } else if (op == "clear") {
    return Operation::CLEAR;
  } else if (op == "stop") {
    return Operation::STOP;
  } else if (op == "start") {
    return Operation::START;
  }
  return Operation::HEARTBEAT;
}
#ifdef WIN32
#pragma pop_macro("GetObject")
#endif
} /* namespace c2 */
} /* namespace minifi */
} /* namespace nifi */
} /* namespace apache */
} /* namespace org */
<|endoftext|>


<commit_before>#include "WelcomePage.hpp"
#include <QProcess>
#include <iostream>

#include <QFileDialog>
#include <QMessageBox>
#include <QFile>

#include "Connecting.hpp"

WelcomePage::WelcomePage(QWidget *parent) :
	QWidget(parent)
{
	ui.setupUi(this);

	ui.lblTitle->resetText("Where do you want to go?");
	QFont fnt(ui.lblTitle->font());
	fnt.setFamily("Ubuntu Light");
	fnt.setPointSize(16);
	ui.lblTitle->setFont(fnt);
	ui.btnErrOk->setFont(fnt);

	fnt.setPointSize(14);
	ui.lblErr->setFont(fnt);
	m_last_page = 0;

	connect(ui.btnErrOk, SIGNAL(clicked()), this, SLOT(restorePage()));
}

WelcomePage::~WelcomePage()
{

}

void WelcomePage::on_btnConnect_clicked()
{
	ui.lblTitle->setText("Connecting to DisCODe");
	ui.stackedWidget->setCurrentIndex(1);
}

void WelcomePage::on_btnConnectOk_clicked()
{
	m_last_page = 1;
	emit do_connect_sig(ui.editConnectHost->text(), ui.editConnectPort->text());
}

void WelcomePage::on_btnConnectCancel_clicked()
{
	ui.lblTitle->setText("Where do you want to go?");
	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::on_btnSpawn_clicked()
{
	ui.lblTitle->setText("Spawning DisCODe process");
	ui.stackedWidget->setCurrentIndex(2);
}

void WelcomePage::on_btnSpawnOk_clicked()
{
	QString program = "discode";
	QStringList arguments;
	arguments << "-T" << ui.editTaskName->text();
	m_last_page = 2;

	if (!QProcess::startDetached(program, arguments))
		showError("Could not spawn DisCODe!");
	else {
		//QMessageBox::information(this, tr("Info"), tr("DisCODe spawned."));
		emit do_connect_sig(ui.editConnectHost->text(), ui.editConnectPort->text());
	}
//
//	ui.lblTitle->setText("Where do you want to go?");
//	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::on_btnSpawnCancel_clicked()
{
	ui.lblTitle->setText("Where do you want to go?");
	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::reset() {
	ui.lblTitle->setText("Where do you want to go?");
	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::on_btnLoadTask_linkActivated ( const QString & link )
{
	if (link == "load") {
		QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("XML files (*.xml);;All files (*.*)"));

		if (fileName != "") {
			QFile file(fileName);
			if (!file.open(QIODevice::ReadOnly)) {
				QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
			} else {
				ui.editTaskName->setText(fileName);
				file.close();
			}
		}
	}

}

void WelcomePage::showError(const QString& text) {
	ui.lblTitle->setText("Error!");
	ui.lblErr->setText(text);
	ui.stackedWidget->setCurrentIndex(3);
}

void WelcomePage::restorePage() {
	QStringList titles;
	titles << "Where do you want to go?";
	titles << "Connecting to DisCODe";
	titles << "Spawning DisCODe process";

	ui.lblTitle->setText(titles[m_last_page]);
	ui.stackedWidget->setCurrentIndex(m_last_page);

	m_last_page = 0;
}
<commit_msg>Added trimming of whitespaces in task name<commit_after>#include "WelcomePage.hpp"
#include <QProcess>
#include <iostream>

#include <QFileDialog>
#include <QMessageBox>
#include <QFile>

#include "Connecting.hpp"

WelcomePage::WelcomePage(QWidget *parent) :
	QWidget(parent)
{
	ui.setupUi(this);

	ui.lblTitle->resetText("Where do you want to go?");
	QFont fnt(ui.lblTitle->font());
	fnt.setFamily("Ubuntu Light");
	fnt.setPointSize(16);
	ui.lblTitle->setFont(fnt);
	ui.btnErrOk->setFont(fnt);

	fnt.setPointSize(14);
	ui.lblErr->setFont(fnt);
	m_last_page = 0;

	connect(ui.btnErrOk, SIGNAL(clicked()), this, SLOT(restorePage()));
}

WelcomePage::~WelcomePage()
{

}

void WelcomePage::on_btnConnect_clicked()
{
	ui.lblTitle->setText("Connecting to DisCODe");
	ui.stackedWidget->setCurrentIndex(1);
}

void WelcomePage::on_btnConnectOk_clicked()
{
	m_last_page = 1;
	emit do_connect_sig(ui.editConnectHost->text(), ui.editConnectPort->text());
}

void WelcomePage::on_btnConnectCancel_clicked()
{
	ui.lblTitle->setText("Where do you want to go?");
	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::on_btnSpawn_clicked()
{
	ui.lblTitle->setText("Spawning DisCODe process");
	ui.stackedWidget->setCurrentIndex(2);
}

void WelcomePage::on_btnSpawnOk_clicked()
{
	QString program = "discode";
	QStringList arguments;
	arguments << "-T" << ui.editTaskName->text().trimmed();
	m_last_page = 2;

	if (!QProcess::startDetached(program, arguments))
		showError("Could not spawn DisCODe!");
	else {
		//QMessageBox::information(this, tr("Info"), tr("DisCODe spawned."));
		emit do_connect_sig(ui.editConnectHost->text(), ui.editConnectPort->text());
	}
//
//	ui.lblTitle->setText("Where do you want to go?");
//	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::on_btnSpawnCancel_clicked()
{
	ui.lblTitle->setText("Where do you want to go?");
	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::reset() {
	ui.lblTitle->setText("Where do you want to go?");
	ui.stackedWidget->setCurrentIndex(0);
}

void WelcomePage::on_btnLoadTask_linkActivated ( const QString & link )
{
	if (link == "load") {
		QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", tr("XML files (*.xml);;All files (*.*)"));

		if (fileName != "") {
			QFile file(fileName);
			if (!file.open(QIODevice::ReadOnly)) {
				QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
			} else {
				ui.editTaskName->setText(fileName);
				file.close();
			}
		}
	}

}

void WelcomePage::showError(const QString& text) {
	ui.lblTitle->setText("Error!");
	ui.lblErr->setText(text);
	ui.stackedWidget->setCurrentIndex(3);
}

void WelcomePage::restorePage() {
	QStringList titles;
	titles << "Where do you want to go?";
	titles << "Connecting to DisCODe";
	titles << "Spawning DisCODe process";

	ui.lblTitle->setText(titles[m_last_page]);
	ui.stackedWidget->setCurrentIndex(m_last_page);

	m_last_page = 0;
}
<|endoftext|>