<commit_before>/* Required for CPU_ALLOC(), ... */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif

#include <unistd.h>
#include <sched.h>

#include <cassert>
#include <memory>
#include <vector>

#include "cpu-count.hh"
#include "cpu-foreach.hh"
#include "thread.hh"

namespace mimosa
{
void cpuForeach(const std::function<void ()>& cb, bool affinity, size_t ratio)
{
  assert(ratio >= 1);

  std::vector<Thread> threads;
  size_t nproc = cpuCount();
  threads.resize(nproc * ratio);

  for (size_t i = 0; i < nproc * ratio; ++i)
  {
    threads[i].start([i, nproc, &cb, affinity, ratio] {
#ifdef HAS_SCHED_SETAFFINITY
      cpu_set_t * set = nullptr;
      if (affinity)
      {
        set = CPU_ALLOC(nproc);
        assert(set);
        CPU_ZERO_S(nproc, set);
        CPU_SET(i / ratio, set);

        sched_setaffinity(0, CPU_ALLOC_SIZE(nproc), set);
      }
#endif /* HAS_SCHED_SETAFFINITY */

      try {
        cb();
      } catch (...) {
      }
#ifdef HAS_SCHED_SETAFFINITY
      if (affinity)
        CPU_FREE(set);
#endif
    });
  }

  for (int i = 0; i < nproc * ratio; ++i)
    threads[i].join();
}
}
<commit_msg>Fix type<commit_after>/* Required for CPU_ALLOC(), ... */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif

#include <unistd.h>
#include <sched.h>

#include <cassert>
#include <memory>
#include <vector>

#include "cpu-count.hh"
#include "cpu-foreach.hh"
#include "thread.hh"

namespace mimosa
{
void cpuForeach(const std::function<void ()>& cb, bool affinity, size_t ratio)
{
  assert(ratio >= 1);

  std::vector<Thread> threads;
  size_t nproc = cpuCount();
  threads.resize(nproc * ratio);

  for (size_t i = 0; i < nproc * ratio; ++i)
  {
    threads[i].start([i, nproc, &cb, affinity, ratio] {
#ifdef HAS_SCHED_SETAFFINITY
      cpu_set_t * set = nullptr;
      if (affinity)
      {
        set = CPU_ALLOC(nproc);
        assert(set);
        CPU_ZERO_S(nproc, set);
        CPU_SET(i / ratio, set);

        sched_setaffinity(0, CPU_ALLOC_SIZE(nproc), set);
      }
#endif /* HAS_SCHED_SETAFFINITY */

      try {
        cb();
      } catch (...) {
      }
#ifdef HAS_SCHED_SETAFFINITY
      if (affinity)
        CPU_FREE(set);
#endif
    });
  }

  for (size_t i = 0; i < nproc * ratio; ++i)
    threads[i].join();
}
}
<|endoftext|>


<commit_before>/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */
#include "backuptest.h"
#include <signond/signoncommon.h>
 #include <QDBusMessage>

void TestBackup::initTestCase()
{
    /*
    daemonProcess = new QProcess();
    daemonProcess->start("signond");
    daemonProcess->waitForStarted(10 * 1000);
    */
}

void TestBackup::cleanupTestCase()
{
/*
    daemonProcess->kill();
    daemonProcess->waitForFinished();
    delete daemonProcess;
*/
}
void TestBackup::init()
{
    //wait a bit between tests
    sleep(5);
}
void TestBackup::cleanup()
{
    sleep(1);
}

void TestBackup::backupTest()
{
    QDBusConnection conn (SIGNOND_BUS);
    QDBusMessage msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "prestart");
    QDBusMessage reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //remove backup files
    QFile::remove("/home/user/.signon/signondb.bin");

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "backup");
    QList<QVariant> args;
    args.append(QStringList("settings"));
    msg.setArguments(args);
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check if backup file was created successfully
    QVERIFY(QFile::exists("/home/user/.signon/signondb.bin"));

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "close");
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

}
void TestBackup::restoreTest()
{
    QDBusConnection conn (SIGNOND_BUS);
    QDBusMessage msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "prestart");
    QDBusMessage reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "restore");
    QList<QVariant> args;
    args.append(QStringList("settings"));
    args.append(QString("harmattan"));
    args.append(QStringList());
    msg.setArguments(args);
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check if backup file was created successfully
    QVERIFY(QFile::remove("/home/user/.signon/signondb.bin"));
    QVERIFY(QFile::exists("/home/user/signon.db"));

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "close");
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

}

void TestBackup::backupNormalTest()
{

    daemonProcess = new QProcess();
    daemonProcess->start("signond");
    daemonProcess->waitForStarted(10 * 1000);

    QDBusConnection conn (SIGNOND_BUS);
    QDBusMessage msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "prestart");
    QDBusMessage reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //remove backup files
    QFile::remove("/home/user/.signon/signondb.bin");

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "backup");
    QList<QVariant> args;
    args.append(QStringList("settings"));
    msg.setArguments(args);
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check if backup file was created successfully
    QVERIFY(QFile::exists("/home/user/.signon/signondb.bin"));

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "close");
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check that daemon is still running normally after backup close signal
    QVERIFY(daemonProcess->state()==QProcess::Running);
    daemonProcess->kill();
    daemonProcess->waitForFinished();
    delete daemonProcess;
    daemonProcess = NULL;
}
void TestBackup::restoreNormalTest()
{

    daemonProcess = new QProcess();
    daemonProcess->start("signond");
    daemonProcess->waitForStarted(10 * 1000);

    QDBusConnection conn (SIGNOND_BUS);
    QDBusMessage msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "prestart");
    QDBusMessage reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "restore");
    QList<QVariant> args;
    args.append(QStringList("settings"));
    args.append(QString("harmattan"));
    args.append(QStringList());
    msg.setArguments(args);
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check if backup file was created successfully
    QVERIFY(QFile::remove("/home/user/.signon/signondb.bin"));
    QVERIFY(QFile::exists("/home/user/signon.db"));

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "close");
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check that daemon is still running normally after backup close signal
    QVERIFY(daemonProcess->state()==QProcess::Running);
    daemonProcess->kill();
    daemonProcess->waitForFinished();
    delete daemonProcess;
    daemonProcess = NULL;

}

void TestBackup::runAllTests()
{
    initTestCase();

    init();
    backupTest();
    cleanup();

    init();
    restoreTest();
    cleanup();

    init();
    backupNormalTest();
    cleanup();

    init();
    restoreNormalTest();
    cleanup();

    cleanupTestCase();
}

#if !defined(SSO_CI_TESTMANAGEMENT)
    QTEST_MAIN(TestPluginProxy)
#endif
<commit_msg>changes in backup unit tests<commit_after>/*
 * This file is part of signon
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */
#include "backuptest.h"
#include <signond/signoncommon.h>
 #include <QDBusMessage>

void TestBackup::initTestCase()
{
    /*
    daemonProcess = new QProcess();
    daemonProcess->start("signond");
    daemonProcess->waitForStarted(10 * 1000);
    */
}

void TestBackup::cleanupTestCase()
{
/*
    daemonProcess->kill();
    daemonProcess->waitForFinished();
    delete daemonProcess;
*/
}
void TestBackup::init()
{
    //wait a bit between tests
    sleep(5);
}
void TestBackup::cleanup()
{
    sleep(1);
}

void TestBackup::backupTest()
{
    QDBusConnection conn (SIGNOND_BUS);

    //remove backup files
    QFile::remove("/home/user/.signon/signondb.bin");

    QDBusMessage msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                                      SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                                      "com.nokia.backupclient",
                                                      "backupStarts");
    QList<QVariant> args;
    msg.setArguments(args);

    QDBusMessage reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check if backup file was created successfully
    QVERIFY(QFile::exists("/home/user/.signon/signondb.bin"));
    QFile::copy("/home/user/.signon/signondb.bin", "/home/user/.signon/signondb.bin2");

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "backupFinished");
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);
    QVERIFY(QFile::exists("/home/user/.signon/signondb.bin") == false);

}
void TestBackup::restoreTest()
{
    QDBusConnection conn (SIGNOND_BUS);

    QVERIFY(QFile::exists("/home/user/.signon/signondb.bin2"));
    QFile::rename("/home/user/.signon/signondb.bin2", "/home/user/.signon/signondb.bin");

    QDBusMessage msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                                      SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                                      "com.nokia.backupclient",
                                                      "restoreStarts");
    QList<QVariant> args;
    msg.setArguments(args);

    QDBusMessage reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

    //check if backup file was created successfully

    msg = QDBusMessage::createMethodCall(SIGNOND_SERVICE + ".backup",
                                            SIGNOND_DAEMON_OBJECTPATH + "/backup",
                                            "com.nokia.backupclient",
                                            "restoreFinished");
    reply = conn.call(msg, QDBus::Block, 10*1000);

    QVERIFY(QFile::exists("/home/user/.signon/signondb.bin") == false);
    QVERIFY(QFile::exists("/home/user/signon.db"));

    QVERIFY(reply.type() == QDBusMessage::ReplyMessage);

}

void TestBackup::backupNormalTest()
{

    daemonProcess = new QProcess();
    daemonProcess->start("signond");
    daemonProcess->waitForStarted(10 * 1000);

    backupTest();

    //check that daemon is still running normally after backup close signal
    QVERIFY(daemonProcess->state()==QProcess::Running);
    daemonProcess->kill();
    daemonProcess->waitForFinished();
    delete daemonProcess;
    daemonProcess = NULL;
}
void TestBackup::restoreNormalTest()
{

    daemonProcess = new QProcess();
    daemonProcess->start("signond");
    daemonProcess->waitForStarted(10 * 1000);

    restoreTest();

    //check that daemon is still running normally after backup close signal
    QVERIFY(daemonProcess->state()==QProcess::Running);
    daemonProcess->kill();
    daemonProcess->waitForFinished();
    delete daemonProcess;
    daemonProcess = NULL;

}

void TestBackup::runAllTests()
{
    initTestCase();

    init();
    backupTest();
    cleanup();

    init();
    restoreTest();
    cleanup();

    init();
    backupNormalTest();
    cleanup();

    init();
    restoreNormalTest();
    cleanup();

    cleanupTestCase();
}

#if !defined(SSO_CI_TESTMANAGEMENT)
    QTEST_MAIN(TestBackup)
#endif
<|endoftext|>


<commit_before><commit_msg>fwk160: #i113943# catch the exception<commit_after><|endoftext|>


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

 The Medical Imaging Interaction Toolkit (MITK)

 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.

 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.

 See LICENSE.txt or http://www.mitk.org for details.

 ===================================================================*/

#include "QmitkRenderWindow.h"

#include "mitkInteractionKeyEvent.h"
#include "mitkInternalEvent.h"
#include "mitkMouseDoubleClickEvent.h"
#include "mitkMouseMoveEvent.h"
#include "mitkMousePressEvent.h"
#include "mitkMouseReleaseEvent.h"
#include "mitkMouseWheelEvent.h"
#include <QCursor>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QSurfaceFormat>
#include <QTimer>
#include <QWheelEvent>
#include <QWindow>

#include "QmitkMimeTypes.h"
#include "QmitkRenderWindowMenu.h"

QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, const QString &name, mitk::VtkPropRenderer *, mitk::RenderingManager *renderingManager, mitk::BaseRenderer::RenderingMode::Type renderingMode)
  : QVTKOpenGLWidget(parent),
    m_ResendQtEvents(true),
    m_MenuWidget(nullptr),
    m_MenuWidgetActivated(false),
    m_LayoutIndex(0)
{
  m_InternalRenderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
  m_InternalRenderWindow->SetMultiSamples(0);
  m_InternalRenderWindow->SetAlphaBitPlanes(0);

  this->SetRenderWindow(m_InternalRenderWindow);

  this->Initialize(renderingManager, name.toStdString().c_str(), renderingMode);

  this->setFocusPolicy(Qt::StrongFocus);
  this->setMouseTracking(true);
  QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  this->setSizePolicy(sizePolicy);
}

QmitkRenderWindow::~QmitkRenderWindow()
{
  Destroy(); // Destroy mitkRenderWindowBase
}

void QmitkRenderWindow::SetResendQtEvents(bool resend)
{
  m_ResendQtEvents = resend;
}

void QmitkRenderWindow::SetLayoutIndex(unsigned int layoutIndex)
{
  m_LayoutIndex = layoutIndex;
  if (m_MenuWidget)
    m_MenuWidget->SetLayoutIndex(layoutIndex);
}

unsigned int QmitkRenderWindow::GetLayoutIndex()
{
  if (m_MenuWidget)
    return m_MenuWidget->GetLayoutIndex();
  else
    return 0;
}

void QmitkRenderWindow::LayoutDesignListChanged(int layoutDesignIndex)
{
  if (m_MenuWidget)
    m_MenuWidget->UpdateLayoutDesignList(layoutDesignIndex);
}

bool QmitkRenderWindow::event(QEvent* e)
{
  mitk::InteractionEvent::Pointer mitkEvent = nullptr;
  switch (e->type())
  {
    case QEvent::MouseMove:
    {
      auto me = static_cast<QMouseEvent *>(e);
      mitkEvent = mitk::MouseMoveEvent::New(m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me));
      break;
    }
    case QEvent::MouseButtonPress:
    {
      auto me = static_cast<QMouseEvent *>(e);
      mitkEvent = mitk::MousePressEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me));
      break;
    }
    case QEvent::MouseButtonRelease:
    {
      auto me = static_cast<QMouseEvent *>(e);
      mitkEvent = mitk::MouseReleaseEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me));
      break;
    }
    case QEvent::MouseButtonDblClick:
    {
      auto me = static_cast<QMouseEvent *>(e);
      mitkEvent = mitk::MouseDoubleClickEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me));
      break;
    }
    case QEvent::Wheel:
    {
      auto we = static_cast<QWheelEvent *>(e);
      mitkEvent = mitk::MouseWheelEvent::New( m_Renderer, GetMousePosition(we), GetButtonState(we), GetModifiers(we), GetDelta(we));
      break;
    }
    case QEvent::KeyPress:
    {
      auto ke = static_cast<QKeyEvent*>(e);
      mitkEvent = mitk::InteractionKeyEvent::New(m_Renderer, GetKeyLetter(ke), GetModifiers(ke));
      break;
    }
  }

  if (mitkEvent != nullptr)
  {
    if (this->HandleEvent(mitkEvent.GetPointer())) {
      return m_ResendQtEvents ? false : true;
    }
  }

  return QVTKOpenGLWidget::event(e);
}

void QmitkRenderWindow::enterEvent(QEvent *e)
{
  // TODO implement new event
  QVTKOpenGLWidget::enterEvent(e);
}

void QmitkRenderWindow::DeferredHideMenu()
{
  MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu";

  if (m_MenuWidget)
    m_MenuWidget->HideMenu();
}

void QmitkRenderWindow::leaveEvent(QEvent *e)
{
  mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(this->m_Renderer, nullptr, "LeaveRenderWindow");

  this->HandleEvent(internalEvent.GetPointer());

  if (m_MenuWidget)
    m_MenuWidget->smoothHide();

  QVTKOpenGLWidget::leaveEvent(e);
}

//-----------------------------------------------------------------------------
void QmitkRenderWindow::resizeGL(int w, int h)
{
  this->GetRenderer()->GetRenderingManager()->ForceImmediateUpdate(GetRenderWindow());
  QVTKOpenGLWidget::resizeGL(w, h);
}

void QmitkRenderWindow::moveEvent(QMoveEvent *event)
{
  QVTKOpenGLWidget::moveEvent(event);

  // after a move the overlays need to be positioned
  emit moved();
}

void QmitkRenderWindow::showEvent(QShowEvent *event)
{
  QVTKOpenGLWidget::showEvent(event);

  // this singleshot is necessary to have the overlays positioned correctly after initial show
  // simple call of moved() is no use here!!
  QTimer::singleShot(0, this, SIGNAL(moved()));
}

void QmitkRenderWindow::ActivateMenuWidget(bool state, QmitkStdMultiWidget *stdMultiWidget)
{
  m_MenuWidgetActivated = state;

  if (!m_MenuWidgetActivated && m_MenuWidget)
  {
    // disconnect Signal/Slot Connection
    disconnect(m_MenuWidget, SIGNAL(SignalChangeLayoutDesign(int)), this, SLOT(OnChangeLayoutDesign(int)));
    disconnect(m_MenuWidget, SIGNAL(ResetView()), this, SIGNAL(ResetView()));
    disconnect(m_MenuWidget, SIGNAL(ChangeCrosshairRotationMode(int)), this, SIGNAL(ChangeCrosshairRotationMode(int)));

    delete m_MenuWidget;
    m_MenuWidget = nullptr;
  }
  else if (m_MenuWidgetActivated && !m_MenuWidget)
  {
    // create render window MenuBar for split, close Window or set new setting.
    m_MenuWidget = new QmitkRenderWindowMenu(this, nullptr, m_Renderer, stdMultiWidget);
    m_MenuWidget->SetLayoutIndex(m_LayoutIndex);

    // create Signal/Slot Connection
    connect(m_MenuWidget, SIGNAL(SignalChangeLayoutDesign(int)), this, SLOT(OnChangeLayoutDesign(int)));
    connect(m_MenuWidget, SIGNAL(ResetView()), this, SIGNAL(ResetView()));
    connect(m_MenuWidget, SIGNAL(ChangeCrosshairRotationMode(int)), this, SIGNAL(ChangeCrosshairRotationMode(int)));
  }
}

void QmitkRenderWindow::AdjustRenderWindowMenuVisibility(const QPoint & /*pos*/)
{
  if (m_MenuWidget)
  {
    m_MenuWidget->ShowMenu();
    m_MenuWidget->MoveWidgetToCorrectPos(1.0f);
  }
}

void QmitkRenderWindow::HideRenderWindowMenu()
{
  // DEPRECATED METHOD
}

void QmitkRenderWindow::OnChangeLayoutDesign(int layoutDesignIndex)
{
  emit SignalLayoutDesignChanged(layoutDesignIndex);
}

void QmitkRenderWindow::OnWidgetPlaneModeChanged(int mode)
{
  if (m_MenuWidget)
    m_MenuWidget->NotifyNewWidgetPlanesMode(mode);
}

void QmitkRenderWindow::FullScreenMode(bool state)
{
  if (m_MenuWidget)
    m_MenuWidget->ChangeFullScreenMode(state);
}

void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event)
{
  if (event->mimeData()->hasFormat("application/x-mitk-datanodes"))
  {
    event->accept();
  }
}

void QmitkRenderWindow::dropEvent(QDropEvent *event)
{
  QList<mitk::DataNode *> dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData());
  if (!dataNodeList.empty())
  {
    emit NodesDropped(this, dataNodeList.toVector().toStdVector());
  }
}

mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent *me) const
{
  mitk::Point2D point;
  point[0] = me->x();
  // We need to convert the y component, as the display and vtk have other definitions for the y direction
  point[1] = m_Renderer->GetSizeY() - me->y();
  return point;
}

mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent *we) const
{
  mitk::Point2D point;
  point[0] = we->x();
  // We need to convert the y component, as the display and vtk have other definitions for the y direction
  point[1] = m_Renderer->GetSizeY() - we->y();
  return point;
}

mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent *me) const
{
  mitk::InteractionEvent::MouseButtons eventButton;
  switch (me->button())
  {
    case Qt::LeftButton:
      eventButton = mitk::InteractionEvent::LeftMouseButton;
      break;
    case Qt::RightButton:
      eventButton = mitk::InteractionEvent::RightMouseButton;
      break;
    case Qt::MidButton:
      eventButton = mitk::InteractionEvent::MiddleMouseButton;
      break;
    default:
      eventButton = mitk::InteractionEvent::NoButton;
      break;
  }
  return eventButton;
}

mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent *me) const
{
  mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton;

  if (me->buttons() & Qt::LeftButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton;
  }
  if (me->buttons() & Qt::RightButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::RightMouseButton;
  }
  if (me->buttons() & Qt::MidButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton;
  }
  return buttonState;
}

mitk::InteractionEvent::ModifierKeys QmitkRenderWindow::GetModifiers(QInputEvent *me) const
{
  mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey;

  if (me->modifiers() & Qt::ALT)
  {
    modifiers = modifiers | mitk::InteractionEvent::AltKey;
  }
  if (me->modifiers() & Qt::CTRL)
  {
    modifiers = modifiers | mitk::InteractionEvent::ControlKey;
  }
  if (me->modifiers() & Qt::SHIFT)
  {
    modifiers = modifiers | mitk::InteractionEvent::ShiftKey;
  }
  return modifiers;
}

mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent *we) const
{
  mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton;

  if (we->buttons() & Qt::LeftButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton;
  }
  if (we->buttons() & Qt::RightButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::RightMouseButton;
  }
  if (we->buttons() & Qt::MidButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton;
  }
  return buttonState;
}

std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) const
{
  // Converting Qt Key Event to string element.
  std::string key = "";
  int tkey = ke->key();
  if (tkey < 128)
  { // standard ascii letter
    key = (char)toupper(tkey);
  }
  else
  { // special keys
    switch (tkey)
    {
      case Qt::Key_Return:
        key = mitk::InteractionEvent::KeyReturn;
        break;
      case Qt::Key_Enter:
        key = mitk::InteractionEvent::KeyEnter;
        break;
      case Qt::Key_Escape:
        key = mitk::InteractionEvent::KeyEsc;
        break;
      case Qt::Key_Delete:
        key = mitk::InteractionEvent::KeyDelete;
        break;
      case Qt::Key_Up:
        key = mitk::InteractionEvent::KeyArrowUp;
        break;
      case Qt::Key_Down:
        key = mitk::InteractionEvent::KeyArrowDown;
        break;
      case Qt::Key_Left:
        key = mitk::InteractionEvent::KeyArrowLeft;
        break;
      case Qt::Key_Right:
        key = mitk::InteractionEvent::KeyArrowRight;
        break;

      case Qt::Key_F1:
        key = mitk::InteractionEvent::KeyF1;
        break;
      case Qt::Key_F2:
        key = mitk::InteractionEvent::KeyF2;
        break;
      case Qt::Key_F3:
        key = mitk::InteractionEvent::KeyF3;
        break;
      case Qt::Key_F4:
        key = mitk::InteractionEvent::KeyF4;
        break;
      case Qt::Key_F5:
        key = mitk::InteractionEvent::KeyF5;
        break;
      case Qt::Key_F6:
        key = mitk::InteractionEvent::KeyF6;
        break;
      case Qt::Key_F7:
        key = mitk::InteractionEvent::KeyF7;
        break;
      case Qt::Key_F8:
        key = mitk::InteractionEvent::KeyF8;
        break;
      case Qt::Key_F9:
        key = mitk::InteractionEvent::KeyF9;
        break;
      case Qt::Key_F10:
        key = mitk::InteractionEvent::KeyF10;
        break;
      case Qt::Key_F11:
        key = mitk::InteractionEvent::KeyF11;
        break;
      case Qt::Key_F12:
        key = mitk::InteractionEvent::KeyF12;
        break;

      case Qt::Key_End:
        key = mitk::InteractionEvent::KeyEnd;
        break;
      case Qt::Key_Home:
        key = mitk::InteractionEvent::KeyPos1;
        break;
      case Qt::Key_Insert:
        key = mitk::InteractionEvent::KeyInsert;
        break;
      case Qt::Key_PageDown:
        key = mitk::InteractionEvent::KeyPageDown;
        break;
      case Qt::Key_PageUp:
        key = mitk::InteractionEvent::KeyPageUp;
        break;
      case Qt::Key_Space:
        key = mitk::InteractionEvent::KeySpace;
        break;
    }
  }
  return key;
}

int QmitkRenderWindow::GetDelta(QWheelEvent *we) const
{
  return we->delta();
}
<commit_msg>Re-introduce call to enable render-window menus (removed without intention)<commit_after>/*===================================================================

 The Medical Imaging Interaction Toolkit (MITK)

 Copyright (c) German Cancer Research Center,
 Division of Medical and Biological Informatics.
 All rights reserved.

 This software is distributed WITHOUT ANY WARRANTY; without
 even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.

 See LICENSE.txt or http://www.mitk.org for details.

 ===================================================================*/

#include "QmitkRenderWindow.h"

#include "mitkInteractionKeyEvent.h"
#include "mitkInternalEvent.h"
#include "mitkMouseDoubleClickEvent.h"
#include "mitkMouseMoveEvent.h"
#include "mitkMousePressEvent.h"
#include "mitkMouseReleaseEvent.h"
#include "mitkMouseWheelEvent.h"
#include <QCursor>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QResizeEvent>
#include <QSurfaceFormat>
#include <QTimer>
#include <QWheelEvent>
#include <QWindow>

#include "QmitkMimeTypes.h"
#include "QmitkRenderWindowMenu.h"

QmitkRenderWindow::QmitkRenderWindow(QWidget *parent, const QString &name, mitk::VtkPropRenderer *, mitk::RenderingManager *renderingManager, mitk::BaseRenderer::RenderingMode::Type renderingMode)
  : QVTKOpenGLWidget(parent),
    m_ResendQtEvents(true),
    m_MenuWidget(nullptr),
    m_MenuWidgetActivated(false),
    m_LayoutIndex(0)
{
  m_InternalRenderWindow = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
  m_InternalRenderWindow->SetMultiSamples(0);
  m_InternalRenderWindow->SetAlphaBitPlanes(0);

  this->SetRenderWindow(m_InternalRenderWindow);

  this->Initialize(renderingManager, name.toStdString().c_str(), renderingMode);

  this->setFocusPolicy(Qt::StrongFocus);
  this->setMouseTracking(true);
  QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  this->setSizePolicy(sizePolicy);
}

QmitkRenderWindow::~QmitkRenderWindow()
{
  Destroy(); // Destroy mitkRenderWindowBase
}

void QmitkRenderWindow::SetResendQtEvents(bool resend)
{
  m_ResendQtEvents = resend;
}

void QmitkRenderWindow::SetLayoutIndex(unsigned int layoutIndex)
{
  m_LayoutIndex = layoutIndex;
  if (m_MenuWidget)
    m_MenuWidget->SetLayoutIndex(layoutIndex);
}

unsigned int QmitkRenderWindow::GetLayoutIndex()
{
  if (m_MenuWidget)
    return m_MenuWidget->GetLayoutIndex();
  else
    return 0;
}

void QmitkRenderWindow::LayoutDesignListChanged(int layoutDesignIndex)
{
  if (m_MenuWidget)
    m_MenuWidget->UpdateLayoutDesignList(layoutDesignIndex);
}

bool QmitkRenderWindow::event(QEvent* e)
{
  mitk::InteractionEvent::Pointer mitkEvent = nullptr;
  switch (e->type())
  {
    case QEvent::MouseMove:
    {
      auto me = static_cast<QMouseEvent *>(e);
      this->AdjustRenderWindowMenuVisibility(me->pos());
      mitkEvent = mitk::MouseMoveEvent::New(m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me));
      break;
    }
    case QEvent::MouseButtonPress:
    {
      auto me = static_cast<QMouseEvent *>(e);
      mitkEvent = mitk::MousePressEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me));
      break;
    }
    case QEvent::MouseButtonRelease:
    {
      auto me = static_cast<QMouseEvent *>(e);
      mitkEvent = mitk::MouseReleaseEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me));
      break;
    }
    case QEvent::MouseButtonDblClick:
    {
      auto me = static_cast<QMouseEvent *>(e);
      mitkEvent = mitk::MouseDoubleClickEvent::New( m_Renderer, GetMousePosition(me), GetButtonState(me), GetModifiers(me), GetEventButton(me));
      break;
    }
    case QEvent::Wheel:
    {
      auto we = static_cast<QWheelEvent *>(e);
      mitkEvent = mitk::MouseWheelEvent::New( m_Renderer, GetMousePosition(we), GetButtonState(we), GetModifiers(we), GetDelta(we));
      break;
    }
    case QEvent::KeyPress:
    {
      auto ke = static_cast<QKeyEvent*>(e);
      mitkEvent = mitk::InteractionKeyEvent::New(m_Renderer, GetKeyLetter(ke), GetModifiers(ke));
      break;
    }
  }

  if (mitkEvent != nullptr)
  {
    if (this->HandleEvent(mitkEvent.GetPointer())) {
      return m_ResendQtEvents ? false : true;
    }
  }

  return QVTKOpenGLWidget::event(e);
}

void QmitkRenderWindow::enterEvent(QEvent *e)
{
  // TODO implement new event
  QVTKOpenGLWidget::enterEvent(e);
}

void QmitkRenderWindow::DeferredHideMenu()
{
  MITK_DEBUG << "QmitkRenderWindow::DeferredHideMenu";

  if (m_MenuWidget)
    m_MenuWidget->HideMenu();
}

void QmitkRenderWindow::leaveEvent(QEvent *e)
{
  mitk::InternalEvent::Pointer internalEvent = mitk::InternalEvent::New(this->m_Renderer, nullptr, "LeaveRenderWindow");

  this->HandleEvent(internalEvent.GetPointer());

  if (m_MenuWidget)
    m_MenuWidget->smoothHide();

  QVTKOpenGLWidget::leaveEvent(e);
}

//-----------------------------------------------------------------------------
void QmitkRenderWindow::resizeGL(int w, int h)
{
  this->GetRenderer()->GetRenderingManager()->ForceImmediateUpdate(GetRenderWindow());
  QVTKOpenGLWidget::resizeGL(w, h);
}

void QmitkRenderWindow::moveEvent(QMoveEvent *event)
{
  QVTKOpenGLWidget::moveEvent(event);

  // after a move the overlays need to be positioned
  emit moved();
}

void QmitkRenderWindow::showEvent(QShowEvent *event)
{
  QVTKOpenGLWidget::showEvent(event);

  // this singleshot is necessary to have the overlays positioned correctly after initial show
  // simple call of moved() is no use here!!
  QTimer::singleShot(0, this, SIGNAL(moved()));
}

void QmitkRenderWindow::ActivateMenuWidget(bool state, QmitkStdMultiWidget *stdMultiWidget)
{
  m_MenuWidgetActivated = state;

  if (!m_MenuWidgetActivated && m_MenuWidget)
  {
    // disconnect Signal/Slot Connection
    disconnect(m_MenuWidget, SIGNAL(SignalChangeLayoutDesign(int)), this, SLOT(OnChangeLayoutDesign(int)));
    disconnect(m_MenuWidget, SIGNAL(ResetView()), this, SIGNAL(ResetView()));
    disconnect(m_MenuWidget, SIGNAL(ChangeCrosshairRotationMode(int)), this, SIGNAL(ChangeCrosshairRotationMode(int)));

    delete m_MenuWidget;
    m_MenuWidget = nullptr;
  }
  else if (m_MenuWidgetActivated && !m_MenuWidget)
  {
    // create render window MenuBar for split, close Window or set new setting.
    m_MenuWidget = new QmitkRenderWindowMenu(this, nullptr, m_Renderer, stdMultiWidget);
    m_MenuWidget->SetLayoutIndex(m_LayoutIndex);

    // create Signal/Slot Connection
    connect(m_MenuWidget, SIGNAL(SignalChangeLayoutDesign(int)), this, SLOT(OnChangeLayoutDesign(int)));
    connect(m_MenuWidget, SIGNAL(ResetView()), this, SIGNAL(ResetView()));
    connect(m_MenuWidget, SIGNAL(ChangeCrosshairRotationMode(int)), this, SIGNAL(ChangeCrosshairRotationMode(int)));
  }
}

void QmitkRenderWindow::AdjustRenderWindowMenuVisibility(const QPoint & /*pos*/)
{
  if (m_MenuWidget)
  {
    m_MenuWidget->ShowMenu();
    m_MenuWidget->MoveWidgetToCorrectPos(1.0f);
  }
}

void QmitkRenderWindow::HideRenderWindowMenu()
{
  // DEPRECATED METHOD
}

void QmitkRenderWindow::OnChangeLayoutDesign(int layoutDesignIndex)
{
  emit SignalLayoutDesignChanged(layoutDesignIndex);
}

void QmitkRenderWindow::OnWidgetPlaneModeChanged(int mode)
{
  if (m_MenuWidget)
    m_MenuWidget->NotifyNewWidgetPlanesMode(mode);
}

void QmitkRenderWindow::FullScreenMode(bool state)
{
  if (m_MenuWidget)
    m_MenuWidget->ChangeFullScreenMode(state);
}

void QmitkRenderWindow::dragEnterEvent(QDragEnterEvent *event)
{
  if (event->mimeData()->hasFormat("application/x-mitk-datanodes"))
  {
    event->accept();
  }
}

void QmitkRenderWindow::dropEvent(QDropEvent *event)
{
  QList<mitk::DataNode *> dataNodeList = QmitkMimeTypes::ToDataNodePtrList(event->mimeData());
  if (!dataNodeList.empty())
  {
    emit NodesDropped(this, dataNodeList.toVector().toStdVector());
  }
}

mitk::Point2D QmitkRenderWindow::GetMousePosition(QMouseEvent *me) const
{
  mitk::Point2D point;
  point[0] = me->x();
  // We need to convert the y component, as the display and vtk have other definitions for the y direction
  point[1] = m_Renderer->GetSizeY() - me->y();
  return point;
}

mitk::Point2D QmitkRenderWindow::GetMousePosition(QWheelEvent *we) const
{
  mitk::Point2D point;
  point[0] = we->x();
  // We need to convert the y component, as the display and vtk have other definitions for the y direction
  point[1] = m_Renderer->GetSizeY() - we->y();
  return point;
}

mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetEventButton(QMouseEvent *me) const
{
  mitk::InteractionEvent::MouseButtons eventButton;
  switch (me->button())
  {
    case Qt::LeftButton:
      eventButton = mitk::InteractionEvent::LeftMouseButton;
      break;
    case Qt::RightButton:
      eventButton = mitk::InteractionEvent::RightMouseButton;
      break;
    case Qt::MidButton:
      eventButton = mitk::InteractionEvent::MiddleMouseButton;
      break;
    default:
      eventButton = mitk::InteractionEvent::NoButton;
      break;
  }
  return eventButton;
}

mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QMouseEvent *me) const
{
  mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton;

  if (me->buttons() & Qt::LeftButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton;
  }
  if (me->buttons() & Qt::RightButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::RightMouseButton;
  }
  if (me->buttons() & Qt::MidButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton;
  }
  return buttonState;
}

mitk::InteractionEvent::ModifierKeys QmitkRenderWindow::GetModifiers(QInputEvent *me) const
{
  mitk::InteractionEvent::ModifierKeys modifiers = mitk::InteractionEvent::NoKey;

  if (me->modifiers() & Qt::ALT)
  {
    modifiers = modifiers | mitk::InteractionEvent::AltKey;
  }
  if (me->modifiers() & Qt::CTRL)
  {
    modifiers = modifiers | mitk::InteractionEvent::ControlKey;
  }
  if (me->modifiers() & Qt::SHIFT)
  {
    modifiers = modifiers | mitk::InteractionEvent::ShiftKey;
  }
  return modifiers;
}

mitk::InteractionEvent::MouseButtons QmitkRenderWindow::GetButtonState(QWheelEvent *we) const
{
  mitk::InteractionEvent::MouseButtons buttonState = mitk::InteractionEvent::NoButton;

  if (we->buttons() & Qt::LeftButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::LeftMouseButton;
  }
  if (we->buttons() & Qt::RightButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::RightMouseButton;
  }
  if (we->buttons() & Qt::MidButton)
  {
    buttonState = buttonState | mitk::InteractionEvent::MiddleMouseButton;
  }
  return buttonState;
}

std::string QmitkRenderWindow::GetKeyLetter(QKeyEvent *ke) const
{
  // Converting Qt Key Event to string element.
  std::string key = "";
  int tkey = ke->key();
  if (tkey < 128)
  { // standard ascii letter
    key = (char)toupper(tkey);
  }
  else
  { // special keys
    switch (tkey)
    {
      case Qt::Key_Return:
        key = mitk::InteractionEvent::KeyReturn;
        break;
      case Qt::Key_Enter:
        key = mitk::InteractionEvent::KeyEnter;
        break;
      case Qt::Key_Escape:
        key = mitk::InteractionEvent::KeyEsc;
        break;
      case Qt::Key_Delete:
        key = mitk::InteractionEvent::KeyDelete;
        break;
      case Qt::Key_Up:
        key = mitk::InteractionEvent::KeyArrowUp;
        break;
      case Qt::Key_Down:
        key = mitk::InteractionEvent::KeyArrowDown;
        break;
      case Qt::Key_Left:
        key = mitk::InteractionEvent::KeyArrowLeft;
        break;
      case Qt::Key_Right:
        key = mitk::InteractionEvent::KeyArrowRight;
        break;

      case Qt::Key_F1:
        key = mitk::InteractionEvent::KeyF1;
        break;
      case Qt::Key_F2:
        key = mitk::InteractionEvent::KeyF2;
        break;
      case Qt::Key_F3:
        key = mitk::InteractionEvent::KeyF3;
        break;
      case Qt::Key_F4:
        key = mitk::InteractionEvent::KeyF4;
        break;
      case Qt::Key_F5:
        key = mitk::InteractionEvent::KeyF5;
        break;
      case Qt::Key_F6:
        key = mitk::InteractionEvent::KeyF6;
        break;
      case Qt::Key_F7:
        key = mitk::InteractionEvent::KeyF7;
        break;
      case Qt::Key_F8:
        key = mitk::InteractionEvent::KeyF8;
        break;
      case Qt::Key_F9:
        key = mitk::InteractionEvent::KeyF9;
        break;
      case Qt::Key_F10:
        key = mitk::InteractionEvent::KeyF10;
        break;
      case Qt::Key_F11:
        key = mitk::InteractionEvent::KeyF11;
        break;
      case Qt::Key_F12:
        key = mitk::InteractionEvent::KeyF12;
        break;

      case Qt::Key_End:
        key = mitk::InteractionEvent::KeyEnd;
        break;
      case Qt::Key_Home:
        key = mitk::InteractionEvent::KeyPos1;
        break;
      case Qt::Key_Insert:
        key = mitk::InteractionEvent::KeyInsert;
        break;
      case Qt::Key_PageDown:
        key = mitk::InteractionEvent::KeyPageDown;
        break;
      case Qt::Key_PageUp:
        key = mitk::InteractionEvent::KeyPageUp;
        break;
      case Qt::Key_Space:
        key = mitk::InteractionEvent::KeySpace;
        break;
    }
  }
  return key;
}

int QmitkRenderWindow::GetDelta(QWheelEvent *we) const
{
  return we->delta();
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>

#include "zlib.h"

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/udp_tracker_connection.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"

using namespace libtorrent;

namespace
{
	enum
	{
		minimum_tracker_response_length = 3,
		http_buffer_size = 2048
	};

	enum
	{
		FTEXT = 0x01,
		FHCRC = 0x02,
		FEXTRA = 0x04,
		FNAME = 0x08,
		FCOMMENT = 0x10,
		FRESERVED = 0xe0,

		GZIP_MAGIC0 = 0x1f,
		GZIP_MAGIC1 = 0x8b
	};

}

namespace libtorrent
{

	// returns -1 if gzip header is invalid or the header size in bytes
	int gzip_header(const char* buf, int size)
	{
		assert(buf != 0);
		assert(size > 0);

		const unsigned char* buffer = reinterpret_cast<const unsigned char*>(buf);
		const int total_size = size;

		// The zip header cannot be shorter than 10 bytes
		if (size < 10) return -1;

		// check the magic header of gzip
		if ((buffer[0] != GZIP_MAGIC0) || (buffer[1] != GZIP_MAGIC1)) return -1;

		int method = buffer[2];
		int flags = buffer[3];

		// check for reserved flag and make sure it's compressed with the correct metod
		if (method != Z_DEFLATED || (flags & FRESERVED) != 0) return -1;

		// skip time, xflags, OS code
		size -= 10;
		buffer += 10;

		if (flags & FEXTRA)
		{
			int extra_len;

			if (size < 2) return -1;

			extra_len = (buffer[1] << 8) | buffer[0];

			if (size < (extra_len+2)) return -1;
			size -= (extra_len + 2);
			buffer += (extra_len + 2);
		}

		if (flags & FNAME)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FCOMMENT)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FHCRC)
		{
			if (size < 2) return -1;

			size -= 2;
			buffer += 2;
		}

		return total_size - size;
	}

	bool inflate_gzip(
		std::vector<char>& buffer
		, request_callback* requester
		, int maximum_tracker_response_length)
	{
		assert(maximum_tracker_response_length > 0);

		int header_len = gzip_header(&buffer[0], (int)buffer.size());
		if (header_len < 0)
		{
			requester->tracker_request_error(200, "invalid gzip header in tracker response");
			return true;
		}

		// start off wth one kilobyte and grow
		// if needed
		std::vector<char> inflate_buffer(1024);

		// initialize the zlib-stream
		z_stream str;

		// subtract 8 from the end of the buffer since that's CRC32 and input size
		// and those belong to the gzip file
		str.avail_in = (int)buffer.size() - header_len - 8;
		str.next_in = reinterpret_cast<Bytef*>(&buffer[header_len]);
		str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[0]);
		str.avail_out = (int)inflate_buffer.size();
		str.zalloc = Z_NULL;
		str.zfree = Z_NULL;
		str.opaque = 0;
		// -15 is really important. It will make inflate() not look for a zlib header
		// and just deflate the buffer
		if (inflateInit2(&str, -15) != Z_OK)
		{
			requester->tracker_request_error(200, "gzip out of memory");
			return true;
		}

		// inflate and grow inflate_buffer as needed
		int ret = inflate(&str, Z_SYNC_FLUSH);
		while (ret == Z_OK)
		{
			if (str.avail_out == 0)
			{
				if (inflate_buffer.size() >= (unsigned)maximum_tracker_response_length)
				{
					inflateEnd(&str);
					requester->tracker_request_error(200, "tracker response too large");
					return true;
				}
				int new_size = (int)inflate_buffer.size() * 2;
				if (new_size > maximum_tracker_response_length) new_size = maximum_tracker_response_length;
				int old_size = (int)inflate_buffer.size();

				inflate_buffer.resize(new_size);
				str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[old_size]);
				str.avail_out = new_size - old_size;
			}

			ret = inflate(&str, Z_SYNC_FLUSH);
		}

		inflate_buffer.resize(inflate_buffer.size() - str.avail_out);
		inflateEnd(&str);

		if (ret != Z_STREAM_END)
		{
			requester->tracker_request_error(200, "gzip error");
			return true;
		}

		// commit the resulting buffer
		std::swap(buffer, inflate_buffer);
		return false;
	}

	std::string base64encode(const std::string& s)
	{
		static const char base64_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
			'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
			'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
			'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/'
		};

		unsigned char inbuf[3];
		unsigned char outbuf[4];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			// available input is 1,2 or 3 bytes
			// since we read 3 bytes at a time at most
			int available_input = std::min(3, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+3, 0);

			// read a chunk of input into inbuf
			for (int j = 0; j < available_input; ++j)
			{
				inbuf[j] = *i;
				++i;
			}

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xfc) >> 2;
			outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
			outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
			outbuf[3] = inbuf[2] & 0x3f;

			// write output
			for (int j = 0; j < available_input+1; ++j)
			{
				ret += base64_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 3 - available_input; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	void tracker_manager::tick()
	{
		std::vector<boost::shared_ptr<tracker_connection> >::iterator i;
		for (i = m_connections.begin(); i != m_connections.end(); ++i)
		{
			boost::shared_ptr<tracker_connection>& c = *i;
			try
			{
				if (!c->tick()) continue;
			}
			catch (const std::exception& e)
			{
				if (c->requester())
					c->requester()->tracker_request_error(-1, e.what());
			}
			if (c->requester()) c->requester()->m_manager = 0;
			m_connections.erase(i);
			--i; // compensate for the remove
		}
	}

	void tracker_manager::queue_request(
		tracker_request req
		, request_callback* c
		, std::string const& password)
	{
		assert(req.num_want >= 0);
		if (req.event == tracker_request::stopped)
			req.num_want = 0;

		try
		{
			std::string hostname; // hostname only
			std::string protocol; // should be http
			int port = 80;

			// PARSE URL
			std::string::iterator start = req.url.begin();
			std::string::iterator end
				= std::find(req.url.begin(), req.url.end(), ':');
			protocol = std::string(start, end);

			if (end == req.url.end()) throw std::runtime_error("invalid url");
			++end;
			if (end == req.url.end()) throw std::runtime_error("invalid url");
			if (*end != '/') throw std::runtime_error("invalid url");
			++end;
			if (end == req.url.end()) throw std::runtime_error("invalid url");
			if (*end != '/') throw std::runtime_error("invalid url");
			++end;
			start = end;

			end = std::find(start, req.url.end(), '/');
			std::string::const_iterator port_pos
				= std::find(start, req.url.end(), ':');

			if (port_pos < end)
			{
				hostname.assign(start, port_pos);
				++port_pos;
				try
				{
					port = boost::lexical_cast<int>(std::string(port_pos, end));
				}
				catch(boost::bad_lexical_cast&)
				{
					throw std::runtime_error("invalid url");
				}
			}
			else
			{
				hostname.assign(start, end);
			}

			start = end;
			std::string request_string = std::string(start, req.url.end());

			boost::shared_ptr<tracker_connection> con;

			if (protocol == "http")
			{
				con.reset(new http_tracker_connection(
					req
					, hostname
					, port
					, request_string
					, c
					, m_settings
					, password));
			}
			else if (protocol == "udp")
			{
				con.reset(new udp_tracker_connection(
					req
					, hostname
					, port
					, c
					, m_settings));
			}
			else
			{
				throw std::runtime_error("unkown protocol in tracker url");
			}

			m_connections.push_back(con);

			if (con->requester()) con->requester()->m_manager = this;
		}
		catch (std::exception& e)
		{
			if (c) c->tracker_request_error(-1, e.what());
		}
	}

	void tracker_manager::abort_request(request_callback* c)
	{
		assert(c != 0);
		std::vector<boost::shared_ptr<tracker_connection> >::iterator i;
		for (i = m_connections.begin(); i != m_connections.end(); ++i)
		{
			if ((*i)->requester() == c)
			{
				m_connections.erase(i);
				break;
			}
		}
	}

	void tracker_manager::abort_all_requests()
	{
		// removes all connections from m_connections
		// except those with a requester == 0 (since those are
		// 'event=stopped'-requests)

		std::vector<boost::shared_ptr<tracker_connection> > keep_connections;

		for (std::vector<boost::shared_ptr<tracker_connection> >::const_iterator i =
				m_connections.begin();
			i != m_connections.end();
			++i)
		{
			if ((*i)->requester() == 0) keep_connections.push_back(*i);
		}

		std::swap(m_connections, keep_connections);
	}

	bool tracker_manager::send_finished() const
	{
		for (std::vector<boost::shared_ptr<tracker_connection> >::const_iterator i =
				m_connections.begin();
			i != m_connections.end();
			++i)
		{
			if (!(*i)->send_finished()) return false;
		}
		return true;
	}

}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <vector>
#include <iostream>
#include <cctype>
#include <iomanip>
#include <sstream>

#include "zlib.h"

#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/udp_tracker_connection.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp"

using namespace libtorrent;

namespace
{
	enum
	{
		minimum_tracker_response_length = 3,
		http_buffer_size = 2048
	};

	enum
	{
		FTEXT = 0x01,
		FHCRC = 0x02,
		FEXTRA = 0x04,
		FNAME = 0x08,
		FCOMMENT = 0x10,
		FRESERVED = 0xe0,

		GZIP_MAGIC0 = 0x1f,
		GZIP_MAGIC1 = 0x8b
	};

}

namespace libtorrent
{

	// returns -1 if gzip header is invalid or the header size in bytes
	int gzip_header(const char* buf, int size)
	{
		assert(buf != 0);
		assert(size > 0);

		const unsigned char* buffer = reinterpret_cast<const unsigned char*>(buf);
		const int total_size = size;

		// The zip header cannot be shorter than 10 bytes
		if (size < 10) return -1;

		// check the magic header of gzip
		if ((buffer[0] != GZIP_MAGIC0) || (buffer[1] != GZIP_MAGIC1)) return -1;

		int method = buffer[2];
		int flags = buffer[3];

		// check for reserved flag and make sure it's compressed with the correct metod
		if (method != Z_DEFLATED || (flags & FRESERVED) != 0) return -1;

		// skip time, xflags, OS code
		size -= 10;
		buffer += 10;

		if (flags & FEXTRA)
		{
			int extra_len;

			if (size < 2) return -1;

			extra_len = (buffer[1] << 8) | buffer[0];

			if (size < (extra_len+2)) return -1;
			size -= (extra_len + 2);
			buffer += (extra_len + 2);
		}

		if (flags & FNAME)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FCOMMENT)
		{
			while (size && *buffer)
			{
				--size;
				++buffer;
			}
			if (!size || *buffer) return -1;

			--size;
			++buffer;
		}

		if (flags & FHCRC)
		{
			if (size < 2) return -1;

			size -= 2;
			buffer += 2;
		}

		return total_size - size;
	}

	bool inflate_gzip(
		std::vector<char>& buffer
		, request_callback* requester
		, int maximum_tracker_response_length)
	{
		assert(maximum_tracker_response_length > 0);

		int header_len = gzip_header(&buffer[0], (int)buffer.size());
		if (header_len < 0)
		{
			requester->tracker_request_error(200, "invalid gzip header in tracker response");
			return true;
		}

		// start off wth one kilobyte and grow
		// if needed
		std::vector<char> inflate_buffer(1024);

		// initialize the zlib-stream
		z_stream str;

		// subtract 8 from the end of the buffer since that's CRC32 and input size
		// and those belong to the gzip file
		str.avail_in = (int)buffer.size() - header_len - 8;
		str.next_in = reinterpret_cast<Bytef*>(&buffer[header_len]);
		str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[0]);
		str.avail_out = (int)inflate_buffer.size();
		str.zalloc = Z_NULL;
		str.zfree = Z_NULL;
		str.opaque = 0;
		// -15 is really important. It will make inflate() not look for a zlib header
		// and just deflate the buffer
		if (inflateInit2(&str, -15) != Z_OK)
		{
			requester->tracker_request_error(200, "gzip out of memory");
			return true;
		}

		// inflate and grow inflate_buffer as needed
		int ret = inflate(&str, Z_SYNC_FLUSH);
		while (ret == Z_OK)
		{
			if (str.avail_out == 0)
			{
				if (inflate_buffer.size() >= (unsigned)maximum_tracker_response_length)
				{
					inflateEnd(&str);
					requester->tracker_request_error(200, "tracker response too large");
					return true;
				}
				int new_size = (int)inflate_buffer.size() * 2;
				if (new_size > maximum_tracker_response_length) new_size = maximum_tracker_response_length;
				int old_size = (int)inflate_buffer.size();

				inflate_buffer.resize(new_size);
				str.next_out = reinterpret_cast<Bytef*>(&inflate_buffer[old_size]);
				str.avail_out = new_size - old_size;
			}

			ret = inflate(&str, Z_SYNC_FLUSH);
		}

		inflate_buffer.resize(inflate_buffer.size() - str.avail_out);
		inflateEnd(&str);

		if (ret != Z_STREAM_END)
		{
			requester->tracker_request_error(200, "gzip error");
			return true;
		}

		// commit the resulting buffer
		std::swap(buffer, inflate_buffer);
		return false;
	}

	std::string base64encode(const std::string& s)
	{
		static const char base64_table[] =
		{
			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
			'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
			'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
			'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
			'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
			'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
			'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/'
		};

		unsigned char inbuf[3];
		unsigned char outbuf[4];

		std::string ret;
		for (std::string::const_iterator i = s.begin(); i != s.end();)
		{
			// available input is 1,2 or 3 bytes
			// since we read 3 bytes at a time at most
			int available_input = std::min(3, (int)std::distance(i, s.end()));

			// clear input buffer
			std::fill(inbuf, inbuf+3, 0);

			// read a chunk of input into inbuf
			for (int j = 0; j < available_input; ++j)
			{
				inbuf[j] = *i;
				++i;
			}

			// encode inbuf to outbuf
			outbuf[0] = (inbuf[0] & 0xfc) >> 2;
			outbuf[1] = ((inbuf[0] & 0x03) << 4) | ((inbuf [1] & 0xf0) >> 4);
			outbuf[2] = ((inbuf[1] & 0x0f) << 2) | ((inbuf [2] & 0xc0) >> 6);
			outbuf[3] = inbuf[2] & 0x3f;

			// write output
			for (int j = 0; j < available_input+1; ++j)
			{
				ret += base64_table[outbuf[j]];
			}

			// write pad
			for (int j = 0; j < 3 - available_input; ++j)
			{
				ret += '=';
			}
		}
		return ret;
	}

	void tracker_manager::tick()
	{
		std::vector<boost::shared_ptr<tracker_connection> >::iterator i;
		for (i = m_connections.begin(); i != m_connections.end(); ++i)
		{
			boost::shared_ptr<tracker_connection>& c = *i;
			try
			{
				if (!c->tick()) continue;
			}
			catch (const std::exception& e)
			{
				if (c->requester())
					c->requester()->tracker_request_error(-1, e.what());
			}
			if (c->requester()) c->requester()->m_manager = 0;
			m_connections.erase(i);
			--i; // compensate for the remove
		}
	}

	void tracker_manager::queue_request(
		tracker_request req
		, request_callback* c
		, std::string const& password)
	{
		assert(req.num_want >= 0);
		if (req.event == tracker_request::stopped)
			req.num_want = 0;

		try
		{
			std::string hostname; // hostname only
			std::string protocol; // should be http
			int port = 80;

			// PARSE URL
			std::string::iterator start = req.url.begin();
			std::string::iterator end
				= std::find(req.url.begin(), req.url.end(), ':');
			protocol = std::string(start, end);

			if (end == req.url.end()) throw std::runtime_error("invalid url");
			++end;
			if (end == req.url.end()) throw std::runtime_error("invalid url");
			if (*end != '/') throw std::runtime_error("invalid url");
			++end;
			if (end == req.url.end()) throw std::runtime_error("invalid url");
			if (*end != '/') throw std::runtime_error("invalid url");
			++end;
			start = end;

			end = std::find(start, req.url.end(), '/');
			std::string::iterator port_pos
				= std::find(start, req.url.end(), ':');

			if (port_pos < end)
			{
				hostname.assign(start, port_pos);
				++port_pos;
				try
				{
					port = boost::lexical_cast<int>(std::string(port_pos, end));
				}
				catch(boost::bad_lexical_cast&)
				{
					throw std::runtime_error("invalid url");
				}
			}
			else
			{
				hostname.assign(start, end);
			}

			start = end;
			std::string request_string = std::string(start, req.url.end());

			boost::shared_ptr<tracker_connection> con;

			if (protocol == "http")
			{
				con.reset(new http_tracker_connection(
					req
					, hostname
					, port
					, request_string
					, c
					, m_settings
					, password));
			}
			else if (protocol == "udp")
			{
				con.reset(new udp_tracker_connection(
					req
					, hostname
					, port
					, c
					, m_settings));
			}
			else
			{
				throw std::runtime_error("unkown protocol in tracker url");
			}

			m_connections.push_back(con);

			if (con->requester()) con->requester()->m_manager = this;
		}
		catch (std::exception& e)
		{
			if (c) c->tracker_request_error(-1, e.what());
		}
	}

	void tracker_manager::abort_request(request_callback* c)
	{
		assert(c != 0);
		std::vector<boost::shared_ptr<tracker_connection> >::iterator i;
		for (i = m_connections.begin(); i != m_connections.end(); ++i)
		{
			if ((*i)->requester() == c)
			{
				m_connections.erase(i);
				break;
			}
		}
	}

	void tracker_manager::abort_all_requests()
	{
		// removes all connections from m_connections
		// except those with a requester == 0 (since those are
		// 'event=stopped'-requests)

		std::vector<boost::shared_ptr<tracker_connection> > keep_connections;

		for (std::vector<boost::shared_ptr<tracker_connection> >::const_iterator i =
				m_connections.begin();
			i != m_connections.end();
			++i)
		{
			if ((*i)->requester() == 0) keep_connections.push_back(*i);
		}

		std::swap(m_connections, keep_connections);
	}

	bool tracker_manager::send_finished() const
	{
		for (std::vector<boost::shared_ptr<tracker_connection> >::const_iterator i =
				m_connections.begin();
			i != m_connections.end();
			++i)
		{
			if (!(*i)->send_finished()) return false;
		}
		return true;
	}

}
<|endoftext|>


<commit_before>#include "png.h"

#include <cstdint>
#include <cstring>
#include <iostream>

#include "miniz/miniz.h"
#include "zopflipng/zopflipng_lib.h"

#include "../leanify.h"

#ifdef _MSC_VER
#   define bswap32(x) _byteswap_ulong(x)
#elif defined __GNUC__
#   define bswap32(x) __builtin_bswap32(x)
#else
#   define bswap32(x) _bswap(x)
#endif

const unsigned char Png::header_magic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };

size_t Png::Leanify(size_t size_leanified /*= 0*/)
{

    char *p_read, *p_write, *idat_addr;

    // header
    p_read = fp;
    p_write = p_read - size_leanified;

    if (size_leanified)
    {
        memmove(p_write, p_read, sizeof(header_magic));
    }

    p_read += sizeof(header_magic);
    p_write += sizeof(header_magic);

    // chunk
    uint32_t chunk_type;

    do
    {

        // read chunk length
        // use bswap to convert Big-Endian to Little-Endian
        // 12 = length: 4 + type: 4 + crc: 4
        uint32_t chunk_lenth = bswap32(*(uint32_t *)p_read) + 12;

        // detect truncated file
        if (p_read + chunk_lenth > fp + size)
        {
            memmove(p_write, p_read, fp + size - p_read);
            p_write += fp + size - p_read;
            p_read = fp + size;
            break;
        }

        // read chunk type
        chunk_type = *(uint32_t *)(p_read + 4);

        // judge the case of first letter
        // remove all ancillary chunks except tRNS and APNG chunks and npTc
        // tRNS has transparency information
        if (chunk_type & 0x20)
        {

            switch (chunk_type)
            {
            case 0x534E5274:    // tRNS     transparent
            case 0x4C546361:    // acTL     APNG
            case 0x4C546366:    // fcTL     APNG
            case 0x54416466:    // fdAT     APNG    TODO: use zopfli to recompress fdAT
            case 0x6354706E:    // npTc     Android 9Patch images (*.9.png)
                break;

            default:
                if (is_verbose)
                {
                    // chunk name
                    for (int i = 4; i < 8; i++)
                    {
                        std::cout << p_read[i];
                    }
                    std::cout << " chunk removed." << std::endl;
                }
                // remove this chunk
                p_read += chunk_lenth;
                continue;
            }

        }

        // move this chunk
        if (p_write != p_read)
        {
            memmove(p_write, p_read, chunk_lenth);
        }

        // save IDAT chunk address
        if (chunk_type == 0x54414449)
        {
            idat_addr = p_write;
        }

        // skip whole chunk
        p_write += chunk_lenth;
        p_read += chunk_lenth;

    } while (chunk_type != 0x444E4549);     // IEND

    fp -= size_leanified;
    uint32_t png_size = p_write - fp;

    ZopfliPNGOptions zopflipng_options;
    zopflipng_options.use_zopfli = !is_fast;
    zopflipng_options.lossy_transparent = true;
    // see the switch above for information about these chunks
    zopflipng_options.keepchunks = { "acTL", "fcTL", "fdAT", "npTc" };
    zopflipng_options.num_iterations = iterations;
    zopflipng_options.num_iterations_large = iterations / 3 + 1;
    // trying both methods does not worth the time it spend
    // it's better to use the time for more iterations.
    // zopflipng_options.block_split_strategy = 3;

    const std::vector<unsigned char> origpng(fp, fp + png_size);
    std::vector<unsigned char> resultpng;

    if (!ZopfliPNGOptimize(origpng, zopflipng_options, is_verbose, &resultpng))
    {
        // only use the result PNG if it is smaller
        // sometimes the original PNG is already highly optimized
        // then maybe ZopfliPNG will produce bigger file
        if (resultpng.size() < png_size)
        {
            memcpy(fp, resultpng.data(), resultpng.size());
            return resultpng.size();
        }
    }

    // sometimes the strategy chosen by ZopfliPNG is worse than original
    // then try to recompress IDAT chunk using only zopfli
    uint32_t idat_length = bswap32(*(uint32_t *)idat_addr);
    uint32_t new_idat_length = ZlibRecompress(idat_addr + 8, idat_length);
    if (idat_length != new_idat_length)
    {
        *(uint32_t *)idat_addr = bswap32(new_idat_length);
        *(uint32_t *)(idat_addr + new_idat_length + 8) = bswap32(mz_crc32(0, (unsigned char *)idat_addr + 4, new_idat_length + 4));
        char *idat_end = idat_addr + idat_length + 12;
        memmove(idat_addr + new_idat_length + 12, idat_end, fp + png_size - idat_end);
        png_size -= idat_length - new_idat_length;
    }

    return png_size;
}
<commit_msg>Typo in variable name<commit_after>#include "png.h"

#include <cstdint>
#include <cstring>
#include <iostream>

#include "miniz/miniz.h"
#include "zopflipng/zopflipng_lib.h"

#include "../leanify.h"

#ifdef _MSC_VER
#   define bswap32(x) _byteswap_ulong(x)
#elif defined __GNUC__
#   define bswap32(x) __builtin_bswap32(x)
#else
#   define bswap32(x) _bswap(x)
#endif

const unsigned char Png::header_magic[] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };

size_t Png::Leanify(size_t size_leanified /*= 0*/)
{

    char *p_read, *p_write, *idat_addr;

    // header
    p_read = fp;
    p_write = p_read - size_leanified;

    if (size_leanified)
    {
        memmove(p_write, p_read, sizeof(header_magic));
    }

    p_read += sizeof(header_magic);
    p_write += sizeof(header_magic);

    // chunk
    uint32_t chunk_type;

    do
    {

        // read chunk length
        // use bswap to convert Big-Endian to Little-Endian
        // 12 = length: 4 + type: 4 + crc: 4
        uint32_t chunk_length = bswap32(*(uint32_t *)p_read) + 12;

        // detect truncated file
        if (p_read + chunk_length > fp + size)
        {
            memmove(p_write, p_read, fp + size - p_read);
            p_write += fp + size - p_read;
            p_read = fp + size;
            break;
        }

        // read chunk type
        chunk_type = *(uint32_t *)(p_read + 4);

        // judge the case of first letter
        // remove all ancillary chunks except tRNS and APNG chunks and npTc
        // tRNS has transparency information
        if (chunk_type & 0x20)
        {

            switch (chunk_type)
            {
            case 0x534E5274:    // tRNS     transparent
            case 0x4C546361:    // acTL     APNG
            case 0x4C546366:    // fcTL     APNG
            case 0x54416466:    // fdAT     APNG    TODO: use zopfli to recompress fdAT
            case 0x6354706E:    // npTc     Android 9Patch images (*.9.png)
                break;

            default:
                if (is_verbose)
                {
                    // chunk name
                    for (int i = 4; i < 8; i++)
                    {
                        std::cout << p_read[i];
                    }
                    std::cout << " chunk removed." << std::endl;
                }
                // remove this chunk
                p_read += chunk_length;
                continue;
            }

        }

        // move this chunk
        if (p_write != p_read)
        {
            memmove(p_write, p_read, chunk_length);
        }

        // save IDAT chunk address
        if (chunk_type == 0x54414449)
        {
            idat_addr = p_write;
        }

        // skip whole chunk
        p_write += chunk_length;
        p_read += chunk_length;

    } while (chunk_type != 0x444E4549);     // IEND

    fp -= size_leanified;
    uint32_t png_size = p_write - fp;

    ZopfliPNGOptions zopflipng_options;
    zopflipng_options.use_zopfli = !is_fast;
    zopflipng_options.lossy_transparent = true;
    // see the switch above for information about these chunks
    zopflipng_options.keepchunks = { "acTL", "fcTL", "fdAT", "npTc" };
    zopflipng_options.num_iterations = iterations;
    zopflipng_options.num_iterations_large = iterations / 3 + 1;
    // trying both methods does not worth the time it spend
    // it's better to use the time for more iterations.
    // zopflipng_options.block_split_strategy = 3;

    const std::vector<unsigned char> origpng(fp, fp + png_size);
    std::vector<unsigned char> resultpng;

    if (!ZopfliPNGOptimize(origpng, zopflipng_options, is_verbose, &resultpng))
    {
        // only use the result PNG if it is smaller
        // sometimes the original PNG is already highly optimized
        // then maybe ZopfliPNG will produce bigger file
        if (resultpng.size() < png_size)
        {
            memcpy(fp, resultpng.data(), resultpng.size());
            return resultpng.size();
        }
    }

    // sometimes the strategy chosen by ZopfliPNG is worse than original
    // then try to recompress IDAT chunk using only zopfli
    uint32_t idat_length = bswap32(*(uint32_t *)idat_addr);
    uint32_t new_idat_length = ZlibRecompress(idat_addr + 8, idat_length);
    if (idat_length != new_idat_length)
    {
        *(uint32_t *)idat_addr = bswap32(new_idat_length);
        *(uint32_t *)(idat_addr + new_idat_length + 8) = bswap32(mz_crc32(0, (unsigned char *)idat_addr + 4, new_idat_length + 4));
        char *idat_end = idat_addr + idat_length + 12;
        memmove(idat_addr + new_idat_length + 12, idat_end, fp + png_size - idat_end);
        png_size -= idat_length - new_idat_length;
    }

    return png_size;
}
<|endoftext|>


<commit_before>#include "xml.h"

#include <cstring>
#include <iostream>

#include "../leanify.h"
#include "../utils.h"

Xml::Xml(void *p, size_t s /*= 0*/) : Format(p, s), doc(true)
{
    unsigned char *q = (unsigned char *)p;

    const unsigned char utf8_bom[] = { 0xEF, 0xBB, 0xBF };

    // tinyxml2 does not support utf16
    /*
    const unsigned char utf16be_bom[] = { 0xFE, 0xFF };
    const unsigned char utf16le_bom[] = { 0xFF, 0xFE };
    */
    // skip utf8 bom
    if (!memcmp(q, utf8_bom, sizeof(utf8_bom)))
    {
        q += sizeof(utf8_bom);
    }
    /*      else if (!memcmp(q, utf16le_bom, sizeof(utf16le_bom)) || !memcmp(q, utf16be_bom, sizeof(utf16be_bom)))
    {
    q += sizeof(utf16le_bom);
    }
    */
    // skip spaces
    while (isspace(*q) && q < (unsigned char *)p + s)
    {
        q++;
    }
    // only parse the file if it starts with '<'
    if (*q == '<')
    {
        is_valid = (doc.Parse(fp, size) == 0);
    }
    else
    {
        is_valid = false;
    }
}

size_t Xml::Leanify(size_t size_leanified /*= 0*/)
{
    const char *root_name = doc.RootElement()->Name();
    // if the XML is fb2 file
    if (strcmp(root_name, "FictionBook") == 0)
    {
        if (is_verbose)
        {
            std::cout << "FB2 detected." << std::endl;
        }
        if (depth < max_depth)
        {
            depth++;

            // iterate through all binary element
            for (auto e = doc.RootElement()->FirstChildElement("binary"); e; e = e->NextSiblingElement("binary"))
            {
                for (int i = 1; i < depth; i++)
                {
                    std::cout << "-> ";
                }
                std::cout << e->Attribute("id") << std::endl;

                const char *base64_data = e->GetText();
                if (base64_data == nullptr)
                {
                    std::cout << "No data found." << std::endl;
                    continue;
                }
                size_t base64_len = strlen(base64_data);

                // 4 base64 character contains information of 3 bytes
                size_t binary_len = 3 * base64_len / 4;
                unsigned char *binary_data = new unsigned char[binary_len];

                if (Base64Decode(base64_data, base64_len, binary_data, &binary_len))
                {
                    std::cout << "Base64 decode error." << std::endl;
                    delete[] binary_data;
                    continue;
                }

                // Leanify embedded image
                binary_len = LeanifyFile(binary_data, binary_len);

                // allocate a few more bytes for padding
                size_t new_base64_len = 4 * binary_len / 3 + 4;
                char *new_base64_data = new char[new_base64_len];

                if (Base64Encode(binary_data, binary_len, new_base64_data, new_base64_len))
                {
                    std::cout << "Base64 encode error." << std::endl;
                }
                else if (strlen(new_base64_data) < base64_len)
                {
                    e->SetText(new_base64_data);
                }

                delete[] binary_data;
                delete[] new_base64_data;
            }
            depth--;
        }
    }
    else if (strcmp(root_name, "svg") == 0)
    {
        if (is_verbose)
        {
            std::cout << "SVG detected." << std::endl;
        }
        for (auto e = doc.RootElement()->FirstChildElement("metadata"); e; e = e->NextSiblingElement("metadata"))
        {
            doc.RootElement()->DeleteChild(e);
        }

        // remove empty attribute
        TraverseElements(doc.RootElement(), [](tinyxml2::XMLElement* e)
        {
            for (auto attr = e->FirstAttribute(); attr; attr = attr->Next())
            {
                auto value = attr->Value();
                if (value == nullptr || *value == 0)
                {
                    e->DeleteAttribute(attr->Name());
                }
            }
        });
    }

    // print leanified XML to memory
    tinyxml2::XMLPrinter printer(0, true);
    doc.Print(&printer);

    size_t new_size = printer.CStrSize() - 1;     // -1 for the \0
    fp -= size_leanified;
    if (new_size < size)
    {
        memcpy(fp, printer.CStr(), new_size);
        return new_size;
    }
    else if (size_leanified)
    {
        memmove(fp, fp + size_leanified, size);
    }
    return size;
}

void Xml::TraverseElements(tinyxml2::XMLElement *e, std::function<void(tinyxml2::XMLElement*)> callback)
{
    callback(e);

    for (e = e->FirstChildElement(); e; e = e->NextSiblingElement())
    {
        TraverseElements(e, callback);
    }
}

<commit_msg>SVG: remove empty text element and container element<commit_after>#include "xml.h"

#include <cstring>
#include <iostream>

#include "../leanify.h"
#include "../utils.h"

Xml::Xml(void *p, size_t s /*= 0*/) : Format(p, s), doc(true)
{
    unsigned char *q = (unsigned char *)p;

    const unsigned char utf8_bom[] = { 0xEF, 0xBB, 0xBF };

    // tinyxml2 does not support utf16
    /*
    const unsigned char utf16be_bom[] = { 0xFE, 0xFF };
    const unsigned char utf16le_bom[] = { 0xFF, 0xFE };
    */
    // skip utf8 bom
    if (!memcmp(q, utf8_bom, sizeof(utf8_bom)))
    {
        q += sizeof(utf8_bom);
    }
    /*      else if (!memcmp(q, utf16le_bom, sizeof(utf16le_bom)) || !memcmp(q, utf16be_bom, sizeof(utf16be_bom)))
    {
    q += sizeof(utf16le_bom);
    }
    */
    // skip spaces
    while (isspace(*q) && q < (unsigned char *)p + s)
    {
        q++;
    }
    // only parse the file if it starts with '<'
    if (*q == '<')
    {
        is_valid = (doc.Parse(fp, size) == 0);
    }
    else
    {
        is_valid = false;
    }
}

size_t Xml::Leanify(size_t size_leanified /*= 0*/)
{
    const char *root_name = doc.RootElement()->Name();
    // if the XML is fb2 file
    if (strcmp(root_name, "FictionBook") == 0)
    {
        if (is_verbose)
        {
            std::cout << "FB2 detected." << std::endl;
        }
        if (depth < max_depth)
        {
            depth++;

            // iterate through all binary element
            for (auto e = doc.RootElement()->FirstChildElement("binary"); e; e = e->NextSiblingElement("binary"))
            {
                for (int i = 1; i < depth; i++)
                {
                    std::cout << "-> ";
                }
                std::cout << e->Attribute("id") << std::endl;

                const char *base64_data = e->GetText();
                if (base64_data == nullptr)
                {
                    std::cout << "No data found." << std::endl;
                    continue;
                }
                size_t base64_len = strlen(base64_data);

                // 4 base64 character contains information of 3 bytes
                size_t binary_len = 3 * base64_len / 4;
                unsigned char *binary_data = new unsigned char[binary_len];

                if (Base64Decode(base64_data, base64_len, binary_data, &binary_len))
                {
                    std::cout << "Base64 decode error." << std::endl;
                    delete[] binary_data;
                    continue;
                }

                // Leanify embedded image
                binary_len = LeanifyFile(binary_data, binary_len);

                // allocate a few more bytes for padding
                size_t new_base64_len = 4 * binary_len / 3 + 4;
                char *new_base64_data = new char[new_base64_len];

                if (Base64Encode(binary_data, binary_len, new_base64_data, new_base64_len))
                {
                    std::cout << "Base64 encode error." << std::endl;
                }
                else if (strlen(new_base64_data) < base64_len)
                {
                    e->SetText(new_base64_data);
                }

                delete[] binary_data;
                delete[] new_base64_data;
            }
            depth--;
        }
    }
    else if (strcmp(root_name, "svg") == 0)
    {
        if (is_verbose)
        {
            std::cout << "SVG detected." << std::endl;
        }
        for (auto e = doc.RootElement()->FirstChildElement("metadata"); e; e = e->NextSiblingElement("metadata"))
        {
            doc.RootElement()->DeleteChild(e);
        }

        TraverseElements(doc.RootElement(), [](tinyxml2::XMLElement* e)
        {
            // remove empty attribute
            for (auto attr = e->FirstAttribute(); attr; attr = attr->Next())
            {
                auto value = attr->Value();
                if (value == nullptr || *value == 0)
                {
                    e->DeleteAttribute(attr->Name());
                }
            }

            // remove empty text element and container element
            auto name = e->Name();
            if (e->NoChildren())
            {
                if (strcmp(name, "text") == 0 ||
                    strcmp(name, "tspan") == 0 ||
                    strcmp(name, "a") == 0 ||
                    strcmp(name, "defs") == 0 ||
                    strcmp(name, "g") == 0 ||
                    strcmp(name, "marker") == 0 ||
                    strcmp(name, "mask") == 0 ||
                    strcmp(name, "missing-glyph") == 0 ||
                    strcmp(name, "pattern") == 0 ||
                    strcmp(name, "switch") == 0 ||
                    strcmp(name, "symbol") == 0)
                {
                    e->Parent()->DeleteChild(e);
                }
            }

            if (strcmp(name, "tref") == 0 && e->Attribute("xlink:href") == nullptr)
            {
                e->Parent()->DeleteChild(e);
            }
        });
    }

    // print leanified XML to memory
    tinyxml2::XMLPrinter printer(0, true);
    doc.Print(&printer);

    size_t new_size = printer.CStrSize() - 1;     // -1 for the \0
    fp -= size_leanified;
    if (new_size < size)
    {
        memcpy(fp, printer.CStr(), new_size);
        return new_size;
    }
    else if (size_leanified)
    {
        memmove(fp, fp + size_leanified, size);
    }
    return size;
}

void Xml::TraverseElements(tinyxml2::XMLElement *ele, std::function<void(tinyxml2::XMLElement*)> callback)
{
    for (auto e = ele->FirstChildElement(); e; e = e->NextSiblingElement())
    {
        TraverseElements(e, callback);
    }

    callback(ele);
}

<|endoftext|>