<commit_before>//===--- TaskFuture.cpp - Unit tests for the task futures API -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/Basic/STLExtras.h"
#include "gtest/gtest.h"

using namespace swift;

namespace {
template <class T> struct FutureContext;

template <class T>
using InvokeFunctionRef =
  llvm::function_ref<void(AsyncTask *task,
                          ExecutorRef executor,
                          FutureContext<T> *context)>;

using BodyFunctionRef =
  llvm::function_ref<void(AsyncTask *task)>;

template <class Storage> struct PODFutureContext : AsyncContext {
  alignas(Storage) char resultStorage[sizeof(Storage)];
  void *errorStorage;
};

template <class Storage> struct FutureContext : PODFutureContext<Storage> {
  InvokeFunctionRef<Storage> storedInvokeFn;

  Storage& getStorage() {
    return *reinterpret_cast<Storage *>(&this->resultStorage[0]);
  }
};

// Disable template argument deduction.
template <class T>
using undeduced =
  typename std::enable_if<std::is_same<T, T>::value, T>::type;

template <class T>
SWIFT_CC(swift)
static void futureTaskInvokeFunction(AsyncTask *task, ExecutorRef executor,
                                     AsyncContext *context) {
  auto futureContext = static_cast<FutureContext<T>*>(context);
  futureContext->storedInvokeFn(task, executor, futureContext);

  // Return to finish off the task.
  // In a normal situation we'd need to free the context, but here
  // we know we're at the top level.
  futureContext->ResumeParent(task, executor, futureContext);
}

template <class T>
static void withFutureTask(const Metadata *resultType,
                           undeduced<InvokeFunctionRef<T>> invokeFn,
                           BodyFunctionRef body) {
  JobFlags flags = JobKind::Task;
  flags.task_setIsFuture(true);

  auto taskAndContext =
    swift_task_create_future_f(flags, /*parent*/ nullptr, resultType,
                               &futureTaskInvokeFunction<T>,
                               sizeof(FutureContext<T>),
                               offsetof(PODFutureContext<T>, resultStorage),
                               offsetof(PODFutureContext<T>, errorStorage));

  auto futureContext =
    static_cast<FutureContext<T>*>(taskAndContext.InitialContext);
  futureContext->getStorage() = 42; // Magic number.
  futureContext->storedInvokeFn = invokeFn;

  // Forward our owning reference to the task into its execution,
  // causing it to be destroyed when it completes.
  body(taskAndContext.Task);
}

static ExecutorRef createFakeExecutor(uintptr_t value) {
  return {reinterpret_cast<Executor*>(value)};
}
}

extern const FullMetadata<OpaqueMetadata> METADATA_SYM(Si);

TEST(TaskFutureTest, intFuture) {
  auto createdExecutor = createFakeExecutor(1234);
  bool hasRun = false;

  withFutureTask<intptr_t>(
      reinterpret_cast<const Metadata *>(&METADATA_SYM(Si)),
      [&](AsyncTask *task, ExecutorRef executor,
          FutureContext<intptr_t> *context) {
    // The storage should be what we initialized it to earlier.
    EXPECT_EQ(42, context->getStorage());

    // The error storage should have been cleared out for us.
    EXPECT_EQ(nullptr, context->errorStorage);

    // Store something in the future.
    context->getStorage() = 17;

    hasRun = true;
  }, [&](AsyncTask *task) {
    // Run the task, which should fill in the future.
    EXPECT_FALSE(hasRun);
    task->run(createdExecutor);
    EXPECT_TRUE(hasRun);

    // "Wait" for the future, which must have completed by now.
    auto waitResult = swift_task_future_wait(task, nullptr);
    EXPECT_EQ(TaskFutureWaitResult::Success, waitResult.kind);

    // Make sure we got the result value we expect.
    EXPECT_EQ(17, *reinterpret_cast<intptr_t *>(waitResult.storage));
  });
}

<commit_msg>[Future] Add a test to make sure we're handling object lifetimes properly.<commit_after>//===--- TaskFuture.cpp - Unit tests for the task futures API -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Demangling/ManglingMacros.h"
#include "swift/Basic/STLExtras.h"
#include "gtest/gtest.h"

using namespace swift;

namespace {
template <class T> struct FutureContext;

template <class T>
using InvokeFunctionRef =
  llvm::function_ref<void(AsyncTask *task,
                          ExecutorRef executor,
                          FutureContext<T> *context)>;

using BodyFunctionRef =
  llvm::function_ref<void(AsyncTask *task)>;

template <class Storage> struct PODFutureContext : AsyncContext {
  alignas(Storage) char resultStorage[sizeof(Storage)];
  void *errorStorage;
};

template <class Storage> struct FutureContext : PODFutureContext<Storage> {
  InvokeFunctionRef<Storage> storedInvokeFn;

  Storage& getStorage() {
    return *reinterpret_cast<Storage *>(&this->resultStorage[0]);
  }
};

// Disable template argument deduction.
template <class T>
using undeduced =
  typename std::enable_if<std::is_same<T, T>::value, T>::type;

template <class T>
SWIFT_CC(swift)
static void futureTaskInvokeFunction(AsyncTask *task, ExecutorRef executor,
                                     AsyncContext *context) {
  auto futureContext = static_cast<FutureContext<T>*>(context);
  futureContext->storedInvokeFn(task, executor, futureContext);

  // Return to finish off the task.
  // In a normal situation we'd need to free the context, but here
  // we know we're at the top level.
  futureContext->ResumeParent(task, executor, futureContext);
}

template <class T>
static void withFutureTask(const Metadata *resultType,
                           const T& initialValue,
                           undeduced<InvokeFunctionRef<T>> invokeFn,
                           BodyFunctionRef body) {
  JobFlags flags = JobKind::Task;
  flags.task_setIsFuture(true);

  auto taskAndContext =
    swift_task_create_future_f(flags, /*parent*/ nullptr, resultType,
                               &futureTaskInvokeFunction<T>,
                               sizeof(FutureContext<T>),
                               offsetof(PODFutureContext<T>, resultStorage),
                               offsetof(PODFutureContext<T>, errorStorage));

  auto futureContext =
    static_cast<FutureContext<T>*>(taskAndContext.InitialContext);
  futureContext->getStorage() = initialValue; // Magic number.
  futureContext->storedInvokeFn = invokeFn;

  // Forward our owning reference to the task into its execution,
  // causing it to be destroyed when it completes.
  body(taskAndContext.Task);
}

static ExecutorRef createFakeExecutor(uintptr_t value) {
  return {reinterpret_cast<Executor*>(value)};
}
}

extern const FullMetadata<OpaqueMetadata> METADATA_SYM(Si);

struct TestObject : HeapObject {
  constexpr TestObject(HeapMetadata const *newMetadata)
    : HeapObject(newMetadata, InlineRefCounts::Immortal)
    , Addr(NULL), Value(0) {}

  size_t *Addr;
  size_t Value;
};

static SWIFT_CC(swift) void destroyTestObject(SWIFT_CONTEXT HeapObject *_object) {
  auto object = static_cast<TestObject*>(_object);
  assert(object->Addr && "object already deallocated");
  *object->Addr = object->Value;
  object->Addr = nullptr;
  swift_deallocObject(object, sizeof(TestObject), alignof(TestObject) - 1);
}

static const FullMetadata<ClassMetadata> TestClassObjectMetadata = {
  { { &destroyTestObject }, { &VALUE_WITNESS_SYM(Bo) } },
  { { nullptr }, ClassFlags::UsesSwiftRefcounting, 0, 0, 0, 0, 0, 0 }
};

/// Create an object that, when deallocated, stores the given value to
/// the given pointer.
static TestObject *allocTestObject(size_t *addr, size_t value) {
  auto result =
    static_cast<TestObject *>(swift_allocObject(&TestClassObjectMetadata,
                                                sizeof(TestObject),
                                                alignof(TestObject) - 1));
  result->Addr = addr;
  result->Value = value;
  return result;
}

TEST(TaskFutureTest, intFuture) {
  auto createdExecutor = createFakeExecutor(1234);
  bool hasRun = false;

  withFutureTask<intptr_t>(
      reinterpret_cast<const Metadata *>(&METADATA_SYM(Si)), 42,
      [&](AsyncTask *task, ExecutorRef executor,
          FutureContext<intptr_t> *context) {
    // The storage should be what we initialized it to earlier.
    EXPECT_EQ(42, context->getStorage());

    // The error storage should have been cleared out for us.
    EXPECT_EQ(nullptr, context->errorStorage);

    // Store something in the future.
    context->getStorage() = 17;

    hasRun = true;
  }, [&](AsyncTask *task) {
    // Run the task, which should fill in the future.
    EXPECT_FALSE(hasRun);
    task->run(createdExecutor);
    EXPECT_TRUE(hasRun);

    // "Wait" for the future, which must have completed by now.
    auto waitResult = swift_task_future_wait(task, nullptr);
    EXPECT_EQ(TaskFutureWaitResult::Success, waitResult.kind);

    // Make sure we got the result value we expect.
    EXPECT_EQ(17, *reinterpret_cast<intptr_t *>(waitResult.storage));
  });
}

TEST(TaskFutureTest, objectFuture) {
  auto createdExecutor = createFakeExecutor(1234);
  bool hasRun = false;

  size_t objectValueOnComplete = 7;
  TestObject *object = nullptr;
  withFutureTask<TestObject *>(
      &TestClassObjectMetadata, nullptr,
      [&](AsyncTask *task, ExecutorRef executor,
          FutureContext<TestObject *> *context) {
    object = allocTestObject(&objectValueOnComplete, 25);

    // The error storage should have been cleared out for us.
    EXPECT_EQ(nullptr, context->errorStorage);

    // Store the object in the future.
    context->getStorage() = object;

    hasRun = true;
  }, [&](AsyncTask *task) {
    // Retain the task, so it won't be destroyed when it is executed.
    swift_retain(task);

    // Run the task, which should fill in the future.
    EXPECT_FALSE(hasRun);
    task->run(createdExecutor);
    EXPECT_TRUE(hasRun);

    // "Wait" for the future, which must have completed by now.
    auto waitResult = swift_task_future_wait(task, nullptr);
    EXPECT_EQ(TaskFutureWaitResult::Success, waitResult.kind);

    // Make sure we got the result value we expect.
    EXPECT_EQ(object, *reinterpret_cast<TestObject **>(waitResult.storage));

    // Make sure the object hasn't been destroyed.
    EXPECT_EQ(7, objectValueOnComplete);

    // Okay, release the task. This should destroy the object.
    swift_release(task);
    assert(objectValueOnComplete == 25);
  });

}
<|endoftext|>


<commit_before>#include <GuiBase/Viewer/TrackballCamera.hpp>

#include <QApplication>
#include <QMessageBox>
#include <iostream>

#include <Core/Event/KeyEvent.hpp>
#include <Core/Event/MouseEvent.hpp>
#include <Core/Log/Log.hpp>
#include <Core/Math/Math.hpp>
#include <Engine/Renderer/Camera/Camera.hpp>
#include <Engine/Renderer/Light/Light.hpp>

#include <GuiBase/Utils/KeyMappingManager.hpp>

namespace Ra {
using Core::Math::Pi;

Gui::TrackballCamera::TrackballCamera( uint width, uint height ) :
    CameraInterface( width, height ),
    m_trackballCenter( 0, 0, 0 ),
    m_quickCameraModifier( 1.f ),
    m_wheelSpeedModifier( 0.02f ),
    m_distFromCenter( 1.0f ),
    m_cameraRadius( 1.0f ),
    m_rotateAround( true ),
    m_cameraRotateMode( false ),
    m_cameraPanMode( false ),
    m_cameraZoomMode( false ),
    m_walkingOn( false ),
    m_strafingOn( false ),
    m_climbingOn( false ),
    m_walking( 0 ),
    m_strafing( 0 ),
    m_climbing( 0 ) {
    resetCamera();
}

Gui::TrackballCamera::~TrackballCamera() {}

void Gui::TrackballCamera::resetCamera() {
    m_camera->setFrame( Core::Transform::Identity() );
    m_camera->setPosition( Core::Vector3( 0, 0, 1 ) );
    m_trackballCenter = Core::Vector3::Zero();
    updatePhiTheta();

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::setCameraRadius( Scalar rad ) {
    m_cameraRadius = rad;
}
Scalar Gui::TrackballCamera::getCameraRadius() {
    return m_cameraRadius;
}

bool Gui::TrackballCamera::handleMousePressEvent( QMouseEvent* event ) {
    bool handled = false;
    m_lastMouseX = event->pos().x();
    m_lastMouseY = event->pos().y();

    /* TODO: Better handling of rotation/pan/zoom with KeyMappingManager */
    if ( event->modifiers().testFlag( Qt::NoModifier ) )
    {
        m_cameraRotateMode = true;
        handled = true;
    }

    if ( event->modifiers().testFlag( Qt::ShiftModifier ) )
    {
        m_cameraPanMode = true;
        handled = true;
    }

    if ( event->modifiers().testFlag( Qt::ControlModifier ) )
    {
        m_cameraZoomMode = true;
        handled = true;
    }

    return handled;
}

bool Gui::TrackballCamera::handleMouseMoveEvent( QMouseEvent* event ) {
    Scalar dx = ( event->pos().x() - m_lastMouseX ) / m_camera->getWidth();
    Scalar dy = ( event->pos().y() - m_lastMouseY ) / m_camera->getHeight();

    if ( event->modifiers().testFlag( Qt::AltModifier ) )
    {
        m_quickCameraModifier = 10.0;
    } else
    { m_quickCameraModifier = 2.0; }

    if ( m_cameraRotateMode )
    {
        handleCameraRotate( dx, dy );
    }

    if ( m_cameraPanMode )
    {
        handleCameraPan( dx, dy );
    }

    if ( m_cameraZoomMode )
    {
        handleCameraZoom( dx, dy );
    }

    m_lastMouseX = event->pos().x();
    m_lastMouseY = event->pos().y();

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );

    return true;
}

bool Gui::TrackballCamera::handleMouseReleaseEvent( QMouseEvent* event ) {
    m_cameraRotateMode = false;
    m_cameraPanMode = false;
    m_cameraZoomMode = false;
    m_quickCameraModifier = 1.0;

    return true;
}

bool Gui::TrackballCamera::handleWheelEvent( QWheelEvent* event ) {
    handleCameraZoom( ( event->angleDelta().y() * 0.01 + event->angleDelta().x() * 0.01 ) *
                      m_wheelSpeedModifier );

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    emit cameraPositionChanged( m_camera->getPosition() );

    return true;
}

bool Gui::TrackballCamera::handleKeyPressEvent( QKeyEvent* e ) {
    if ( Gui::KeyMappingManager::getInstance()->actionTriggered(
             e, Gui::KeyMappingManager::TRACKBALLCAMERA_ROTATE_AROUND ) )
    {
        m_rotateAround = !m_rotateAround;
        return true;
    }

    return false;
}

bool Gui::TrackballCamera::handleKeyReleaseEvent( QKeyEvent* e ) {
    return false;
}

void Gui::TrackballCamera::save( std::ostream& out ) const {
    out << "#Radium_trackball_camera_state" << std::endl;
    out << m_camera->getFrame().matrix() << std::endl;
    out << std::endl;
    out << m_camera->getFOV() << " " << m_camera->getZNear() << " " << m_camera->getZFar()
        << std::endl;
    out << std::endl;
    out << m_trackballCenter.transpose();
}

void Gui::TrackballCamera::load( std::istream& in ) {
    std::string str;
    Scalar M[16]; // 4x4 view matrix;
    Scalar fov, znear, zfar, x, y, z;

    in >> str;
    bool result = !in.fail();
    for ( uint i = 0; i < 16; ++i )
    {
        in >> M[i];
        result &= !in.fail();
    }
    in >> fov >> znear >> zfar >> x >> y >> z;
    result &= !in.fail();

    if ( !result )
    {
        LOG( logWARNING ) << "Could not load camera file data";
        return;
    }

    Core::Matrix4 frame;
    frame << M[0], M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12], M[13],
        M[14], M[15];

    Core::Transform T( frame );
    m_camera->setFrame( T );
    m_camera->setFOV( fov );
    m_camera->setZNear( znear );
    m_camera->setZFar( zfar );
    m_trackballCenter = Core::Vector3( x, y, x );

    updatePhiTheta();

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::setCameraPosition( const Core::Vector3& position ) {
    if ( position == m_trackballCenter )
    {
        QMessageBox::warning( nullptr, "Error", "Position cannot be set to target point" );
        return;
    }
    m_camera->setPosition( position );
    m_camera->setDirection( m_trackballCenter - position );

    updatePhiTheta();

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::setCameraTarget( const Core::Vector3& target ) {
    if ( m_camera->getPosition() == m_trackballCenter )
    {
        QMessageBox::warning( nullptr, "Error", "Target cannot be set to current camera position" );
        return;
    }

    m_trackballCenter = target;
    m_camera->setDirection( target - m_camera->getPosition() );
    updatePhiTheta();

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::fitScene( const Core::Aabb& aabb ) {
    resetCamera();

    Scalar f = m_camera->getFOV();
    Scalar a = m_camera->getAspect();

    const Scalar r = ( aabb.max() - aabb.min() ).norm() / 2.0;
    const Scalar x = r / std::sin( f / 2.0 );
    const Scalar y = r / std::sin( f * a / 2.0 );
    Scalar d = std::max( std::max( x, y ), Scalar( 0.001 ) );

    m_camera->setPosition(
        Core::Vector3( aabb.center().x(), aabb.center().y(), aabb.center().z() + d ) );
    m_camera->setDirection( Core::Vector3( 0, 0, -1 ) );
    m_trackballCenter = aabb.center();

    updatePhiTheta();

    m_distFromCenter = d;
    m_cameraRadius = d;

    Scalar zfar =
        std::max( Scalar( d + ( aabb.max().z() - aabb.min().z() ) * 2.0 ), m_camera->getZFar() );
    m_camera->setZFar( zfar );

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::handleCameraRotate( Scalar dx, Scalar dy ) {
    Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier;
    Scalar y = -dy * m_cameraSensitivity * m_quickCameraModifier;

    Scalar phi = m_phi + x; // Keep phi between -pi and pi
    Scalar theta = std::min( std::max( m_theta + y, Scalar( 0.0 ) ), Pi );

    Scalar dphi = phi - m_phi;
    Scalar dtheta = theta - m_theta;

    const Core::Vector3 C = m_trackballCenter;
    const Core::Vector3 P0 = m_camera->getPosition();
    const Scalar r = ( C - P0 ).norm();
    // Compute new camera position, on the sphere of radius r centered on C
    Scalar px = C.x() + r * std::cos( phi ) * std::sin( theta );
    Scalar py = C.y() + r * std::cos( theta );
    Scalar pz = C.z() + r * std::sin( phi ) * std::sin( theta );

    // Compute the translation from old pos to new pos
    Core::Vector3 P( px, py, pz );
    Core::Vector3 t( P - P0 );

    // Translate the camera given this translation
    Core::Transform T( Core::Transform::Identity() );
    T.translation() = t;

    // Rotate the camera so that it points to the center
    Core::Transform R1( Core::Transform::Identity() );
    Core::Transform R2( Core::Transform::Identity() );

    Core::Vector3 U = Core::Vector3( 0, 1, 0 );
    Core::Vector3 R = -m_camera->getRightVector().normalized();

    R1 = Core::AngleAxis( -dphi, U );
    R2 = Core::AngleAxis( -dtheta, R );

    m_camera->applyTransform( T * R1 * R2 );

    m_phi = phi;
    m_theta = theta;
}

void Gui::TrackballCamera::handleCameraPan( Scalar dx, Scalar dy ) {
    Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1;
    Scalar y = dy * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1;
    // Move camera and trackball center, keep the distance to the center
    Core::Vector3 R = -m_camera->getRightVector();
    Core::Vector3 U = m_camera->getUpVector();

    Core::Transform T( Core::Transform::Identity() );
    Core::Vector3 t = x * R + y * U;
    T.translate( t );

    m_camera->applyTransform( T );
    m_trackballCenter += t;
}

void Gui::TrackballCamera::handleCameraZoom( Scalar dx, Scalar dy ) {
    handleCameraZoom( Ra::Core::Math::sign( dx ) * ( std::abs( dx ) + std::abs( dy ) ) );
}

void Gui::TrackballCamera::handleCameraZoom( Scalar z ) {
    Scalar y = m_cameraRadius * z * m_cameraSensitivity * m_quickCameraModifier;
    Core::Vector3 F = m_camera->getDirection();

    Scalar dist = ( m_trackballCenter - m_camera->getPosition() ).norm();

    if ( dist < ( m_camera->getZNear() + y ) )
    {
        y = dist - m_camera->getZNear();
    }

    Core::Transform T( Core::Transform::Identity() );
    Core::Vector3 t = y * F;
    T.translate( t );

    m_camera->applyTransform( T );

    // m_trackballCenter = m_camera->getPosition() + m_camera->getDirection().normalized();

    emit cameraTargetChanged( m_trackballCenter );

    // m_distFromCenter = ( m_trackballCenter - m_camera->getPosition() ).norm();
}

void Gui::TrackballCamera::updatePhiTheta() {
    const Core::Vector3& P = m_camera->getPosition();
    const Core::Vector3& C = m_trackballCenter;
    const Core::Vector3& R = P - C;
    const Scalar r = R.norm();

    m_theta = std::acos( R.y() / r );
    m_phi = ( R.z() == 0.f && R.x() == 0.f ) ? 0.f : std::atan2( R.z(), R.x() );
    CORE_ASSERT( std::isfinite( m_theta ) && std::isfinite( m_phi ), "Error in trackball camera" );
}
} // namespace Ra
<commit_msg>Fix camera load ;<commit_after>#include <GuiBase/Viewer/TrackballCamera.hpp>

#include <QApplication>
#include <QMessageBox>
#include <iostream>

#include <Core/Event/KeyEvent.hpp>
#include <Core/Event/MouseEvent.hpp>
#include <Core/Log/Log.hpp>
#include <Core/Math/Math.hpp>
#include <Engine/Renderer/Camera/Camera.hpp>
#include <Engine/Renderer/Light/Light.hpp>

#include <GuiBase/Utils/KeyMappingManager.hpp>

namespace Ra {
using Core::Math::Pi;

Gui::TrackballCamera::TrackballCamera( uint width, uint height ) :
    CameraInterface( width, height ),
    m_trackballCenter( 0, 0, 0 ),
    m_quickCameraModifier( 1.f ),
    m_wheelSpeedModifier( 0.02f ),
    m_distFromCenter( 1.0f ),
    m_cameraRadius( 1.0f ),
    m_rotateAround( true ),
    m_cameraRotateMode( false ),
    m_cameraPanMode( false ),
    m_cameraZoomMode( false ),
    m_walkingOn( false ),
    m_strafingOn( false ),
    m_climbingOn( false ),
    m_walking( 0 ),
    m_strafing( 0 ),
    m_climbing( 0 ) {
    resetCamera();
}

Gui::TrackballCamera::~TrackballCamera() {}

void Gui::TrackballCamera::resetCamera() {
    m_camera->setFrame( Core::Transform::Identity() );
    m_camera->setPosition( Core::Vector3( 0, 0, 1 ) );
    m_trackballCenter = Core::Vector3::Zero();
    updatePhiTheta();

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::setCameraRadius( Scalar rad ) {
    m_cameraRadius = rad;
}
Scalar Gui::TrackballCamera::getCameraRadius() {
    return m_cameraRadius;
}

bool Gui::TrackballCamera::handleMousePressEvent( QMouseEvent* event ) {
    bool handled = false;
    m_lastMouseX = event->pos().x();
    m_lastMouseY = event->pos().y();

    /* TODO: Better handling of rotation/pan/zoom with KeyMappingManager */
    if ( event->modifiers().testFlag( Qt::NoModifier ) )
    {
        m_cameraRotateMode = true;
        handled = true;
    }

    if ( event->modifiers().testFlag( Qt::ShiftModifier ) )
    {
        m_cameraPanMode = true;
        handled = true;
    }

    if ( event->modifiers().testFlag( Qt::ControlModifier ) )
    {
        m_cameraZoomMode = true;
        handled = true;
    }

    return handled;
}

bool Gui::TrackballCamera::handleMouseMoveEvent( QMouseEvent* event ) {
    Scalar dx = ( event->pos().x() - m_lastMouseX ) / m_camera->getWidth();
    Scalar dy = ( event->pos().y() - m_lastMouseY ) / m_camera->getHeight();

    if ( event->modifiers().testFlag( Qt::AltModifier ) )
    {
        m_quickCameraModifier = 10.0;
    } else
    { m_quickCameraModifier = 2.0; }

    if ( m_cameraRotateMode )
    {
        handleCameraRotate( dx, dy );
    }

    if ( m_cameraPanMode )
    {
        handleCameraPan( dx, dy );
    }

    if ( m_cameraZoomMode )
    {
        handleCameraZoom( dx, dy );
    }

    m_lastMouseX = event->pos().x();
    m_lastMouseY = event->pos().y();

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );

    return true;
}

bool Gui::TrackballCamera::handleMouseReleaseEvent( QMouseEvent* event ) {
    m_cameraRotateMode = false;
    m_cameraPanMode = false;
    m_cameraZoomMode = false;
    m_quickCameraModifier = 1.0;

    return true;
}

bool Gui::TrackballCamera::handleWheelEvent( QWheelEvent* event ) {
    handleCameraZoom( ( event->angleDelta().y() * 0.01 + event->angleDelta().x() * 0.01 ) *
                      m_wheelSpeedModifier );

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    emit cameraPositionChanged( m_camera->getPosition() );

    return true;
}

bool Gui::TrackballCamera::handleKeyPressEvent( QKeyEvent* e ) {
    if ( Gui::KeyMappingManager::getInstance()->actionTriggered(
             e, Gui::KeyMappingManager::TRACKBALLCAMERA_ROTATE_AROUND ) )
    {
        m_rotateAround = !m_rotateAround;
        return true;
    }

    return false;
}

bool Gui::TrackballCamera::handleKeyReleaseEvent( QKeyEvent* e ) {
    return false;
}

void Gui::TrackballCamera::save( std::ostream& out ) const {
    out << "#Radium_trackball_camera_state" << std::endl;
    out << m_camera->getFrame().matrix() << std::endl;
    out << std::endl;
    out << m_camera->getFOV() << " " << m_camera->getZNear() << " " << m_camera->getZFar() << " "
        << m_camera->getZoomFactor() << " " << m_cameraRadius << " " << m_distFromCenter
        << std::endl;
    out << std::endl;
    out << m_trackballCenter.transpose();
    out << std::endl;
}

void Gui::TrackballCamera::load( std::istream& in ) {
    std::string str;
    Scalar M[16]; // 4x4 view matrix;
    Scalar fov, znear, zfar, Z, r, d, x, y, z;

    in >> str;
    bool result = !in.fail();
    for ( uint i = 0; i < 16; ++i )
    {
        in >> M[i];
        result &= !in.fail();
    }
    in >> fov >> znear >> zfar >> Z >> r >> d >> x >> y >> z;
    result &= !in.fail();

    if ( !result )
    {
        LOG( logWARNING ) << "Could not load camera file data";
        return;
    }
    m_cameraRadius = r;
    m_distFromCenter = d;

    Core::Matrix4 frame;
    frame << M[0], M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8], M[9], M[10], M[11], M[12], M[13],
        M[14], M[15];

    Core::Transform T( frame );
    m_camera->setFrame( T );
    m_camera->setFOV( fov );
    m_camera->setZNear( znear );
    m_camera->setZFar( zfar );
    m_camera->setZoomFactor( Z );
    m_trackballCenter = Core::Vector3( x, y, z );

    updatePhiTheta();

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    save( std::cout );

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::setCameraPosition( const Core::Vector3& position ) {
    if ( position == m_trackballCenter )
    {
        QMessageBox::warning( nullptr, "Error", "Position cannot be set to target point" );
        return;
    }
    m_camera->setPosition( position );
    m_camera->setDirection( m_trackballCenter - position );

    updatePhiTheta();

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::setCameraTarget( const Core::Vector3& target ) {
    if ( m_camera->getPosition() == m_trackballCenter )
    {
        QMessageBox::warning( nullptr, "Error", "Target cannot be set to current camera position" );
        return;
    }

    m_trackballCenter = target;
    m_camera->setDirection( target - m_camera->getPosition() );
    updatePhiTheta();

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::fitScene( const Core::Aabb& aabb ) {
    resetCamera();

    Scalar f = m_camera->getFOV();
    Scalar a = m_camera->getAspect();

    const Scalar r = ( aabb.max() - aabb.min() ).norm() / 2.0;
    const Scalar x = r / std::sin( f / 2.0 );
    const Scalar y = r / std::sin( f * a / 2.0 );
    Scalar d = std::max( std::max( x, y ), Scalar( 0.001 ) );

    m_camera->setPosition(
        Core::Vector3( aabb.center().x(), aabb.center().y(), aabb.center().z() + d ) );
    m_camera->setDirection( Core::Vector3( 0, 0, -1 ) );
    m_trackballCenter = aabb.center();

    updatePhiTheta();

    m_distFromCenter = d;
    m_cameraRadius = d;

    Scalar zfar =
        std::max( Scalar( d + ( aabb.max().z() - aabb.min().z() ) * 2.0 ), m_camera->getZFar() );
    m_camera->setZFar( zfar );

    if ( m_hasLightAttached )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    emit cameraPositionChanged( m_camera->getPosition() );
    emit cameraTargetChanged( m_trackballCenter );
}

void Gui::TrackballCamera::handleCameraRotate( Scalar dx, Scalar dy ) {
    Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier;
    Scalar y = -dy * m_cameraSensitivity * m_quickCameraModifier;

    Scalar phi = m_phi + x; // Keep phi between -pi and pi
    Scalar theta = std::min( std::max( m_theta + y, Scalar( 0.0 ) ), Pi );

    Scalar dphi = phi - m_phi;
    Scalar dtheta = theta - m_theta;

    const Core::Vector3 C = m_trackballCenter;
    const Core::Vector3 P0 = m_camera->getPosition();
    const Scalar r = ( C - P0 ).norm();
    // Compute new camera position, on the sphere of radius r centered on C
    Scalar px = C.x() + r * std::cos( phi ) * std::sin( theta );
    Scalar py = C.y() + r * std::cos( theta );
    Scalar pz = C.z() + r * std::sin( phi ) * std::sin( theta );

    // Compute the translation from old pos to new pos
    Core::Vector3 P( px, py, pz );
    Core::Vector3 t( P - P0 );

    // Translate the camera given this translation
    Core::Transform T( Core::Transform::Identity() );
    T.translation() = t;

    // Rotate the camera so that it points to the center
    Core::Transform R1( Core::Transform::Identity() );
    Core::Transform R2( Core::Transform::Identity() );

    Core::Vector3 U = Core::Vector3( 0, 1, 0 );
    Core::Vector3 R = -m_camera->getRightVector().normalized();

    R1 = Core::AngleAxis( -dphi, U );
    R2 = Core::AngleAxis( -dtheta, R );

    m_camera->applyTransform( T * R1 * R2 );

    m_phi = phi;
    m_theta = theta;
}

void Gui::TrackballCamera::handleCameraPan( Scalar dx, Scalar dy ) {
    Scalar x = dx * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1;
    Scalar y = dy * m_cameraSensitivity * m_quickCameraModifier * m_distFromCenter * 0.1;
    // Move camera and trackball center, keep the distance to the center
    Core::Vector3 R = -m_camera->getRightVector();
    Core::Vector3 U = m_camera->getUpVector();

    Core::Transform T( Core::Transform::Identity() );
    Core::Vector3 t = x * R + y * U;
    T.translate( t );

    m_camera->applyTransform( T );
    m_trackballCenter += t;
}

void Gui::TrackballCamera::handleCameraZoom( Scalar dx, Scalar dy ) {
    handleCameraZoom( Ra::Core::Math::sign( dx ) * ( std::abs( dx ) + std::abs( dy ) ) );
}

void Gui::TrackballCamera::handleCameraZoom( Scalar z ) {
    Scalar y = m_cameraRadius * z * m_cameraSensitivity * m_quickCameraModifier;
    Core::Vector3 F = m_camera->getDirection();

    Scalar dist = ( m_trackballCenter - m_camera->getPosition() ).norm();

    if ( dist < ( m_camera->getZNear() + y ) )
    {
        y = dist - m_camera->getZNear();
    }

    Core::Transform T( Core::Transform::Identity() );
    Core::Vector3 t = y * F;
    T.translate( t );

    m_camera->applyTransform( T );

    // m_trackballCenter = m_camera->getPosition() + m_camera->getDirection().normalized();

    emit cameraTargetChanged( m_trackballCenter );

    // m_distFromCenter = ( m_trackballCenter - m_camera->getPosition() ).norm();
}

void Gui::TrackballCamera::updatePhiTheta() {
    const Core::Vector3& P = m_camera->getPosition();
    const Core::Vector3& C = m_trackballCenter;
    const Core::Vector3& R = P - C;
    const Scalar r = R.norm();

    m_theta = std::acos( R.y() / r );
    m_phi = ( R.z() == 0.f && R.x() == 0.f ) ? 0.f : std::atan2( R.z(), R.x() );
    CORE_ASSERT( std::isfinite( m_theta ) && std::isfinite( m_phi ), "Error in trackball camera" );
}
} // namespace Ra
<|endoftext|>


<commit_before>

#include "wsclient.hpp"
#include <cossb.hpp>
#include <algorithm>
#include <ext/json.hpp>

USE_COMPONENT_INTERFACE(wsclient)

void handle_message(const std::string & message)
{
	nlohmann::json _json_data = nlohmann::json::parse(message);

	if(_json_data.find("service")!=_json_data.end()){
		string wsdata = _json_data.dump();
		string service = _json_data["service"];
		cossb::message msg("wsclient", base::msg_type::REQUEST);
		msg.pack(wsdata);
		cossb_broker->publish(service.c_str(), msg);
		cossb_log->log(log::loglevel::INFO, fmt::format("Web socket message : {}", wsdata));
	}

}

wsclient::wsclient()
:cossb::interface::icomponent(COMPONENT(wsclient)){
	// TODO Auto-generated constructor stub

}

wsclient::~wsclient() {

}

bool wsclient::setup()
{
	string uri = get_profile()->get(profile::section::property, "endpoint").asString("ws://localhost.9002");

	if(!_client){
		_client = easywsclient::WebSocket::from_url(uri.c_str());
		if(_client->getReadyState()==easywsclient::WebSocket::OPEN){
			cossb_log->log(log::loglevel::INFO, fmt::format("Connected to the {} websocket server",uri));
			if(!_socket_task)
				_socket_task = create_task(wsclient::read);
			return true;
		}
	}
	return false;
}

bool wsclient::run()
{

	return true;
}

bool wsclient::stop()
{
	destroy_task(_socket_task);

	_client->close();
	delete _client;

	return true;
}

void wsclient::subscribe(cossb::message* const msg)
{
	switch(msg->get_frame()->type){
		case cossb::base::msg_type::REQUEST:{

			string pack = boost::any_cast<string>(*msg->get_data());

		} break;
		case cossb::base::msg_type::DATA: break;
		case cossb::base::msg_type::RESPONSE: break;
		case cossb::base::msg_type::EVENT: break;

	}
}

void wsclient::read()
{
	while(1) {
		try {
			if(_client->getReadyState()!=easywsclient::WebSocket::CLOSED){
				_client->poll();
				_client->dispatch(handle_message);
			}

			boost::this_thread::sleep(boost::posix_time::milliseconds(100));
			if(boost::this_thread::interruption_requested()) break;
		}
		catch(thread_interrupted&) {
			break;
		}
	}
}
<commit_msg>update<commit_after>

#include "wsclient.hpp"
#include <cossb.hpp>
#include <algorithm>
#include <ext/json.hpp>

USE_COMPONENT_INTERFACE(wsclient)

void handle_message(const std::string & message)
{
	nlohmann::json _json_data = nlohmann::json::parse(message);

	if(_json_data.find("service")!=_json_data.end()){
		string wsdata = _json_data.dump();
		string service = _json_data["service"];
		cossb::message msg("wsclient", base::msg_type::REQUEST);
		msg.pack(wsdata);
		cossb_broker->publish(service.c_str(), msg);
		cossb_log->log(log::loglevel::INFO, fmt::format("Publish WS message : {}", wsdata));
	}

}

wsclient::wsclient()
:cossb::interface::icomponent(COMPONENT(wsclient)){
	// TODO Auto-generated constructor stub

}

wsclient::~wsclient() {

}

bool wsclient::setup()
{
	string uri = get_profile()->get(profile::section::property, "endpoint").asString("ws://localhost.9002");

	if(!_client){
		_client = easywsclient::WebSocket::from_url(uri.c_str());
		if(_client->getReadyState()==easywsclient::WebSocket::OPEN){
			cossb_log->log(log::loglevel::INFO, fmt::format("Connected to the {} websocket server",uri));
			if(!_socket_task)
				_socket_task = create_task(wsclient::read);
			return true;
		}
	}
	return false;
}

bool wsclient::run()
{

	return true;
}

bool wsclient::stop()
{
	destroy_task(_socket_task);

	_client->close();
	delete _client;

	return true;
}

void wsclient::subscribe(cossb::message* const msg)
{
	switch(msg->get_frame()->type){
		case cossb::base::msg_type::REQUEST:{

			string pack = boost::any_cast<string>(*msg->get_data());

		} break;
		case cossb::base::msg_type::DATA: break;
		case cossb::base::msg_type::RESPONSE: break;
		case cossb::base::msg_type::EVENT: break;

	}
}

void wsclient::read()
{
	while(1) {
		try {
			if(_client->getReadyState()!=easywsclient::WebSocket::CLOSED){
				_client->poll();
				_client->dispatch(handle_message);
			}

			boost::this_thread::sleep(boost::posix_time::milliseconds(100));
			if(boost::this_thread::interruption_requested()) break;
		}
		catch(thread_interrupted&) {
			break;
		}
	}
}
<|endoftext|>


<commit_before>/**
 * @file ProcessBus.hpp
 * @author Denis Kotov
 * @date 25 Jun 2017
 * @brief Contains ProcessBus class.
 * It is a broker pattern. Used to control registration
 * and connection of services
 * @copyright Denis Kotov, MIT License. Open source:
 */

#ifndef ICC_PROCESSBUS_HPP
#define ICC_PROCESSBUS_HPP

#include <typeinfo>
#include <set>
#include <map>
#include <algorithm>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
#include <IComponent.hpp>

template <typename _Interface>
class IClient;

template <typename _Interface>
class IService;

class ProcessBus
  : public IComponent {
 public:
  using tKeyForClientList = std::pair<std::type_index, std::string>;
  using tListOfClients = std::set<void*>;
  using tKeyForServiceList = std::type_index;
  using tListOfServices = std::map<std::string, void*>;

 public:
  template <typename _Interface>
  void registerService(IService<_Interface> * _service,
                       const std::string & _serviceName) {
    push([=]{
      services_[tKeyForServiceList(typeid(_Interface))].emplace(_serviceName, _service);
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      auto clients = clients_[clientsKey];
      for (auto client : clients) {
        reinterpret_cast<IClient<_Interface>*>(client)->setService(_service);
      }
    });
  }

  template <typename _Interface>
  void unregisterService(IService<_Interface> * _service,
                         const std::string & _serviceName) {
    push([=]{
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      auto clients = clients_[clientsKey];
      for (auto client : clients) {
        reinterpret_cast<IClient<_Interface>*>(client)->setService(nullptr);
      }
    });
  }

  template <typename _Interface>
  void buildClient(IClient<_Interface> * _client,
                   const std::string & _serviceName) {
    push([=] {
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      clients_[clientsKey].emplace(_client);
      auto servicesIter = services_.find(std::type_index(typeid(_Interface)));
      if (services_.end() != servicesIter) {
        auto serviceIter = std::find_if(servicesIter->second.begin(),
                                        servicesIter->second.end(),
        [=](std::pair<std::string, void*> element) {
          return element.first == _serviceName;
        });
        if (servicesIter->second.end() != serviceIter) {
          _client->setService(
              reinterpret_cast<IService<_Interface>*>(serviceIter->second));
        }
      }
    });
  }

  template <typename _Interface>
  void disassembleClient(IClient<_Interface> * _client,
                         const std::string & _serviceName) {
    push([=] {
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      clients_[clientsKey].erase(_client);
    });
  }

 public:
  static ProcessBus & getBus();

 private:
  ProcessBus();
  ProcessBus(const ProcessBus &) = delete;
  ProcessBus(ProcessBus &&) = delete;
  virtual ~ProcessBus();

 private:
  std::thread thread_;
  std::map<tKeyForClientList, tListOfClients> clients_;
  std::map<tKeyForServiceList, tListOfServices> services_;
};

#endif //ICC_PROCESSBUS_HPP
<commit_msg>Removed extra header<commit_after>/**
 * @file ProcessBus.hpp
 * @author Denis Kotov
 * @date 25 Jun 2017
 * @brief Contains ProcessBus class.
 * It is a broker pattern. Used to control registration
 * and connection of services
 * @copyright Denis Kotov, MIT License. Open source:
 */

#ifndef ICC_PROCESSBUS_HPP
#define ICC_PROCESSBUS_HPP

#include <set>
#include <map>
#include <algorithm>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>
#include <IComponent.hpp>

template <typename _Interface>
class IClient;

template <typename _Interface>
class IService;

class ProcessBus
  : public IComponent {
 public:
  using tKeyForClientList = std::pair<std::type_index, std::string>;
  using tListOfClients = std::set<void*>;
  using tKeyForServiceList = std::type_index;
  using tListOfServices = std::map<std::string, void*>;

 public:
  template <typename _Interface>
  void registerService(IService<_Interface> * _service,
                       const std::string & _serviceName) {
    push([=]{
      services_[tKeyForServiceList(typeid(_Interface))].emplace(_serviceName, _service);
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      auto clients = clients_[clientsKey];
      for (auto client : clients) {
        reinterpret_cast<IClient<_Interface>*>(client)->setService(_service);
      }
    });
  }

  template <typename _Interface>
  void unregisterService(IService<_Interface> * _service,
                         const std::string & _serviceName) {
    push([=]{
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      auto clients = clients_[clientsKey];
      for (auto client : clients) {
        reinterpret_cast<IClient<_Interface>*>(client)->setService(nullptr);
      }
    });
  }

  template <typename _Interface>
  void buildClient(IClient<_Interface> * _client,
                   const std::string & _serviceName) {
    push([=] {
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      clients_[clientsKey].emplace(_client);
      auto servicesIter = services_.find(std::type_index(typeid(_Interface)));
      if (services_.end() != servicesIter) {
        auto serviceIter = std::find_if(servicesIter->second.begin(),
                                        servicesIter->second.end(),
        [=](std::pair<std::string, void*> element) {
          return element.first == _serviceName;
        });
        if (servicesIter->second.end() != serviceIter) {
          _client->setService(
              reinterpret_cast<IService<_Interface>*>(serviceIter->second));
        }
      }
    });
  }

  template <typename _Interface>
  void disassembleClient(IClient<_Interface> * _client,
                         const std::string & _serviceName) {
    push([=] {
      auto clientsKey = tKeyForClientList{typeid(_Interface), _serviceName};
      clients_[clientsKey].erase(_client);
    });
  }

 public:
  static ProcessBus & getBus();

 private:
  ProcessBus();
  ProcessBus(const ProcessBus &) = delete;
  ProcessBus(ProcessBus &&) = delete;
  virtual ~ProcessBus();

 private:
  std::thread thread_;
  std::map<tKeyForClientList, tListOfClients> clients_;
  std::map<tKeyForServiceList, tListOfServices> services_;
};

#endif //ICC_PROCESSBUS_HPP
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "frame_buffer.h"
#include "packet.h"

#include <cassert>
#include <string.h>

#if defined(_WIN32)
    // VS 2005: Don't warn for default initialized arrays. See help for more info.
    #pragma warning(disable:4351)
#endif

namespace webrtc {

VCMFrameBuffer::VCMFrameBuffer()
  :
    _state(kStateFree),
    _frameCounted(false),
    _nackCount(0),
    _latestPacketTimeMs(-1) {
}

VCMFrameBuffer::~VCMFrameBuffer() {
}

VCMFrameBuffer::VCMFrameBuffer(VCMFrameBuffer& rhs)
:
VCMEncodedFrame(rhs),
_state(rhs._state),
_frameCounted(rhs._frameCounted),
_sessionInfo(),
_nackCount(rhs._nackCount),
_latestPacketTimeMs(rhs._latestPacketTimeMs)
{
    _sessionInfo = rhs._sessionInfo;
}

webrtc::FrameType
VCMFrameBuffer::FrameType() const
{
    return _sessionInfo.FrameType();
}

void
VCMFrameBuffer::SetPreviousFrameLoss()
{
    _sessionInfo.SetPreviousFrameLoss();
}

WebRtc_Word32
VCMFrameBuffer::GetLowSeqNum() const
{
    return _sessionInfo.LowSequenceNumber();
}

WebRtc_Word32
VCMFrameBuffer::GetHighSeqNum() const
{
    return _sessionInfo.HighSequenceNumber();
}

int VCMFrameBuffer::PictureId() const {
  return _sessionInfo.PictureId();
}

int VCMFrameBuffer::TemporalId() const {
  return _sessionInfo.TemporalId();
}

bool VCMFrameBuffer::LayerSync() const {
  return _sessionInfo.LayerSync();
}

int VCMFrameBuffer::Tl0PicId() const {
  return _sessionInfo.Tl0PicId();
}

bool VCMFrameBuffer::NonReference() const {
  return _sessionInfo.NonReference();
}

bool
VCMFrameBuffer::IsSessionComplete() const
{
    return _sessionInfo.complete();
}

// Insert packet
VCMFrameBufferEnum
VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs,
                             bool enableDecodableState, WebRtc_UWord32 rttMS)
{
    if (_state == kStateDecoding)
    {
        // Do not insert packet
        return kIncomplete;
    }

    // Sanity to check if the frame has been freed. (Too old for example)
    if (_state == kStateFree)
    {
        return kStateError;
    }

    // is this packet part of this frame
    if (TimeStamp() && (TimeStamp() != packet.timestamp))
    {
        return kTimeStampError;
    }

    // sanity checks
    if (_size + packet.sizeBytes +
        (packet.insertStartCode ?  kH264StartCodeLengthBytes : 0 )
        > kMaxJBFrameSizeBytes)
    {
        return kSizeError;
    }
    if (NULL == packet.dataPtr && packet.sizeBytes > 0)
    {
        return kSizeError;
    }
    if (packet.dataPtr != NULL)
    {
        _payloadType = packet.payloadType;
    }

    if (kStateEmpty == _state)
    {
        // First packet (empty and/or media) inserted into this frame.
        // store some info and set some initial values.
        _timeStamp = packet.timestamp;
        _codec = packet.codec;
        if (packet.frameType != kFrameEmpty)
        {
            // first media packet
            SetState(kStateIncomplete);
        }
    }

    WebRtc_UWord32 requiredSizeBytes = Length() + packet.sizeBytes +
                   (packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
    if (requiredSizeBytes >= _size)
    {
        const WebRtc_UWord8* prevBuffer = _buffer;
        const WebRtc_UWord32 increments = requiredSizeBytes /
                                          kBufferIncStepSizeBytes +
                                        (requiredSizeBytes %
                                         kBufferIncStepSizeBytes > 0);
        const WebRtc_UWord32 newSize = _size +
                                       increments * kBufferIncStepSizeBytes;
        if (newSize > kMaxJBFrameSizeBytes)
        {
            return kSizeError;
        }
        if (VerifyAndAllocate(newSize) == -1)
        {
            return kSizeError;
        }
        _sessionInfo.UpdateDataPointers(_buffer - prevBuffer);
    }

    CopyCodecSpecific(&packet.codecSpecificHeader);

    int retVal = _sessionInfo.InsertPacket(packet, _buffer,
                                           enableDecodableState,
                                           rttMS);
    if (retVal == -1)
    {
        return kSizeError;
    }
    else if (retVal == -2)
    {
        return kDuplicatePacket;
    }
    // update length
    _length = Length() + static_cast<WebRtc_UWord32>(retVal);

    _latestPacketTimeMs = timeInMs;

    if (_sessionInfo.complete()) {
      return kCompleteSession;
    } else if (_sessionInfo.decodable()) {
      SetState(kStateDecodable);
      return kDecodableSession;
    } else {
      // this layer is not complete
      if (_state == kStateComplete) {
        // we already have a complete layer
        // wait for all independent layers belonging to the same frame
        _state = kStateIncomplete;
      }
    }
    return kIncomplete;
}

WebRtc_Word64
VCMFrameBuffer::LatestPacketTimeMs()
{
    return _latestPacketTimeMs;
}

// Zero out all entries in list up to and including the (first)
// entry equal to _lowSeqNum
WebRtc_Word32
VCMFrameBuffer::ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num)
{
    if (_sessionInfo.ZeroOutSeqNum(list, num) != 0)
    {
       return -1;
    }
    return 0;
}

// Zero out all entries in list up to and including the (first) entry equal to
// _lowSeqNum. Hybrid mode: 1. Don't NACK FEC packets 2. Make a smart decision
// on whether to NACK or not

WebRtc_Word32
VCMFrameBuffer::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
                                    WebRtc_Word32 num,
                                    WebRtc_UWord32 rttMs)
{
    return _sessionInfo.ZeroOutSeqNumHybrid(list, num, rttMs);
}

void
VCMFrameBuffer::IncrementNackCount()
{
    _nackCount++;
}

WebRtc_Word16
VCMFrameBuffer::GetNackCount() const
{
    return _nackCount;
}

bool
VCMFrameBuffer::HaveLastPacket() const
{
    return _sessionInfo.HaveLastPacket();
}

void
VCMFrameBuffer::Reset()
{
    _length = 0;
    _timeStamp = 0;
    _sessionInfo.Reset();
    _frameCounted = false;
    _payloadType = 0;
    _nackCount = 0;
    _latestPacketTimeMs = -1;
    _state = kStateFree;
    VCMEncodedFrame::Reset();
}

// Makes sure the session contains a decodable stream.
void
VCMFrameBuffer::MakeSessionDecodable()
{
    WebRtc_UWord32 retVal;
#ifdef INDEPENDENT_PARTITIONS
    if (_codec != kVideoCodecVP8) {
        retVal = _sessionInfo.MakeDecodable();
        _length -= retVal;
    }
#else
    retVal = _sessionInfo.MakeDecodable();
    _length -= retVal;
#endif
}

// Set state of frame
void
VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state)
{
    if (_state == state)
    {
        return;
    }
    switch (state)
    {
    case kStateFree:
        // Reset everything
        // We can go to this state from all other states.
        // The one setting the state to free must ensure
        // that the frame is removed from the timestamp
        // ordered frame list in the jb.
        Reset();
        break;

    case kStateIncomplete:
        // we can go to this state from state kStateEmpty
        assert(_state == kStateEmpty ||
            _state == kStateDecoding);

        // Do nothing, we received a packet
        break;

    case kStateComplete:
        assert(_state == kStateEmpty ||
               _state == kStateIncomplete ||
               _state == kStateDecodable);

        break;

    case kStateEmpty:
        assert(_state == kStateFree);
        // Do nothing
        break;

    case kStateDecoding:
        // A frame might have received empty packets, or media packets might
        // have been removed when making the frame decodable. The frame can
        // still be set to decodable since it can be used to inform the
        // decoder of a frame loss.
        assert(_state == kStateComplete || _state == kStateIncomplete ||
               _state == kStateDecodable || _state == kStateEmpty);
        // Transfer frame information to EncodedFrame and create any codec
        // specific information
        RestructureFrameInformation();
        break;

    case kStateDecodable:
        assert(_state == kStateEmpty ||
               _state == kStateIncomplete);
        break;

    default:
        // Should never happen
        assert(!"FrameBuffer::SetState Incorrect frame buffer state as input");
        return;
    }
    _state = state;
}

void
VCMFrameBuffer::RestructureFrameInformation()
{
    PrepareForDecode();
    _frameType = ConvertFrameType(_sessionInfo.FrameType());
    _completeFrame = _sessionInfo.complete();
    _missingFrame = _sessionInfo.PreviousFrameLoss();
}

WebRtc_Word32
VCMFrameBuffer::ExtractFromStorage(const EncodedVideoData& frameFromStorage)
{
    _frameType = ConvertFrameType(frameFromStorage.frameType);
    _timeStamp = frameFromStorage.timeStamp;
    _payloadType = frameFromStorage.payloadType;
    _encodedWidth = frameFromStorage.encodedWidth;
    _encodedHeight = frameFromStorage.encodedHeight;
    _missingFrame = frameFromStorage.missingFrame;
    _completeFrame = frameFromStorage.completeFrame;
    _renderTimeMs = frameFromStorage.renderTimeMs;
    _codec = frameFromStorage.codec;
    const WebRtc_UWord8 *prevBuffer = _buffer;
    if (VerifyAndAllocate(frameFromStorage.payloadSize) < 0)
    {
        return VCM_MEMORY;
    }
    _sessionInfo.UpdateDataPointers(_buffer - prevBuffer);
    memcpy(_buffer, frameFromStorage.payloadData, frameFromStorage.payloadSize);
    _length = frameFromStorage.payloadSize;
    return VCM_OK;
}

int VCMFrameBuffer::NotDecodablePackets() const {
  return _sessionInfo.packets_not_decodable();
}

// Set counted status (as counted by JB or not)
void VCMFrameBuffer::SetCountedFrame(bool frameCounted)
{
    _frameCounted = frameCounted;
}

bool VCMFrameBuffer::GetCountedFrame() const
{
    return _frameCounted;
}

// Get current state of frame
VCMFrameBufferStateEnum
VCMFrameBuffer::GetState() const
{
    return _state;
}

// Get current state of frame
VCMFrameBufferStateEnum
VCMFrameBuffer::GetState(WebRtc_UWord32& timeStamp) const
{
    timeStamp = TimeStamp();
    return GetState();
}

bool
VCMFrameBuffer::IsRetransmitted() const
{
    return _sessionInfo.session_nack();
}

void
VCMFrameBuffer::PrepareForDecode()
{
#ifdef INDEPENDENT_PARTITIONS
    if (_codec == kVideoCodecVP8)
    {
        _length =
            _sessionInfo.BuildVP8FragmentationHeader(_buffer, _length,
                                                     &_fragmentation);
    }
    else
    {
        _length = _sessionInfo.PrepareForDecode(_buffer);
    }
#else
    _length = _sessionInfo.PrepareForDecode(_buffer);
#endif
}

}
<commit_msg>Updating the frame buffer return value in InsertPacket: Return NoError when a packet is inserted to a frame which is being decoded.  Review URL: http://webrtc-codereview.appspot.com/330027<commit_after>/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "frame_buffer.h"
#include "packet.h"

#include <cassert>
#include <string.h>

#if defined(_WIN32)
    // VS 2005: Don't warn for default initialized arrays. See help for more info.
    #pragma warning(disable:4351)
#endif

namespace webrtc {

VCMFrameBuffer::VCMFrameBuffer()
  :
    _state(kStateFree),
    _frameCounted(false),
    _nackCount(0),
    _latestPacketTimeMs(-1) {
}

VCMFrameBuffer::~VCMFrameBuffer() {
}

VCMFrameBuffer::VCMFrameBuffer(VCMFrameBuffer& rhs)
:
VCMEncodedFrame(rhs),
_state(rhs._state),
_frameCounted(rhs._frameCounted),
_sessionInfo(),
_nackCount(rhs._nackCount),
_latestPacketTimeMs(rhs._latestPacketTimeMs)
{
    _sessionInfo = rhs._sessionInfo;
}

webrtc::FrameType
VCMFrameBuffer::FrameType() const
{
    return _sessionInfo.FrameType();
}

void
VCMFrameBuffer::SetPreviousFrameLoss()
{
    _sessionInfo.SetPreviousFrameLoss();
}

WebRtc_Word32
VCMFrameBuffer::GetLowSeqNum() const
{
    return _sessionInfo.LowSequenceNumber();
}

WebRtc_Word32
VCMFrameBuffer::GetHighSeqNum() const
{
    return _sessionInfo.HighSequenceNumber();
}

int VCMFrameBuffer::PictureId() const {
  return _sessionInfo.PictureId();
}

int VCMFrameBuffer::TemporalId() const {
  return _sessionInfo.TemporalId();
}

bool VCMFrameBuffer::LayerSync() const {
  return _sessionInfo.LayerSync();
}

int VCMFrameBuffer::Tl0PicId() const {
  return _sessionInfo.Tl0PicId();
}

bool VCMFrameBuffer::NonReference() const {
  return _sessionInfo.NonReference();
}

bool
VCMFrameBuffer::IsSessionComplete() const
{
    return _sessionInfo.complete();
}

// Insert packet
VCMFrameBufferEnum
VCMFrameBuffer::InsertPacket(const VCMPacket& packet, WebRtc_Word64 timeInMs,
                             bool enableDecodableState, WebRtc_UWord32 rttMS)
{
    if (_state == kStateDecoding)
    {
        // Do not insert packet
        return kNoError;
    }

    // Sanity to check if the frame has been freed. (Too old for example)
    if (_state == kStateFree)
    {
        return kStateError;
    }

    // is this packet part of this frame
    if (TimeStamp() && (TimeStamp() != packet.timestamp))
    {
        return kTimeStampError;
    }

    // sanity checks
    if (_size + packet.sizeBytes +
        (packet.insertStartCode ?  kH264StartCodeLengthBytes : 0 )
        > kMaxJBFrameSizeBytes)
    {
        return kSizeError;
    }
    if (NULL == packet.dataPtr && packet.sizeBytes > 0)
    {
        return kSizeError;
    }
    if (packet.dataPtr != NULL)
    {
        _payloadType = packet.payloadType;
    }

    if (kStateEmpty == _state)
    {
        // First packet (empty and/or media) inserted into this frame.
        // store some info and set some initial values.
        _timeStamp = packet.timestamp;
        _codec = packet.codec;
        if (packet.frameType != kFrameEmpty)
        {
            // first media packet
            SetState(kStateIncomplete);
        }
    }

    WebRtc_UWord32 requiredSizeBytes = Length() + packet.sizeBytes +
                   (packet.insertStartCode ? kH264StartCodeLengthBytes : 0);
    if (requiredSizeBytes >= _size)
    {
        const WebRtc_UWord8* prevBuffer = _buffer;
        const WebRtc_UWord32 increments = requiredSizeBytes /
                                          kBufferIncStepSizeBytes +
                                        (requiredSizeBytes %
                                         kBufferIncStepSizeBytes > 0);
        const WebRtc_UWord32 newSize = _size +
                                       increments * kBufferIncStepSizeBytes;
        if (newSize > kMaxJBFrameSizeBytes)
        {
            return kSizeError;
        }
        if (VerifyAndAllocate(newSize) == -1)
        {
            return kSizeError;
        }
        _sessionInfo.UpdateDataPointers(_buffer - prevBuffer);
    }

    CopyCodecSpecific(&packet.codecSpecificHeader);

    int retVal = _sessionInfo.InsertPacket(packet, _buffer,
                                           enableDecodableState,
                                           rttMS);
    if (retVal == -1)
    {
        return kSizeError;
    }
    else if (retVal == -2)
    {
        return kDuplicatePacket;
    }
    // update length
    _length = Length() + static_cast<WebRtc_UWord32>(retVal);

    _latestPacketTimeMs = timeInMs;

    if (_sessionInfo.complete()) {
      return kCompleteSession;
    } else if (_sessionInfo.decodable()) {
      SetState(kStateDecodable);
      return kDecodableSession;
    } else {
      // this layer is not complete
      if (_state == kStateComplete) {
        // we already have a complete layer
        // wait for all independent layers belonging to the same frame
        _state = kStateIncomplete;
      }
    }
    return kIncomplete;
}

WebRtc_Word64
VCMFrameBuffer::LatestPacketTimeMs()
{
    return _latestPacketTimeMs;
}

// Zero out all entries in list up to and including the (first)
// entry equal to _lowSeqNum
WebRtc_Word32
VCMFrameBuffer::ZeroOutSeqNum(WebRtc_Word32* list, WebRtc_Word32 num)
{
    if (_sessionInfo.ZeroOutSeqNum(list, num) != 0)
    {
       return -1;
    }
    return 0;
}

// Zero out all entries in list up to and including the (first) entry equal to
// _lowSeqNum. Hybrid mode: 1. Don't NACK FEC packets 2. Make a smart decision
// on whether to NACK or not

WebRtc_Word32
VCMFrameBuffer::ZeroOutSeqNumHybrid(WebRtc_Word32* list,
                                    WebRtc_Word32 num,
                                    WebRtc_UWord32 rttMs)
{
    return _sessionInfo.ZeroOutSeqNumHybrid(list, num, rttMs);
}

void
VCMFrameBuffer::IncrementNackCount()
{
    _nackCount++;
}

WebRtc_Word16
VCMFrameBuffer::GetNackCount() const
{
    return _nackCount;
}

bool
VCMFrameBuffer::HaveLastPacket() const
{
    return _sessionInfo.HaveLastPacket();
}

void
VCMFrameBuffer::Reset()
{
    _length = 0;
    _timeStamp = 0;
    _sessionInfo.Reset();
    _frameCounted = false;
    _payloadType = 0;
    _nackCount = 0;
    _latestPacketTimeMs = -1;
    _state = kStateFree;
    VCMEncodedFrame::Reset();
}

// Makes sure the session contains a decodable stream.
void
VCMFrameBuffer::MakeSessionDecodable()
{
    WebRtc_UWord32 retVal;
#ifdef INDEPENDENT_PARTITIONS
    if (_codec != kVideoCodecVP8) {
        retVal = _sessionInfo.MakeDecodable();
        _length -= retVal;
    }
#else
    retVal = _sessionInfo.MakeDecodable();
    _length -= retVal;
#endif
}

// Set state of frame
void
VCMFrameBuffer::SetState(VCMFrameBufferStateEnum state)
{
    if (_state == state)
    {
        return;
    }
    switch (state)
    {
    case kStateFree:
        // Reset everything
        // We can go to this state from all other states.
        // The one setting the state to free must ensure
        // that the frame is removed from the timestamp
        // ordered frame list in the jb.
        Reset();
        break;

    case kStateIncomplete:
        // we can go to this state from state kStateEmpty
        assert(_state == kStateEmpty ||
            _state == kStateDecoding);

        // Do nothing, we received a packet
        break;

    case kStateComplete:
        assert(_state == kStateEmpty ||
               _state == kStateIncomplete ||
               _state == kStateDecodable);

        break;

    case kStateEmpty:
        assert(_state == kStateFree);
        // Do nothing
        break;

    case kStateDecoding:
        // A frame might have received empty packets, or media packets might
        // have been removed when making the frame decodable. The frame can
        // still be set to decodable since it can be used to inform the
        // decoder of a frame loss.
        assert(_state == kStateComplete || _state == kStateIncomplete ||
               _state == kStateDecodable || _state == kStateEmpty);
        // Transfer frame information to EncodedFrame and create any codec
        // specific information
        RestructureFrameInformation();
        break;

    case kStateDecodable:
        assert(_state == kStateEmpty ||
               _state == kStateIncomplete);
        break;

    default:
        // Should never happen
        assert(!"FrameBuffer::SetState Incorrect frame buffer state as input");
        return;
    }
    _state = state;
}

void
VCMFrameBuffer::RestructureFrameInformation()
{
    PrepareForDecode();
    _frameType = ConvertFrameType(_sessionInfo.FrameType());
    _completeFrame = _sessionInfo.complete();
    _missingFrame = _sessionInfo.PreviousFrameLoss();
}

WebRtc_Word32
VCMFrameBuffer::ExtractFromStorage(const EncodedVideoData& frameFromStorage)
{
    _frameType = ConvertFrameType(frameFromStorage.frameType);
    _timeStamp = frameFromStorage.timeStamp;
    _payloadType = frameFromStorage.payloadType;
    _encodedWidth = frameFromStorage.encodedWidth;
    _encodedHeight = frameFromStorage.encodedHeight;
    _missingFrame = frameFromStorage.missingFrame;
    _completeFrame = frameFromStorage.completeFrame;
    _renderTimeMs = frameFromStorage.renderTimeMs;
    _codec = frameFromStorage.codec;
    const WebRtc_UWord8 *prevBuffer = _buffer;
    if (VerifyAndAllocate(frameFromStorage.payloadSize) < 0)
    {
        return VCM_MEMORY;
    }
    _sessionInfo.UpdateDataPointers(_buffer - prevBuffer);
    memcpy(_buffer, frameFromStorage.payloadData, frameFromStorage.payloadSize);
    _length = frameFromStorage.payloadSize;
    return VCM_OK;
}

int VCMFrameBuffer::NotDecodablePackets() const {
  return _sessionInfo.packets_not_decodable();
}

// Set counted status (as counted by JB or not)
void VCMFrameBuffer::SetCountedFrame(bool frameCounted)
{
    _frameCounted = frameCounted;
}

bool VCMFrameBuffer::GetCountedFrame() const
{
    return _frameCounted;
}

// Get current state of frame
VCMFrameBufferStateEnum
VCMFrameBuffer::GetState() const
{
    return _state;
}

// Get current state of frame
VCMFrameBufferStateEnum
VCMFrameBuffer::GetState(WebRtc_UWord32& timeStamp) const
{
    timeStamp = TimeStamp();
    return GetState();
}

bool
VCMFrameBuffer::IsRetransmitted() const
{
    return _sessionInfo.session_nack();
}

void
VCMFrameBuffer::PrepareForDecode()
{
#ifdef INDEPENDENT_PARTITIONS
    if (_codec == kVideoCodecVP8)
    {
        _length =
            _sessionInfo.BuildVP8FragmentationHeader(_buffer, _length,
                                                     &_fragmentation);
    }
    else
    {
        _length = _sessionInfo.PrepareForDecode(_buffer);
    }
#else
    _length = _sessionInfo.PrepareForDecode(_buffer);
#endif
}

}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS warnings01 (1.4.10); FILE MERGED 2005/11/10 17:15:23 pl 1.4.10.1: #i55991# removed warnings<commit_after><|endoftext|>


<commit_before>#pragma once

//
//ҪṩSCreateInstanceӿڡӿڶfunSCreateInstance
class SComLoader
{
    typedef BOOL (*funSCreateInstance)(IObjRef **);
public:
    SComLoader():m_hMod(0),m_funCreateInst(NULL){}
    ~SComLoader()
    {
        if(m_hMod) FreeLibrary(m_hMod);
    }

    BOOL CreateInstance(LPCTSTR pszDllPath,IObjRef **ppObj,LPCSTR pszFnName = "SCreateInstance")
    {
        if(!m_funCreateInst)
        {
            m_hMod=LoadLibrary(pszDllPath);
            if(!m_hMod) return FALSE;
            m_funCreateInst=(funSCreateInstance)GetProcAddress(m_hMod,pszFnName);
            if(!m_funCreateInst)
            {
                FreeLibrary(m_hMod);
                return FALSE;
            }
        }
        return m_funCreateInst(ppObj);
    }
protected:
    HMODULE m_hMod;
    funSCreateInstance m_funCreateInst;
};<commit_msg><commit_after>#pragma once

//
//ҪṩSCreateInstanceӿڡӿڶfunSCreateInstance
class SComLoader
{
    typedef BOOL (*funSCreateInstance)(IObjRef **);
public:
    SComLoader()
    :m_hMod(0)
    ,m_funCreateInst(NULL)
    {
        m_szDllPath[0]=0;
    }
    ~SComLoader()
    {
        if(m_hMod) FreeLibrary(m_hMod);
    }

    BOOL CreateInstance(LPCTSTR pszDllPath,IObjRef **ppObj,LPCSTR pszFnName = "SCreateInstance")
    {
        if(!m_funCreateInst)
        {
            m_hMod=LoadLibrary(pszDllPath);
            if(!m_hMod) return FALSE;
            m_funCreateInst=(funSCreateInstance)GetProcAddress(m_hMod,pszFnName);
            if(!m_funCreateInst)
            {
                FreeLibrary(m_hMod);
                return FALSE;
            }
            _tcscpy(m_szDllPath,pszDllPath);
        }
        return m_funCreateInst(ppObj);
    }
protected:
    HMODULE m_hMod;
    funSCreateInstance m_funCreateInst;
    TCHAR   m_szDllPath[MAX_PATH];
};<|endoftext|>


<commit_before>// -*- c++ -*- ///////////////////////////////////////////////////////////////
//
// This file is part of Miro (The Middleware for Robots)
// Copyright (C) 1999-2013
// Department of Neural Information Processing, University of Ulm
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// This program 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 program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#define QT_ALTERNATE_QTSMANIP

#include "ConfigFile.h"

#include "params/Parser.h"
#include "params/Generator.h"
#include "params/TextErrorHandler.h"

#include <qfile.h>
#include <qdom.h>
#include <qxml.h>
#include <qmessagebox.h>
#include <QTextStream>

Miro::Singleton<ConfigFileName> ConfigFileName::instance;
Miro::Singleton<ConfigFile> ConfigFile::instance;

ConfigFileName::ConfigFileName() :
  fileName_(".MiroConfigFile.xml")
{}

ConfigFile::ConfigFile() :
  generator_(NULL),
  handler_(NULL)
{
  char const * const home = getenv("HOME");
  configFile_ = QString(home) + "/" + ConfigFileName::instance()->fileName();

  readConfigFile();
}

ConfigFile::~ConfigFile()
{
  delete generator_;
  delete handler_;
}

void
ConfigFile::setDescriptionFiles(const QStringList& _descriptions)
{
  descriptionFiles_ = _descriptions;

  writeConfigFile();
}

/**
 *if no BehaviourDescriptionFile was loaded (i.e. behaviourFile=="") then
 *the function reads the path of the BehaviourDescriptionFile, which is used last, out of the Config-XML-File.
 *else it only returns the Name of the loaded BehaviourDescriptionFile (i. e. behaviourFile);
 */
void
ConfigFile::readConfigFile()
{
  descriptionFiles_.clear();

  // try to open policy editor config file
  QFile file(configFile_);
  if (file.open(QIODevice::ReadOnly)) {
    QDomDocument doc("MiroConfigDocument");
    if (doc.setContent(&file)) {

      QDomNode n = doc.documentElement().firstChild();
      while (!n.isNull()) {
	QDomElement e = n.toElement();
	if (e.tagName() == "config_item" &&
	    e.attribute("name") == "files") {

	  QDomNode node = n.firstChild();
	  while (!node.isNull()) {
	    e = node.toElement();
	    if (e.tagName() == "parameter" &&
		e.attribute("name") == "file") {
	      //add behaviour description file to list
	      descriptionFiles_.append(node.toElement().attribute("value"));
	    }
	    node = node.nextSibling();
	  }
	}
	n = n.nextSibling();
      }
    }
    else {
      QString infoText("Error parsing configuration file\n" +
		       configFile_ +
		       "\nStarting with empty configuration.");
      QMessageBox::information(0, "Policy Editor", infoText);
    }
    file.close();
  }
  else {
    QString infoText("Error opening configuration file\n" +
		     configFile_ +
		     "\nStarting with empty configuration.");
    QMessageBox::information(0, "Policy Editor", infoText);
    // create a minimal config file for the next run
    writeConfigFile();
  }

  parseDescriptionFiles();
}

void
ConfigFile::writeConfigFile()
{
  parseDescriptionFiles();

  QDomDocument doc( "MiroConfigDocument" );
  QDomElement root = doc.createElement( "Configuration" );
  doc.appendChild( root );

  QDomElement tag = doc.createElement( "config_item" );
  tag.setAttribute("name", "files");
  root.appendChild(tag);
  for (int i = 0; i < descriptionFiles_.count(); ++i) {
    QDomElement f = doc.createElement( "parameter" );
    f.setAttribute("name", "file");
    f.setAttribute("value", descriptionFiles_[i]);
    tag.appendChild(f);
  }

  QFile f(configFile_);
  if (!f.open(QIODevice::WriteOnly)) {
    throw QString("PolicyConfig::writeConfigFile: Error: file error!");
  }
  QTextStream ts(&f);
  doc.save(ts, 0);
}

void
ConfigFile::parseDescriptionFiles()
{
  bool okay = false;
  while (!okay) {
    delete generator_;
    generator_ = new Miro::CFG::Generator;
    delete handler_;
    handler_ = new Miro::CFG::Parser(*generator_);

    QStringList::Iterator first, last = descriptionFiles_.end();
    for (first = descriptionFiles_.begin(); first != last ; ++first) {

      // kill previous namespace nesting
      generator_->clearNamespace();

      QString fileName = *first;
      QFile xmlFile( fileName );
      if (!xmlFile.exists()) {
      QString infoText("Error parsing behaviour description file: \n" +
		       fileName + "\n" +
		       "File not found.");
      QMessageBox::information(0, "Policy Editor", infoText);
      descriptionFiles_.remove(first);
      break;
      }
      QXmlInputSource source( xmlFile );
      QXmlSimpleReader reader;
      Miro::CFG::TextErrorHandler errorHandler;

      reader.setContentHandler( handler_ );
      reader.setErrorHandler( &errorHandler);

      if (!reader.parse( source )) {
	QString infoText("Error parsing behaviour description file:\n" +
			 fileName + "\n" +
			 errorHandler.errorString());
	QMessageBox::information(0, "Policy Editor", infoText);
	descriptionFiles_.remove(first);
	break;
      }
    }
    // parsing successfull
    okay = true;

    //    cout << "parsing complete. known types: " << endl;
    //    cout << *generator_ << endl;
  }
}
<commit_msg>If a Parameter Description File in the load list is not in the file system, query the user for permission to remove it from the load list<commit_after>// -*- c++ -*- ///////////////////////////////////////////////////////////////
//
// This file is part of Miro (The Middleware for Robots)
// Copyright (C) 1999-2013
// Department of Neural Information Processing, University of Ulm
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2, or (at your option)
// any later version.
//
// This program 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 program; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
#define QT_ALTERNATE_QTSMANIP

#include "ConfigFile.h"

#include "params/Parser.h"
#include "params/Generator.h"
#include "params/TextErrorHandler.h"

#include <qfile.h>
#include <qdom.h>
#include <qxml.h>
#include <qmessagebox.h>
#include <QTextStream>

Miro::Singleton<ConfigFileName> ConfigFileName::instance;
Miro::Singleton<ConfigFile> ConfigFile::instance;

ConfigFileName::ConfigFileName() :
  fileName_(".MiroConfigFile.xml")
{}

ConfigFile::ConfigFile() :
  generator_(NULL),
  handler_(NULL)
{
  char const * const home = getenv("HOME");
  configFile_ = QString(home) + "/" + ConfigFileName::instance()->fileName();

  readConfigFile();
}

ConfigFile::~ConfigFile()
{
  delete generator_;
  delete handler_;
}

void
ConfigFile::setDescriptionFiles(const QStringList& _descriptions)
{
  descriptionFiles_ = _descriptions;

  writeConfigFile();
}

/**
 *if no BehaviourDescriptionFile was loaded (i.e. behaviourFile=="") then
 *the function reads the path of the BehaviourDescriptionFile, which is used last, out of the Config-XML-File.
 *else it only returns the Name of the loaded BehaviourDescriptionFile (i. e. behaviourFile);
 */
void
ConfigFile::readConfigFile()
{
  descriptionFiles_.clear();

  // try to open policy editor config file
  QFile file(configFile_);
  if (file.open(QIODevice::ReadOnly)) {
    QDomDocument doc("MiroConfigDocument");
    if (doc.setContent(&file)) {

      QDomNode n = doc.documentElement().firstChild();
      while (!n.isNull()) {
	QDomElement e = n.toElement();
	if (e.tagName() == "config_item" &&
	    e.attribute("name") == "files") {

	  QDomNode node = n.firstChild();
	  while (!node.isNull()) {
	    e = node.toElement();
	    if (e.tagName() == "parameter" &&
		e.attribute("name") == "file") {
	      //add behaviour description file to list
	      descriptionFiles_.append(node.toElement().attribute("value"));
	    }
	    node = node.nextSibling();
	  }
	}
	n = n.nextSibling();
      }
    }
    else {
      QString infoText("Error parsing configuration file\n" +
		       configFile_ +
		       "\nStarting with empty configuration.");
      QMessageBox::information(0, "Policy Editor", infoText);
    }
    file.close();
  }
  else {
    QString infoText("Error opening configuration file\n" +
		     configFile_ +
		     "\nStarting with empty configuration.");
    QMessageBox::information(0, "Policy Editor", infoText);
    // create a minimal config file for the next run
    writeConfigFile();
  }

  parseDescriptionFiles();
}

void
ConfigFile::writeConfigFile()
{
  parseDescriptionFiles();

  QDomDocument doc( "MiroConfigDocument" );
  QDomElement root = doc.createElement( "Configuration" );
  doc.appendChild( root );

  QDomElement tag = doc.createElement( "config_item" );
  tag.setAttribute("name", "files");
  root.appendChild(tag);
  for (int i = 0; i < descriptionFiles_.count(); ++i) {
    QDomElement f = doc.createElement( "parameter" );
    f.setAttribute("name", "file");
    f.setAttribute("value", descriptionFiles_[i]);
    tag.appendChild(f);
  }

  QFile f(configFile_);
  if (!f.open(QIODevice::WriteOnly)) {
    throw QString("PolicyConfig::writeConfigFile: Error: file error!");
  }
  QTextStream ts(&f);
  doc.save(ts, 0);
}

void
ConfigFile::parseDescriptionFiles()
{
  bool okay = false;
  while (!okay) {
    delete generator_;
    generator_ = new Miro::CFG::Generator;
    delete handler_;
    handler_ = new Miro::CFG::Parser(*generator_);

    QStringList::Iterator first, last = descriptionFiles_.end();
    for (first = descriptionFiles_.begin(); first != last ; ++first) {

      // kill previous namespace nesting
      generator_->clearNamespace();

      QString fileName = *first;
      QFile xmlFile( fileName );
      if (!xmlFile.exists()) {
	// Always remove the pathname of the nonexistent file.
	// Do this unconditionally before calling writeConfigFile() and
	// before break;
	descriptionFiles_.remove(first);
	// For why this QMessageBox is built in this way, see
	// http://qt-project.org/doc/qt-4.8/qmessagebox.html#the-property-based-api
	// where it says: "Using the property-based API is recommended."
	QMessageBox msgBox;
	msgBox.setText("Parameter Description File not found:\n" +
		       fileName + "\n");
	msgBox.setInformativeText("Do you want to remove this file from the list?");
	msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
	msgBox.setDefaultButton(QMessageBox::No);
	const int ret = msgBox.exec();
	if (ret == QMessageBox::Yes)
	{
	  writeConfigFile();
	}
	break;
      }
      QXmlInputSource source( xmlFile );
      QXmlSimpleReader reader;
      Miro::CFG::TextErrorHandler errorHandler;

      reader.setContentHandler( handler_ );
      reader.setErrorHandler( &errorHandler);

      if (!reader.parse( source )) {
	QString infoText("Error parsing behaviour description file:\n" +
			 fileName + "\n" +
			 errorHandler.errorString());
	QMessageBox::information(0, "Policy Editor", infoText);
	descriptionFiles_.remove(first);
	break;
      }
    }
    // parsing successfull
    okay = true;

    //    cout << "parsing complete. known types: " << endl;
    //    cout << *generator_ << endl;
  }
}
<|endoftext|>


<commit_before>//===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/X86FixupKinds.h"
#include "MCTargetDesc/X86MCTargetDesc.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"

using namespace llvm;

namespace {
  class X86ELFObjectWriter : public MCELFObjectTargetWriter {
  public:
    X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);

    ~X86ELFObjectWriter() override;

  protected:
    unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                          const MCFixup &Fixup, bool IsPCRel) const override;
  };
}

X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
                                       uint16_t EMachine)
    : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
                              // Only i386 and IAMCU use Rel instead of RelA.
                              /*HasRelocationAddend*/
                              (EMachine != ELF::EM_386) &&
                                  (EMachine != ELF::EM_IAMCU)) {}

X86ELFObjectWriter::~X86ELFObjectWriter()
{}

enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };

static X86_64RelType getType64(unsigned Kind,
                               MCSymbolRefExpr::VariantKind &Modifier,
                               bool &IsPCRel) {
  switch (Kind) {
  default:
    llvm_unreachable("Unimplemented");
  case X86::reloc_global_offset_table8:
    Modifier = MCSymbolRefExpr::VK_GOT;
    IsPCRel = true;
    return RT64_64;
  case FK_Data_8:
    return RT64_64;
  case X86::reloc_signed_4byte:
    if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
      return RT64_32S;
    return RT64_32;
  case X86::reloc_global_offset_table:
    Modifier = MCSymbolRefExpr::VK_GOT;
    IsPCRel = true;
    return RT64_32;
  case FK_Data_4:
  case FK_PCRel_4:
  case X86::reloc_riprel_4byte:
  case X86::reloc_riprel_4byte_movq_load:
    return RT64_32;
  case FK_PCRel_2:
  case FK_Data_2:
    return RT64_16;
  case FK_PCRel_1:
  case FK_Data_1:
    return RT64_8;
  }
}

static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
  if (Type != RT64_32)
    Ctx.reportError(Loc,
                    "32 bit reloc applied to a field with a different size");
}

static unsigned getRelocType64(MCContext &Ctx, SMLoc Loc,
                               MCSymbolRefExpr::VariantKind Modifier,
                               X86_64RelType Type, bool IsPCRel) {
  switch (Modifier) {
  default:
    llvm_unreachable("Unimplemented");
  case MCSymbolRefExpr::VK_None:
    switch (Type) {
    case RT64_64:
      return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
    case RT64_32:
      return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
    case RT64_32S:
      return ELF::R_X86_64_32S;
    case RT64_16:
      return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
    case RT64_8:
      return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
    }
  case MCSymbolRefExpr::VK_GOT:
    switch (Type) {
    case RT64_64:
      return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
    case RT64_32:
      return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_GOTOFF:
    assert(Type == RT64_64);
    assert(!IsPCRel);
    return ELF::R_X86_64_GOTOFF64;
  case MCSymbolRefExpr::VK_TPOFF:
    assert(!IsPCRel);
    switch (Type) {
    case RT64_64:
      return ELF::R_X86_64_TPOFF64;
    case RT64_32:
      return ELF::R_X86_64_TPOFF32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_DTPOFF:
    assert(!IsPCRel);
    switch (Type) {
    case RT64_64:
      return ELF::R_X86_64_DTPOFF64;
    case RT64_32:
      return ELF::R_X86_64_DTPOFF32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_SIZE:
    assert(!IsPCRel);
    switch (Type) {
    case RT64_64:
      return ELF::R_X86_64_SIZE64;
    case RT64_32:
      return ELF::R_X86_64_SIZE32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_TLSCALL:
    return ELF::R_X86_64_TLSDESC_CALL;
  case MCSymbolRefExpr::VK_TLSDESC:
    return ELF::R_X86_64_GOTPC32_TLSDESC;
  case MCSymbolRefExpr::VK_TLSGD:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_TLSGD;
  case MCSymbolRefExpr::VK_GOTTPOFF:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_GOTTPOFF;
  case MCSymbolRefExpr::VK_TLSLD:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_TLSLD;
  case MCSymbolRefExpr::VK_PLT:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_PLT32;
  case MCSymbolRefExpr::VK_GOTPCREL:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_GOTPCREL;
  }
}

enum X86_32RelType { RT32_32, RT32_16, RT32_8 };

static X86_32RelType getType32(X86_64RelType T) {
  switch (T) {
  case RT64_64:
    llvm_unreachable("Unimplemented");
  case RT64_32:
  case RT64_32S:
    return RT32_32;
  case RT64_16:
    return RT32_16;
  case RT64_8:
    return RT32_8;
  }
  llvm_unreachable("unexpected relocation type!");
}

static unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier,
                               X86_32RelType Type, bool IsPCRel) {
  switch (Modifier) {
  default:
    llvm_unreachable("Unimplemented");
  case MCSymbolRefExpr::VK_None:
    switch (Type) {
    case RT32_32:
      return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
    case RT32_16:
      return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
    case RT32_8:
      return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
    }
  case MCSymbolRefExpr::VK_GOT:
    assert(Type == RT32_32);
    return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32;
  case MCSymbolRefExpr::VK_GOTOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_GOTOFF;
  case MCSymbolRefExpr::VK_TPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LE_32;
  case MCSymbolRefExpr::VK_DTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LDO_32;
  case MCSymbolRefExpr::VK_TLSGD:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_GD;
  case MCSymbolRefExpr::VK_GOTTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_IE_32;
  case MCSymbolRefExpr::VK_PLT:
    assert(Type == RT32_32);
    return ELF::R_386_PLT32;
  case MCSymbolRefExpr::VK_INDNTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_IE;
  case MCSymbolRefExpr::VK_NTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LE;
  case MCSymbolRefExpr::VK_GOTNTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_GOTIE;
  case MCSymbolRefExpr::VK_TLSLDM:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LDM;
  }
}

unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
                                          const MCFixup &Fixup,
                                          bool IsPCRel) const {
  MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
  X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel);
  if (getEMachine() == ELF::EM_X86_64)
    return getRelocType64(Ctx, Fixup.getLoc(), Modifier, Type, IsPCRel);

  assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
         "Unsupported ELF machine type.");
  return getRelocType32(Modifier, getType32(Type), IsPCRel);
}

MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS,
                                               bool IsELF64, uint8_t OSABI,
                                               uint16_t EMachine) {
  MCELFObjectTargetWriter *MOTW =
    new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
  return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
}
<commit_msg>[MC/ELF] Pass Fixup to getRelocType64.<commit_after>//===-- X86ELFObjectWriter.cpp - X86 ELF Writer ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MCTargetDesc/X86FixupKinds.h"
#include "MCTargetDesc/X86MCTargetDesc.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/ErrorHandling.h"

using namespace llvm;

namespace {
  class X86ELFObjectWriter : public MCELFObjectTargetWriter {
  public:
    X86ELFObjectWriter(bool IsELF64, uint8_t OSABI, uint16_t EMachine);

    ~X86ELFObjectWriter() override;

  protected:
    unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
                          const MCFixup &Fixup, bool IsPCRel) const override;
  };
}

X86ELFObjectWriter::X86ELFObjectWriter(bool IsELF64, uint8_t OSABI,
                                       uint16_t EMachine)
    : MCELFObjectTargetWriter(IsELF64, OSABI, EMachine,
                              // Only i386 and IAMCU use Rel instead of RelA.
                              /*HasRelocationAddend*/
                              (EMachine != ELF::EM_386) &&
                                  (EMachine != ELF::EM_IAMCU)) {}

X86ELFObjectWriter::~X86ELFObjectWriter()
{}

enum X86_64RelType { RT64_64, RT64_32, RT64_32S, RT64_16, RT64_8 };

static X86_64RelType getType64(unsigned Kind,
                               MCSymbolRefExpr::VariantKind &Modifier,
                               bool &IsPCRel) {
  switch (Kind) {
  default:
    llvm_unreachable("Unimplemented");
  case X86::reloc_global_offset_table8:
    Modifier = MCSymbolRefExpr::VK_GOT;
    IsPCRel = true;
    return RT64_64;
  case FK_Data_8:
    return RT64_64;
  case X86::reloc_signed_4byte:
    if (Modifier == MCSymbolRefExpr::VK_None && !IsPCRel)
      return RT64_32S;
    return RT64_32;
  case X86::reloc_global_offset_table:
    Modifier = MCSymbolRefExpr::VK_GOT;
    IsPCRel = true;
    return RT64_32;
  case FK_Data_4:
  case FK_PCRel_4:
  case X86::reloc_riprel_4byte:
  case X86::reloc_riprel_4byte_movq_load:
    return RT64_32;
  case FK_PCRel_2:
  case FK_Data_2:
    return RT64_16;
  case FK_PCRel_1:
  case FK_Data_1:
    return RT64_8;
  }
}

static void checkIs32(MCContext &Ctx, SMLoc Loc, X86_64RelType Type) {
  if (Type != RT64_32)
    Ctx.reportError(Loc,
                    "32 bit reloc applied to a field with a different size");
}

static unsigned getRelocType64(MCContext &Ctx, const MCFixup &Fixup,
                               MCSymbolRefExpr::VariantKind Modifier,
                               X86_64RelType Type, bool IsPCRel) {
  SMLoc Loc = Fixup.getLoc();
  switch (Modifier) {
  default:
    llvm_unreachable("Unimplemented");
  case MCSymbolRefExpr::VK_None:
    switch (Type) {
    case RT64_64:
      return IsPCRel ? ELF::R_X86_64_PC64 : ELF::R_X86_64_64;
    case RT64_32:
      return IsPCRel ? ELF::R_X86_64_PC32 : ELF::R_X86_64_32;
    case RT64_32S:
      return ELF::R_X86_64_32S;
    case RT64_16:
      return IsPCRel ? ELF::R_X86_64_PC16 : ELF::R_X86_64_16;
    case RT64_8:
      return IsPCRel ? ELF::R_X86_64_PC8 : ELF::R_X86_64_8;
    }
  case MCSymbolRefExpr::VK_GOT:
    switch (Type) {
    case RT64_64:
      return IsPCRel ? ELF::R_X86_64_GOTPC64 : ELF::R_X86_64_GOT64;
    case RT64_32:
      return IsPCRel ? ELF::R_X86_64_GOTPC32 : ELF::R_X86_64_GOT32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_GOTOFF:
    assert(Type == RT64_64);
    assert(!IsPCRel);
    return ELF::R_X86_64_GOTOFF64;
  case MCSymbolRefExpr::VK_TPOFF:
    assert(!IsPCRel);
    switch (Type) {
    case RT64_64:
      return ELF::R_X86_64_TPOFF64;
    case RT64_32:
      return ELF::R_X86_64_TPOFF32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_DTPOFF:
    assert(!IsPCRel);
    switch (Type) {
    case RT64_64:
      return ELF::R_X86_64_DTPOFF64;
    case RT64_32:
      return ELF::R_X86_64_DTPOFF32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_SIZE:
    assert(!IsPCRel);
    switch (Type) {
    case RT64_64:
      return ELF::R_X86_64_SIZE64;
    case RT64_32:
      return ELF::R_X86_64_SIZE32;
    case RT64_32S:
    case RT64_16:
    case RT64_8:
      llvm_unreachable("Unimplemented");
    }
  case MCSymbolRefExpr::VK_TLSCALL:
    return ELF::R_X86_64_TLSDESC_CALL;
  case MCSymbolRefExpr::VK_TLSDESC:
    return ELF::R_X86_64_GOTPC32_TLSDESC;
  case MCSymbolRefExpr::VK_TLSGD:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_TLSGD;
  case MCSymbolRefExpr::VK_GOTTPOFF:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_GOTTPOFF;
  case MCSymbolRefExpr::VK_TLSLD:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_TLSLD;
  case MCSymbolRefExpr::VK_PLT:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_PLT32;
  case MCSymbolRefExpr::VK_GOTPCREL:
    checkIs32(Ctx, Loc, Type);
    return ELF::R_X86_64_GOTPCREL;
  }
}

enum X86_32RelType { RT32_32, RT32_16, RT32_8 };

static X86_32RelType getType32(X86_64RelType T) {
  switch (T) {
  case RT64_64:
    llvm_unreachable("Unimplemented");
  case RT64_32:
  case RT64_32S:
    return RT32_32;
  case RT64_16:
    return RT32_16;
  case RT64_8:
    return RT32_8;
  }
  llvm_unreachable("unexpected relocation type!");
}

static unsigned getRelocType32(MCSymbolRefExpr::VariantKind Modifier,
                               X86_32RelType Type, bool IsPCRel) {
  switch (Modifier) {
  default:
    llvm_unreachable("Unimplemented");
  case MCSymbolRefExpr::VK_None:
    switch (Type) {
    case RT32_32:
      return IsPCRel ? ELF::R_386_PC32 : ELF::R_386_32;
    case RT32_16:
      return IsPCRel ? ELF::R_386_PC16 : ELF::R_386_16;
    case RT32_8:
      return IsPCRel ? ELF::R_386_PC8 : ELF::R_386_8;
    }
  case MCSymbolRefExpr::VK_GOT:
    assert(Type == RT32_32);
    return IsPCRel ? ELF::R_386_GOTPC : ELF::R_386_GOT32;
  case MCSymbolRefExpr::VK_GOTOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_GOTOFF;
  case MCSymbolRefExpr::VK_TPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LE_32;
  case MCSymbolRefExpr::VK_DTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LDO_32;
  case MCSymbolRefExpr::VK_TLSGD:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_GD;
  case MCSymbolRefExpr::VK_GOTTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_IE_32;
  case MCSymbolRefExpr::VK_PLT:
    assert(Type == RT32_32);
    return ELF::R_386_PLT32;
  case MCSymbolRefExpr::VK_INDNTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_IE;
  case MCSymbolRefExpr::VK_NTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LE;
  case MCSymbolRefExpr::VK_GOTNTPOFF:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_GOTIE;
  case MCSymbolRefExpr::VK_TLSLDM:
    assert(Type == RT32_32);
    assert(!IsPCRel);
    return ELF::R_386_TLS_LDM;
  }
}

unsigned X86ELFObjectWriter::getRelocType(MCContext &Ctx, const MCValue &Target,
                                          const MCFixup &Fixup,
                                          bool IsPCRel) const {
  MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
  X86_64RelType Type = getType64(Fixup.getKind(), Modifier, IsPCRel);
  if (getEMachine() == ELF::EM_X86_64)
    return getRelocType64(Ctx, Fixup, Modifier, Type, IsPCRel);

  assert((getEMachine() == ELF::EM_386 || getEMachine() == ELF::EM_IAMCU) &&
         "Unsupported ELF machine type.");
  return getRelocType32(Modifier, getType32(Type), IsPCRel);
}

MCObjectWriter *llvm::createX86ELFObjectWriter(raw_pwrite_stream &OS,
                                               bool IsELF64, uint8_t OSABI,
                                               uint16_t EMachine) {
  MCELFObjectTargetWriter *MOTW =
    new X86ELFObjectWriter(IsELF64, OSABI, EMachine);
  return createELFObjectWriter(MOTW, OS,  /*IsLittleEndian=*/true);
}
<|endoftext|>