<commit_before>/*!
** \file Request.cpp
** \date Wed May 7 2008
** \author Steve Sloan <steve@finagle.org>
** Copyright (C) 2008 by Steve Sloan
**
** This library 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.1 of the License, or
** (at your option) any later version.
**
** This library is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, you may access it via the web
** at http://www.gnu.org/copyleft/lesser.html .
*/

#include <string>
#include <curl/curl.h>

#include "Transfer.h"
#include "Request.h"

#include <iostream>

using namespace std;
using namespace Finagle;
using namespace Transfer;

inline void CURL_ASSERT( CURLcode res )
{
  if ( res != 0 )
    throw Transfer::Exception( curl_easy_strerror( res ) );
}

/*!
** \class Finagle::Transfer::Request
** \brief A single cURL request.
**
**
*/

Request::Request( URL const &url )
: _url( url ), _req( curl_easy_init() ), _reqAdded( false ), _res( 0 ), _firstFrag( true )
{
  if ( !_req )
    throw Transfer::Exception( "Unable to create cURL easy instance" );

  CURL_ASSERT( curl_easy_setopt( _req, CURLOPT_URL, ((string const &) _url).c_str() ) );

  CURL_ASSERT( curl_easy_setopt( _req, CURLOPT_WRITEFUNCTION,  onBodyFrag ) );
  CURL_ASSERT( curl_easy_setopt( _req, CURLOPT_WRITEDATA, (void *) this ) );
}

Request::~Request( void )
{
  if ( !_req )  return;
  if ( _reqAdded )  Proc().remove( *this );
  curl_easy_cleanup( _req );
}

unsigned Request::result( void ) const
{
  if ( !_res ) {
    long code;
    CURL_ASSERT( curl_easy_getinfo( _req, CURLINFO_RESPONSE_CODE, &code ) );
    _res = (unsigned) code;
  }
  return _res;
}

void Request::perform( void )
{
  if ( !_req )  return;
  Proc().add( *this );
  _reqAdded = true;
}

size_t Request::onBodyFrag( const char *data, size_t membSize, size_t membNum, Request *reqPtr )
{
  size_t size = membSize * membNum;
  if ( !size )  return 0;

  Request::Ptr req( reqPtr );

  if ( req->_firstFrag ) {
    req->_firstFrag = false;

    if ( !req->recvBodyStart.empty() ) {
      char *type;
      double size;

      CURL_ASSERT( curl_easy_getinfo( req->_req, CURLINFO_CONTENT_TYPE, &type ) );
      CURL_ASSERT( curl_easy_getinfo( req->_req, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size ) );
      req->recvBodyStart( (String) type, (size_t) size );
    }
  }

  req->recvBodyFrag( data, size );
  return req->recvBodyFrag.empty() ? 0 : size;
}
<commit_msg>Net: fixed Request to handle unsized parts.<commit_after>/*!
** \file Request.cpp
** \date Wed May 7 2008
** \author Steve Sloan <steve@finagle.org>
** Copyright (C) 2008 by Steve Sloan
**
** This library 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.1 of the License, or
** (at your option) any later version.
**
** This library is distributed in the hope that it will be useful, but
** WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, you may access it via the web
** at http://www.gnu.org/copyleft/lesser.html .
*/

#include <string>
#include <curl/curl.h>

#include "Transfer.h"
#include "Request.h"

#include <iostream>

using namespace std;
using namespace Finagle;
using namespace Transfer;

inline void CURL_ASSERT( CURLcode res )
{
  if ( res != 0 )
    throw Transfer::Exception( curl_easy_strerror( res ) );
}

/*!
** \class Finagle::Transfer::Request
** \brief A single cURL request.
**
**
*/

Request::Request( URL const &url )
: _url( url ), _req( curl_easy_init() ), _reqAdded( false ), _res( 0 ), _firstFrag( true )
{
  if ( !_req )
    throw Transfer::Exception( "Unable to create cURL easy instance" );

  CURL_ASSERT( curl_easy_setopt( _req, CURLOPT_URL, ((string const &) _url).c_str() ) );

  CURL_ASSERT( curl_easy_setopt( _req, CURLOPT_WRITEFUNCTION,  onBodyFrag ) );
  CURL_ASSERT( curl_easy_setopt( _req, CURLOPT_WRITEDATA, (void *) this ) );
}

Request::~Request( void )
{
  if ( !_req )  return;
  if ( _reqAdded )  Proc().remove( *this );
  curl_easy_cleanup( _req );
}

unsigned Request::result( void ) const
{
  if ( !_res ) {
    long code;
    CURL_ASSERT( curl_easy_getinfo( _req, CURLINFO_RESPONSE_CODE, &code ) );
    _res = (unsigned) code;
  }
  return _res;
}

void Request::perform( void )
{
  if ( !_req )  return;
  Proc().add( *this );
  _reqAdded = true;
}

size_t Request::onBodyFrag( const char *data, size_t membSize, size_t membNum, Request *reqPtr )
{
  size_t size = membSize * membNum;
  if ( !size )  return 0;

  Request::Ptr req( reqPtr );

  if ( req->_firstFrag ) {
    req->_firstFrag = false;

    if ( !req->recvBodyStart.empty() ) {
      char *type;
      double size;

      CURL_ASSERT( curl_easy_getinfo( req->_req, CURLINFO_CONTENT_TYPE, &type ) );
      CURL_ASSERT( curl_easy_getinfo( req->_req, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size ) );
      if ( size < 0.0 )  size = 0;
      req->recvBodyStart( (String) type, (size_t) size );
    }
  }

  req->recvBodyFrag( data, size );
  return req->recvBodyFrag.empty() ? 0 : size;
}
<|endoftext|>


<commit_before>#include <Core/Types.hpp>
#include <Engine/Rendering/Renderer.hpp>
#include <Engine/Scene/Light.hpp>
#include <Gui/Utils/KeyMappingManager.hpp>
#include <Gui/Viewer/RotateAroundCameraManipulator.hpp>
#include <Gui/Viewer/Viewer.hpp>

namespace Ra {
namespace Gui {

using namespace Ra::Core::Utils;
using RotateAroundCameraMapping = KeyMappingManageable<RotateAroundCameraManipulator>;

#define KMA_VALUE( XX ) KeyMappingManager::KeyMappingAction RotateAroundCameraManipulator::XX;
KeyMappingRotateAroundCamera;
#undef KMA_VALUE

void RotateAroundCameraManipulator::configureKeyMapping_impl() {
    auto keyMappingManager = Gui::KeyMappingManager::getInstance();

    thisKeyMapping::setContext( KeyMappingManager::getInstance()->getContext( "CameraContext" ) );
    if ( thisKeyMapping::getContext().isInvalid() )
    {
        LOG( logINFO )
            << "CameraContext not defined (maybe the configuration file do not contains it)";
        LOG( logERROR ) << "CameraContext all keymapping invalide !";
        return;
    }

#define KMA_VALUE( XX ) XX = keyMappingManager->getActionIndex( thisKeyMapping::getContext(), #XX );
    KeyMappingRotateAroundCamera
#undef KMA_VALUE
}

void rotateAroundPoint( Ra::Core::Asset::Camera* cam,
                        Ra::Core::Vector3& target,
                        Ra::Core::Quaternion& rotation,
                        const Ra::Core::Vector3& point ) {
    Ra::Core::Vector3 t = cam->getPosition();
    Scalar l            = ( target - t ).norm();
    Ra::Core::Transform inverseCamRotateAround;
    Ra::Core::AngleAxis aa0 {rotation};
    Ra::Core::AngleAxis aa1 {aa0.angle(), ( cam->getFrame().linear() * aa0.axis() ).normalized()};
    inverseCamRotateAround.setIdentity();
    inverseCamRotateAround.rotate( aa1 );
    cam->applyTransform( inverseCamRotateAround );

    Ra::Core::Vector3 trans = point + inverseCamRotateAround * ( t - point );
    cam->setPosition( trans );
    target = cam->getPosition() + l * cam->getDirection();
    return;
}

RotateAroundCameraManipulator::RotateAroundCameraManipulator( const CameraManipulator& cm,
                                                              Ra::Gui::Viewer* viewer ) :
    TrackballCameraManipulator( cm ), m_viewer( viewer ) {}

bool RotateAroundCameraManipulator::handleMouseMoveEvent(
    QMouseEvent* event,
    const Qt::MouseButtons& /*buttons*/,
    const Qt::KeyboardModifiers& /* modifiers*/,
    int /*key*/ ) {

    Scalar dx = ( event->pos().x() - m_lastMouseX ) / m_camera->getWidth();
    Scalar dy = ( event->pos().y() - m_lastMouseY ) / m_camera->getHeight();

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

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

    if ( m_currentAction == TRACKBALLCAMERA_ROTATE )
    { handleCameraRotate( event->pos().x(), event->pos().y() ); }
    else if ( m_currentAction == TRACKBALLCAMERA_PAN )
        handleCameraPan( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_ZOOM )
        handleCameraZoom( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_MOVE_FORWARD )
        handleCameraMoveForward( dx, dy );
    //    { handleCameraForward( Ra::Core::Math::sign( dx ) * ( std::abs( dx ) + std::abs( dy ) ) );
    //    }

    m_prevMouseX = m_lastMouseX;
    m_prevMouseY = m_lastMouseY;

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    return m_currentAction.isValid();
}

bool RotateAroundCameraManipulator::handleKeyPressEvent(
    QKeyEvent* /*event*/,
    const Ra::Gui::KeyMappingManager::KeyMappingAction& action ) {

    if ( action == ROTATEAROUND_ALIGN_WITH_CLOSEST_AXIS )
    {
        alignOnClosestAxis();
        return true;
    }
    if ( action == ROTATEAROUND_SET_PIVOT )
    {
        setPivotFromPixel( m_lastMouseX, m_lastMouseY );
        return true;
    }

    return false;
}

void RotateAroundCameraManipulator::setPivot( Ra::Core::Vector3 pivot ) {
    m_pivot = pivot;
}

void RotateAroundCameraManipulator::setPivotFromPixel( Scalar x, Scalar y ) {
    m_viewer->makeCurrent();
    Scalar z = m_viewer->getRenderer()->getDepth( x, m_viewer->height() - y );
    setPivot( m_camera->unProjectFromScreen( Ra::Core::Vector3( x, y, z ) ) );
    m_viewer->doneCurrent();
}

void RotateAroundCameraManipulator::alignOnClosestAxis() {
    Ra::Core::Vector3 x( 1_ra, 0_ra, 0_ra );
    Ra::Core::Vector3 y( 0_ra, 1_ra, 0_ra );
    Ra::Core::Vector3 z( 0_ra, 0_ra, 1_ra );
    Ra::Core::Vector3 oldDirection, newDirection = m_camera->getDirection();
    Ra::Core::Vector3 newUpVector = m_camera->getUpVector();
    // getFrame().inverse() is a transform we can apply on Vector3
    Ra::Core::Vector3 pivotInCamSpace = m_camera->getFrame().inverse() * m_pivot;

    auto updateMaxAndAxis =
        []( Ra::Core::Vector3 ref, Ra::Core::Vector3 axis, Ra::Core::Vector3& out, Scalar& max ) {
            Scalar d = ref.dot( axis );
            if ( d > max )
            {
                max = d;
                out = axis;
            }
        };

    Scalar max            = 0_ra;
    Ra::Core::Vector3 ref = m_camera->getDirection();
    for ( auto axis : std::vector<Ra::Core::Vector3> {-x, x, -y, y, -z, z} )
    {
        updateMaxAndAxis( ref, axis, newDirection, max );
    }
    m_camera->setDirection( newDirection );

    max = 0_ra;
    ref = m_camera->getUpVector();
    for ( auto axis : std::vector<Ra::Core::Vector3> {-x, x, -y, y, -z, z} )
    {
        updateMaxAndAxis( ref, axis, newUpVector, max );
    }
    m_camera->setUpVector( newUpVector );

    Ra::Core::Vector3 newPivot = m_camera->getFrame() * pivotInCamSpace;
    Ra::Core::Vector3 trans    = m_pivot - newPivot;
    m_camera->setPosition( m_camera->getPosition() + trans );

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void RotateAroundCameraManipulator::handleCameraRotate( Scalar x, Scalar y ) {
    Ra::Core::Vector3 trans  = m_camera->projectToScreen( m_pivot );
    Ra::Core::Quaternion rot = deformedBallQuaternion( x, y, trans[0], trans[1] );
    Ra::Core::Vector3 pivot  = m_pivot;
    rotateAroundPoint( m_camera, m_target, rot, pivot );
}

Scalar RotateAroundCameraManipulator::projectOnBall( Scalar x, Scalar y ) {
    const Scalar size       = 1.0;
    const Scalar size2      = size * size;
    const Scalar size_limit = size2 * 0.5;

    const Scalar d = x * x + y * y;
    return d < size_limit ? sqrt( size2 - d ) : size_limit / sqrt( d );
}

Ra::Core::Quaternion
RotateAroundCameraManipulator::deformedBallQuaternion( Scalar x, Scalar y, Scalar cx, Scalar cy ) {
    // Points on the deformed ball
    Scalar px = m_cameraSensitivity * ( m_prevMouseX - cx ) / m_camera->getWidth();
    Scalar py = m_cameraSensitivity * ( cy - m_prevMouseY ) / m_camera->getHeight();
    Scalar dx = m_cameraSensitivity * ( x - cx ) / m_camera->getWidth();
    Scalar dy = m_cameraSensitivity * ( cy - y ) / m_camera->getHeight();

    const Ra::Core::Vector3 p1( px, py, projectOnBall( px, py ) );
    const Ra::Core::Vector3 p2( dx, dy, projectOnBall( dx, dy ) );
    // Approximation of rotation angle
    // Should be divided by the projectOnBall size, but it is 1.0
    Ra::Core::Vector3 axis = p2.cross( p1 );
    if ( axis.norm() > 10_ra * Ra::Core::Math::machineEps )
    {
        const Scalar angle =
            5.0 * asin( sqrt( axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm() ) );

        return Ra::Core::Quaternion( Ra::Core::AngleAxis( angle, axis.normalized() ) );
    }
    return Ra::Core::Quaternion {0_ra, 0_ra, 0_ra, 1_ra};
}

void RotateAroundCameraManipulator::handleCameraForward( Scalar z ) {
    Ra::Core::Vector3 trans = m_camera->getDirection() * z;
    Ra::Core::Transform transfo( Ra::Core::Transform::Identity() );
    transfo.translate( trans );

    m_camera->applyTransform( transfo );
}

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

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

    m_camera->applyTransform( T );
}

} // namespace Gui
} // namespace Ra
<commit_msg>[format][gui] fix StatementMacro indent.<commit_after>#include <Core/Types.hpp>
#include <Engine/Rendering/Renderer.hpp>
#include <Engine/Scene/Light.hpp>
#include <Gui/Utils/KeyMappingManager.hpp>
#include <Gui/Viewer/RotateAroundCameraManipulator.hpp>
#include <Gui/Viewer/Viewer.hpp>

namespace Ra {
namespace Gui {

using namespace Ra::Core::Utils;
using RotateAroundCameraMapping = KeyMappingManageable<RotateAroundCameraManipulator>;

#define KMA_VALUE( XX ) KeyMappingManager::KeyMappingAction RotateAroundCameraManipulator::XX;
KeyMappingRotateAroundCamera
#undef KMA_VALUE

void RotateAroundCameraManipulator::configureKeyMapping_impl() {
    auto keyMappingManager = Gui::KeyMappingManager::getInstance();

    thisKeyMapping::setContext( KeyMappingManager::getInstance()->getContext( "CameraContext" ) );
    if ( thisKeyMapping::getContext().isInvalid() )
    {
        LOG( logINFO )
            << "CameraContext not defined (maybe the configuration file do not contains it)";
        LOG( logERROR ) << "CameraContext all keymapping invalide !";
        return;
    }

#define KMA_VALUE( XX ) XX = keyMappingManager->getActionIndex( thisKeyMapping::getContext(), #XX );
    KeyMappingRotateAroundCamera
#undef KMA_VALUE
}

void rotateAroundPoint( Ra::Core::Asset::Camera* cam,
                        Ra::Core::Vector3& target,
                        Ra::Core::Quaternion& rotation,
                        const Ra::Core::Vector3& point ) {
    Ra::Core::Vector3 t = cam->getPosition();
    Scalar l            = ( target - t ).norm();
    Ra::Core::Transform inverseCamRotateAround;
    Ra::Core::AngleAxis aa0 {rotation};
    Ra::Core::AngleAxis aa1 {aa0.angle(), ( cam->getFrame().linear() * aa0.axis() ).normalized()};
    inverseCamRotateAround.setIdentity();
    inverseCamRotateAround.rotate( aa1 );
    cam->applyTransform( inverseCamRotateAround );

    Ra::Core::Vector3 trans = point + inverseCamRotateAround * ( t - point );
    cam->setPosition( trans );
    target = cam->getPosition() + l * cam->getDirection();
    return;
}

RotateAroundCameraManipulator::RotateAroundCameraManipulator( const CameraManipulator& cm,
                                                              Ra::Gui::Viewer* viewer ) :
    TrackballCameraManipulator( cm ), m_viewer( viewer ) {}

bool RotateAroundCameraManipulator::handleMouseMoveEvent(
    QMouseEvent* event,
    const Qt::MouseButtons& /*buttons*/,
    const Qt::KeyboardModifiers& /* modifiers*/,
    int /*key*/ ) {

    Scalar dx = ( event->pos().x() - m_lastMouseX ) / m_camera->getWidth();
    Scalar dy = ( event->pos().y() - m_lastMouseY ) / m_camera->getHeight();

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

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

    if ( m_currentAction == TRACKBALLCAMERA_ROTATE )
    { handleCameraRotate( event->pos().x(), event->pos().y() ); }
    else if ( m_currentAction == TRACKBALLCAMERA_PAN )
        handleCameraPan( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_ZOOM )
        handleCameraZoom( dx, dy );
    else if ( m_currentAction == TRACKBALLCAMERA_MOVE_FORWARD )
        handleCameraMoveForward( dx, dy );
    //    { handleCameraForward( Ra::Core::Math::sign( dx ) * ( std::abs( dx ) + std::abs( dy ) ) );
    //    }

    m_prevMouseX = m_lastMouseX;
    m_prevMouseY = m_lastMouseY;

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }

    return m_currentAction.isValid();
}

bool RotateAroundCameraManipulator::handleKeyPressEvent(
    QKeyEvent* /*event*/,
    const Ra::Gui::KeyMappingManager::KeyMappingAction& action ) {

    if ( action == ROTATEAROUND_ALIGN_WITH_CLOSEST_AXIS )
    {
        alignOnClosestAxis();
        return true;
    }
    if ( action == ROTATEAROUND_SET_PIVOT )
    {
        setPivotFromPixel( m_lastMouseX, m_lastMouseY );
        return true;
    }

    return false;
}

void RotateAroundCameraManipulator::setPivot( Ra::Core::Vector3 pivot ) {
    m_pivot = pivot;
}

void RotateAroundCameraManipulator::setPivotFromPixel( Scalar x, Scalar y ) {
    m_viewer->makeCurrent();
    Scalar z = m_viewer->getRenderer()->getDepth( x, m_viewer->height() - y );
    setPivot( m_camera->unProjectFromScreen( Ra::Core::Vector3( x, y, z ) ) );
    m_viewer->doneCurrent();
}

void RotateAroundCameraManipulator::alignOnClosestAxis() {
    Ra::Core::Vector3 x( 1_ra, 0_ra, 0_ra );
    Ra::Core::Vector3 y( 0_ra, 1_ra, 0_ra );
    Ra::Core::Vector3 z( 0_ra, 0_ra, 1_ra );
    Ra::Core::Vector3 oldDirection, newDirection = m_camera->getDirection();
    Ra::Core::Vector3 newUpVector = m_camera->getUpVector();
    // getFrame().inverse() is a transform we can apply on Vector3
    Ra::Core::Vector3 pivotInCamSpace = m_camera->getFrame().inverse() * m_pivot;

    auto updateMaxAndAxis =
        []( Ra::Core::Vector3 ref, Ra::Core::Vector3 axis, Ra::Core::Vector3& out, Scalar& max ) {
            Scalar d = ref.dot( axis );
            if ( d > max )
            {
                max = d;
                out = axis;
            }
        };

    Scalar max            = 0_ra;
    Ra::Core::Vector3 ref = m_camera->getDirection();
    for ( auto axis : std::vector<Ra::Core::Vector3> {-x, x, -y, y, -z, z} )
    {
        updateMaxAndAxis( ref, axis, newDirection, max );
    }
    m_camera->setDirection( newDirection );

    max = 0_ra;
    ref = m_camera->getUpVector();
    for ( auto axis : std::vector<Ra::Core::Vector3> {-x, x, -y, y, -z, z} )
    {
        updateMaxAndAxis( ref, axis, newUpVector, max );
    }
    m_camera->setUpVector( newUpVector );

    Ra::Core::Vector3 newPivot = m_camera->getFrame() * pivotInCamSpace;
    Ra::Core::Vector3 trans    = m_pivot - newPivot;
    m_camera->setPosition( m_camera->getPosition() + trans );

    if ( m_light != nullptr )
    {
        m_light->setPosition( m_camera->getPosition() );
        m_light->setDirection( m_camera->getDirection() );
    }
}

void RotateAroundCameraManipulator::handleCameraRotate( Scalar x, Scalar y ) {
    Ra::Core::Vector3 trans  = m_camera->projectToScreen( m_pivot );
    Ra::Core::Quaternion rot = deformedBallQuaternion( x, y, trans[0], trans[1] );
    Ra::Core::Vector3 pivot  = m_pivot;
    rotateAroundPoint( m_camera, m_target, rot, pivot );
}

Scalar RotateAroundCameraManipulator::projectOnBall( Scalar x, Scalar y ) {
    const Scalar size       = 1.0;
    const Scalar size2      = size * size;
    const Scalar size_limit = size2 * 0.5;

    const Scalar d = x * x + y * y;
    return d < size_limit ? sqrt( size2 - d ) : size_limit / sqrt( d );
}

Ra::Core::Quaternion
RotateAroundCameraManipulator::deformedBallQuaternion( Scalar x, Scalar y, Scalar cx, Scalar cy ) {
    // Points on the deformed ball
    Scalar px = m_cameraSensitivity * ( m_prevMouseX - cx ) / m_camera->getWidth();
    Scalar py = m_cameraSensitivity * ( cy - m_prevMouseY ) / m_camera->getHeight();
    Scalar dx = m_cameraSensitivity * ( x - cx ) / m_camera->getWidth();
    Scalar dy = m_cameraSensitivity * ( cy - y ) / m_camera->getHeight();

    const Ra::Core::Vector3 p1( px, py, projectOnBall( px, py ) );
    const Ra::Core::Vector3 p2( dx, dy, projectOnBall( dx, dy ) );
    // Approximation of rotation angle
    // Should be divided by the projectOnBall size, but it is 1.0
    Ra::Core::Vector3 axis = p2.cross( p1 );
    if ( axis.norm() > 10_ra * Ra::Core::Math::machineEps )
    {
        const Scalar angle =
            5.0 * asin( sqrt( axis.squaredNorm() / p1.squaredNorm() / p2.squaredNorm() ) );

        return Ra::Core::Quaternion( Ra::Core::AngleAxis( angle, axis.normalized() ) );
    }
    return Ra::Core::Quaternion {0_ra, 0_ra, 0_ra, 1_ra};
}

void RotateAroundCameraManipulator::handleCameraForward( Scalar z ) {
    Ra::Core::Vector3 trans = m_camera->getDirection() * z;
    Ra::Core::Transform transfo( Ra::Core::Transform::Identity() );
    transfo.translate( trans );

    m_camera->applyTransform( transfo );
}

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

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

    m_camera->applyTransform( T );
}

} // namespace Gui
} // namespace Ra
<|endoftext|>


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

#include "boost/python.hpp"
#include "boost/format.hpp"

#include "maya/MSyntax.h"
#include "maya/MArgParser.h"
#include "maya/MStringArray.h"
#include "maya/MFnDagNode.h"
#include "maya/MSelectionList.h"

#include "IECore/CompoundParameter.h"
#include "IECore/AttributeBlock.h"

#include "IECoreRI/Renderer.h"
#include "IECoreRI/Convert.h"

#include "IECoreMaya/DelightProceduralCacheCommand.h"
#include "IECoreMaya/ProceduralHolder.h"
#include "IECoreMaya/PythonCmd.h"
#include "IECoreMaya/Convert.h"

#include "ri.h"

#define STRINGIFY( ARG ) STRINGIFY2( ARG )
#define STRINGIFY2( ARG ) #ARG

using namespace boost::python;
using namespace IECoreMaya;

DelightProceduralCacheCommand::ProceduralMap DelightProceduralCacheCommand::g_procedurals;

DelightProceduralCacheCommand::DelightProceduralCacheCommand()
{
}

DelightProceduralCacheCommand::~DelightProceduralCacheCommand()
{
}

void *DelightProceduralCacheCommand::creator()
{
	return new DelightProceduralCacheCommand;
}

MSyntax DelightProceduralCacheCommand::newSyntax()
{
	MSyntax syn;
	MStatus s;

	s = syn.addFlag( "-a", "-addstep" );
	assert(s);

	s = syn.addFlag( "-e", "-emit" );
	assert(s);

	s = syn.addFlag( "-f", "-flush" );
	assert(s);

	s = syn.addFlag( "-r", "-remove" );
	assert(s);

	s = syn.addFlag( "-l", "-list" );
	assert(s);

	s = syn.addFlag( "-st", "-sampleTime", MSyntax::kDouble );
	assert(s);

	syn.setObjectType( MSyntax::kStringObjects );

	return syn;
}

MStatus DelightProceduralCacheCommand::doIt( const MArgList &args )
{
	MArgParser parser( syntax(), args );
	MStatus s;

	if( parser.isFlagSet( "-a" ) )
	{
		MStringArray objectNames;
		s = parser.getObjects( objectNames );
		if( !s || objectNames.length()!=1 )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get object name argument." );
			return s;
		}

		MSelectionList sel;
		sel.add( objectNames[0] );
		MObject oDepNode;
		s = sel.getDependNode( 0, oDepNode );
		if( !s )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get dependency node for \"" + objectNames[0] + "\"." );
			return s;
		}
		MFnDagNode fnDagNode( oDepNode );
		IECoreMaya::ProceduralHolder *pHolder = dynamic_cast<IECoreMaya::ProceduralHolder *>( fnDagNode.userNode() );
		if( !pHolder )
		{
			displayError( "DelightProceduralCacheCommand::doIt : \"" + objectNames[0] + "\" is not a procedural holder node." );
			return MStatus::kFailure;
		}

		ProceduralMap::iterator pIt = g_procedurals.find( objectNames[0].asChar() );
		if( pIt!=g_procedurals.end() )
		{
			// we already got the procedural on the first sample, but we should expand the bounding box for this sample
			pIt->second.bound.extendBy( IECore::convert<Imath::Box3f>( fnDagNode.boundingBox() ) );
			return MStatus::kSuccess;
		}
		else
		{
			pHolder->setParameterisedValues(); // we're relying on nothing setting different values between now and the time we emit the procedural

			CachedProcedural cachedProcedural;
			cachedProcedural.procedural = pHolder->getProcedural( &cachedProcedural.className, &cachedProcedural.classVersion );
			if( !cachedProcedural.procedural )
			{
				displayError( "DelightProceduralCacheCommand::doIt : failed to get procedural from \"" + objectNames[0] + "\"." );
				return MStatus::kFailure;
			}
			cachedProcedural.bound = IECore::convert<Imath::Box3f>( fnDagNode.boundingBox() );
			IECore::ObjectPtr values = cachedProcedural.procedural->parameters()->getValue();
			if( !values )
			{
				displayError( "DelightProceduralCacheCommand::doIt : failed to get parameter values from \"" + objectNames[0] + "\"." );
				return MStatus::kFailure;
			}
			cachedProcedural.values = values->copy();
			g_procedurals[objectNames[0].asChar()] = cachedProcedural;
		}

		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-l" ) )
	{
		MStringArray result;
		for( ProceduralMap::const_iterator it=g_procedurals.begin(); it!=g_procedurals.end(); it++ )
		{
			result.append( it->first.c_str() );
		}
		setResult( result );
		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-e" ) )
	{
		// get the object name
		MStringArray objectNames;
		s = parser.getObjects( objectNames );
		if( !s || objectNames.length()!=1 )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get object name argument." );
			return s;
		}

		// get the cached procedural
		ProceduralMap::const_iterator it = g_procedurals.find( objectNames[0].asChar() );
		if( it==g_procedurals.end() )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to emit \"" + objectNames[0] + "\" as object has not been cached." );
			return MS::kFailure;
		}

		// and output it
		try
		{
			IECore::ObjectPtr currentValues = it->second.procedural->parameters()->getValue();
			it->second.procedural->parameters()->setValue( it->second.values );

			std::string pythonString;
			try
			{
				// we first get an object referencing the serialise result and then make an extractor for it.
				// making the extractor directly from the return of the serialise call seems to result
				// in the python object dying before we properly extract the value, which results in corrupted
				// strings, and therefore malformed ribs.
				object serialisedResultObject = PythonCmd::globalContext()["IECore"].attr("ParameterParser")().attr("serialise")( it->second.procedural->parameters() );
				extract<std::string> serialisedResultExtractor( serialisedResultObject );

				std::string serialisedParameters = serialisedResultExtractor();
				pythonString = boost::str( boost::format( "IECoreRI.executeProcedural( \"%s\", %d, \"%s\" )" ) % it->second.className % it->second.classVersion % serialisedParameters );
			}
			catch( ... )
			{
				// Make sure we don't lose the 'current' values if we except.
				it->second.procedural->parameters()->setValue( currentValues );
				displayError( "DelightProceduralCacheCommand::doIt : could not get parameters from \"" + objectNames[0] + "\"." );
				return MStatus::kFailure;
			}

			// Put the current values back.
			it->second.procedural->parameters()->setValue( currentValues );

			if( it->second.bound.isEmpty() )
			{
				displayWarning( "DelightProceduralCacheCommand::doIt : not outputting procedural \"" + objectNames[0] + "\" because it has an empty bounding box." );
				return MS::kSuccess;
			}
			RtBound rtBound;
			IECore::convert( it->second.bound, rtBound );

			IECore::RendererPtr renderer = new IECoreRI::Renderer();
			IECore::AttributeBlock attributeBlock( renderer, 1 );

				it->second.procedural->render( renderer.get(), false, true, false, false );

				// tell 3delight we can't run multiple python procedurals concurrently
				int zero = 0;
				RiAttribute( "procedural", "integer reentrant", &zero, 0 );

				const char **data = (const char **)malloc( sizeof( char * ) * 2 );
				data[0] = STRINGIFY( IECORERI_RMANPROCEDURAL_NAME );
				data[1] = pythonString.c_str();
				RiProcedural( data, rtBound, RiProcDynamicLoad, RiProcFree );

		}
		catch( error_already_set )
		{
			PyErr_Print();
			displayError( "DelightProceduralCacheCommand::doIt : failed to output procedural for \"" + objectNames[0] + "\"." );
			return MStatus::kFailure;
		}
		catch( ... )
		{
			displayError( "DelightProceduralCacheCommand::doIt : failed to output procedural for \"" + objectNames[0] + "\"." );
			return MStatus::kFailure;
		}

		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-r" ) )
	{
		MStringArray objectNames;
		s = parser.getObjects( objectNames );
		if( !s || objectNames.length()!=1 )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get object name argument." );
			return s;
		}
		g_procedurals.erase( objectNames[0].asChar() );
		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-f" ) )
	{
		g_procedurals.clear();
		return MStatus::kSuccess;
	}

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

#include "boost/python.hpp"
#include "boost/format.hpp"

#include "maya/MSyntax.h"
#include "maya/MArgParser.h"
#include "maya/MStringArray.h"
#include "maya/MFnDagNode.h"
#include "maya/MSelectionList.h"

#include "IECore/CompoundParameter.h"
#include "IECore/AttributeBlock.h"

#include "IECoreRI/Renderer.h"
#include "IECoreRI/Convert.h"

#include "IECoreMaya/DelightProceduralCacheCommand.h"
#include "IECoreMaya/ProceduralHolder.h"
#include "IECoreMaya/PythonCmd.h"
#include "IECoreMaya/Convert.h"

#include "ri.h"

#define STRINGIFY( ARG ) STRINGIFY2( ARG )
#define STRINGIFY2( ARG ) #ARG

using namespace boost::python;
using namespace IECoreMaya;

DelightProceduralCacheCommand::ProceduralMap DelightProceduralCacheCommand::g_procedurals;

DelightProceduralCacheCommand::DelightProceduralCacheCommand()
{
}

DelightProceduralCacheCommand::~DelightProceduralCacheCommand()
{
}

void *DelightProceduralCacheCommand::creator()
{
	return new DelightProceduralCacheCommand;
}

MSyntax DelightProceduralCacheCommand::newSyntax()
{
	MSyntax syn;
	MStatus s;

	s = syn.addFlag( "-a", "-addstep" );
	assert(s);

	s = syn.addFlag( "-e", "-emit" );
	assert(s);

	s = syn.addFlag( "-f", "-flush" );
	assert(s);

	s = syn.addFlag( "-r", "-remove" );
	assert(s);

	s = syn.addFlag( "-l", "-list" );
	assert(s);

	s = syn.addFlag( "-st", "-sampleTime", MSyntax::kDouble );
	assert(s);

	syn.setObjectType( MSyntax::kStringObjects );

	return syn;
}

MStatus DelightProceduralCacheCommand::doIt( const MArgList &args )
{
	MArgParser parser( syntax(), args );
	MStatus s;

	if( parser.isFlagSet( "-a" ) )
	{
		MStringArray objectNames;
		s = parser.getObjects( objectNames );
		if( !s || objectNames.length()!=1 )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get object name argument." );
			return s;
		}

		MSelectionList sel;
		sel.add( objectNames[0] );
		MObject oDepNode;
		s = sel.getDependNode( 0, oDepNode );
		if( !s )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get dependency node for \"" + objectNames[0] + "\"." );
			return s;
		}
		MFnDagNode fnDagNode( oDepNode );
		IECoreMaya::ProceduralHolder *pHolder = dynamic_cast<IECoreMaya::ProceduralHolder *>( fnDagNode.userNode() );
		if( !pHolder )
		{
			displayError( "DelightProceduralCacheCommand::doIt : \"" + objectNames[0] + "\" is not a procedural holder node." );
			return MStatus::kFailure;
		}

		ProceduralMap::iterator pIt = g_procedurals.find( objectNames[0].asChar() );
		if( pIt!=g_procedurals.end() )
		{
			// we already got the procedural on the first sample, but we should expand the bounding box for this sample
			pIt->second.bound.extendBy( IECore::convert<Imath::Box3f>( fnDagNode.boundingBox() ) );
			return MStatus::kSuccess;
		}
		else
		{
			pHolder->setParameterisedValues();

			CachedProcedural cachedProcedural;
			cachedProcedural.procedural = pHolder->getProcedural( &cachedProcedural.className, &cachedProcedural.classVersion );
			if( !cachedProcedural.procedural )
			{
				displayError( "DelightProceduralCacheCommand::doIt : failed to get procedural from \"" + objectNames[0] + "\"." );
				return MStatus::kFailure;
			}
			cachedProcedural.bound = IECore::convert<Imath::Box3f>( fnDagNode.boundingBox() );
			IECore::ObjectPtr values = cachedProcedural.procedural->parameters()->getValue();
			if( !values )
			{
				displayError( "DelightProceduralCacheCommand::doIt : failed to get parameter values from \"" + objectNames[0] + "\"." );
				return MStatus::kFailure;
			}
			cachedProcedural.values = values->copy();
			g_procedurals[objectNames[0].asChar()] = cachedProcedural;
		}

		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-l" ) )
	{
		MStringArray result;
		for( ProceduralMap::const_iterator it=g_procedurals.begin(); it!=g_procedurals.end(); it++ )
		{
			result.append( it->first.c_str() );
		}
		setResult( result );
		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-e" ) )
	{
		// get the object name
		MStringArray objectNames;
		s = parser.getObjects( objectNames );
		if( !s || objectNames.length()!=1 )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get object name argument." );
			return s;
		}

		// get the cached procedural
		ProceduralMap::const_iterator it = g_procedurals.find( objectNames[0].asChar() );
		if( it==g_procedurals.end() )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to emit \"" + objectNames[0] + "\" as object has not been cached." );
			return MS::kFailure;
		}

		// and output it
		try
		{
			IECore::ObjectPtr currentValues = it->second.procedural->parameters()->getValue();
			it->second.procedural->parameters()->setValue( it->second.values );

			std::string pythonString;
			try
			{
				// we first get an object referencing the serialise result and then make an extractor for it.
				// making the extractor directly from the return of the serialise call seems to result
				// in the python object dying before we properly extract the value, which results in corrupted
				// strings, and therefore malformed ribs.
				object serialisedResultObject = PythonCmd::globalContext()["IECore"].attr("ParameterParser")().attr("serialise")( it->second.procedural->parameters() );
				extract<std::string> serialisedResultExtractor( serialisedResultObject );

				std::string serialisedParameters = serialisedResultExtractor();
				pythonString = boost::str( boost::format( "IECoreRI.executeProcedural( \"%s\", %d, \"%s\" )" ) % it->second.className % it->second.classVersion % serialisedParameters );
			}
			catch( ... )
			{
				// Make sure we don't lose the 'current' values if we except.
				it->second.procedural->parameters()->setValue( currentValues );
				displayError( "DelightProceduralCacheCommand::doIt : could not get parameters from \"" + objectNames[0] + "\"." );
				return MStatus::kFailure;
			}

			// Put the current values back.
			it->second.procedural->parameters()->setValue( currentValues );

			if( it->second.bound.isEmpty() )
			{
				displayWarning( "DelightProceduralCacheCommand::doIt : not outputting procedural \"" + objectNames[0] + "\" because it has an empty bounding box." );
				return MS::kSuccess;
			}
			RtBound rtBound;
			IECore::convert( it->second.bound, rtBound );

			IECore::RendererPtr renderer = new IECoreRI::Renderer();
			IECore::AttributeBlock attributeBlock( renderer, 1 );

				it->second.procedural->render( renderer.get(), false, true, false, false );

				// tell 3delight we can't run multiple python procedurals concurrently
				int zero = 0;
				RiAttribute( "procedural", "integer reentrant", &zero, 0 );

				const char **data = (const char **)malloc( sizeof( char * ) * 2 );
				data[0] = STRINGIFY( IECORERI_RMANPROCEDURAL_NAME );
				data[1] = pythonString.c_str();
				RiProcedural( data, rtBound, RiProcDynamicLoad, RiProcFree );

		}
		catch( error_already_set )
		{
			PyErr_Print();
			displayError( "DelightProceduralCacheCommand::doIt : failed to output procedural for \"" + objectNames[0] + "\"." );
			return MStatus::kFailure;
		}
		catch( ... )
		{
			displayError( "DelightProceduralCacheCommand::doIt : failed to output procedural for \"" + objectNames[0] + "\"." );
			return MStatus::kFailure;
		}

		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-r" ) )
	{
		MStringArray objectNames;
		s = parser.getObjects( objectNames );
		if( !s || objectNames.length()!=1 )
		{
			displayError( "DelightProceduralCacheCommand::doIt : unable to get object name argument." );
			return s;
		}
		g_procedurals.erase( objectNames[0].asChar() );
		return MStatus::kSuccess;
	}
	else if( parser.isFlagSet( "-f" ) )
	{
		g_procedurals.clear();
		return MStatus::kSuccess;
	}

	displayError( "DelightProceduralCacheCommand::doIt : No suitable flag specified." );
	return MS::kFailure;
}
<|endoftext|>


<commit_before>/**@file
	@brief Elements for Mobility Management messages, GSM 04.08 9.2.
*/
/*
* Copyright 2008, 2014 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

    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.

*/

#include <time.h>
#include "GSML3MMElements.h"
#include <Logger.h>

using namespace std;
using namespace GSM;

void L3TimeZoneAndTime::writeV(L3Frame& dest, size_t& wp) const
{
	// See GSM 03.40 9.2.3.11.

	// Convert from seconds since Jan 1, 1970 to calendar time.
	struct tm fields;
	const time_t seconds = mTime.sec();
	if (mType == LOCAL_TIME) {
		localtime_r(&seconds,&fields);
	} else {
		gmtime_r(&seconds,&fields);
	}
	// Write the fields in BCD format.
	// year
	unsigned year = fields.tm_year % 100;
	dest.writeField(wp, year % 10, 4);
	dest.writeField(wp, year / 10, 4);
	// month
	unsigned month = fields.tm_mon + 1;
	dest.writeField(wp, month % 10, 4);
	dest.writeField(wp, month / 10, 4);
	// day
	dest.writeField(wp, fields.tm_mday % 10, 4);
	dest.writeField(wp, fields.tm_mday / 10, 4);
	// hour
	dest.writeField(wp, fields.tm_hour % 10, 4);
	dest.writeField(wp, fields.tm_hour / 10, 4);
	// minute
	dest.writeField(wp, fields.tm_min % 10, 4);
	dest.writeField(wp, fields.tm_min / 10, 4);
	// second
	dest.writeField(wp, fields.tm_sec % 10, 4);
	dest.writeField(wp, fields.tm_sec / 10, 4);

	// time zone, in 1/4 steps with a sign bit
	int zone;
	if (mType == LOCAL_TIME) {
		zone = fields.tm_gmtoff;
	} else {
		// At least under Linux gmtime_r() does not return timezone
		// information for some reason and we have to use localtime_r()
		// to reptrieve this information.
		struct tm fields_local;
		localtime_r(&seconds,&fields_local);
		zone = fields_local.tm_gmtoff;
	}
	zone = zone / (15*60);
	unsigned zoneSign = (zone < 0);
	zone = abs(zone);
	dest.writeField(wp, zone % 10, 4);
	dest.writeField(wp, zoneSign, 1);
	dest.writeField(wp, zone / 10, 3);

	LOG(DEBUG) << "year=" << year << " month=" << month << " day=" << fields.tm_mday
	           << " hour=" << fields.tm_hour << " min=" << fields.tm_min << " sec=" << fields.tm_sec
	           << " zone=" << (zoneSign?"-":"+") << zone;
}

void L3TimeZoneAndTime::parseV(const L3Frame& src, size_t& rp)
{
	// See GSM 03.40 9.2.3.11.

	// Read it all into a localtime struct tm,
	// then covert to Unix seconds.
	struct tm fields;
	// year
	fields.tm_year = 2000 + src.readField(rp,4) + src.readField(rp,4)*10;
	// month
	fields.tm_mon = 1 + src.readField(rp,4) + src.readField(rp,4)*10;
	// day
	fields.tm_mday = src.readField(rp,4) + src.readField(rp,4)*10;
	// hour
	fields.tm_hour = src.readField(rp,4) + src.readField(rp,4)*10;
	// minute
	fields.tm_min = src.readField(rp,4) + src.readField(rp,4)*10;
	// second
	fields.tm_sec = src.readField(rp,4) + src.readField(rp,4)*10;
	// zone
	unsigned zone = src.readField(rp,4);
	unsigned zoneSign = src.readField(rp,1);
	zone += 10*src.readField(rp,4);
	if (zoneSign) zone = -zone;
	fields.tm_gmtoff = zone * 15 * 60;
	// convert
	mTime = Timeval(timegm(&fields),0);
}

void L3TimeZoneAndTime::text(ostream& os) const
{
	//char timeStr[26];
	const time_t seconds = mTime.sec();
        std::string timeStr;
        Timeval::isoTime(seconds, timeStr, true);
	//ctime_r(&seconds,timeStr);
	//timeStr[24]='\0';
	os << timeStr << " (local)";
}

// vim: ts=4 sw=4
<commit_msg>fixes issue loading some 0-length SMS. Turns out that we were taking one extra bit off of the time field of the message incorrectly. Also resolved some time conversion issues in the same funcion.<commit_after>/**@file
	@brief Elements for Mobility Management messages, GSM 04.08 9.2.
*/
/*
* Copyright 2008, 2014 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribuion.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

    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.

*/

#include <time.h>
#include "GSML3MMElements.h"
#include <Logger.h>

using namespace std;
using namespace GSM;

void L3TimeZoneAndTime::writeV(L3Frame& dest, size_t& wp) const
{
	// See GSM 03.40 9.2.3.11.

	// Convert from seconds since Jan 1, 1970 to calendar time.
	struct tm fields;
	const time_t seconds = mTime.sec();
	if (mType == LOCAL_TIME) {
		localtime_r(&seconds,&fields);
	} else {
		gmtime_r(&seconds,&fields);
	}
	// Write the fields in BCD format.
	// year
	unsigned year = fields.tm_year % 100;
	dest.writeField(wp, year % 10, 4);
	dest.writeField(wp, year / 10, 4);
	// month
	unsigned month = fields.tm_mon + 1;
	dest.writeField(wp, month % 10, 4);
	dest.writeField(wp, month / 10, 4);
	// day
	dest.writeField(wp, fields.tm_mday % 10, 4);
	dest.writeField(wp, fields.tm_mday / 10, 4);
	// hour
	dest.writeField(wp, fields.tm_hour % 10, 4);
	dest.writeField(wp, fields.tm_hour / 10, 4);
	// minute
	dest.writeField(wp, fields.tm_min % 10, 4);
	dest.writeField(wp, fields.tm_min / 10, 4);
	// second
	dest.writeField(wp, fields.tm_sec % 10, 4);
	dest.writeField(wp, fields.tm_sec / 10, 4);

	// time zone, in 1/4 steps with a sign bit
	int zone;
	if (mType == LOCAL_TIME) {
		zone = fields.tm_gmtoff;
	} else {
		// At least under Linux gmtime_r() does not return timezone
		// information for some reason and we have to use localtime_r()
		// to reptrieve this information.
		struct tm fields_local;
		localtime_r(&seconds,&fields_local);
		zone = fields_local.tm_gmtoff;
	}
	zone = zone / (15*60);
	unsigned zoneSign = (zone < 0);
	zone = abs(zone);
	dest.writeField(wp, zone % 10, 4);
	dest.writeField(wp, zoneSign, 1);
	dest.writeField(wp, zone / 10, 3);

	LOG(DEBUG) << "year=" << year << " month=" << month << " day=" << fields.tm_mday
	           << " hour=" << fields.tm_hour << " min=" << fields.tm_min << " sec=" << fields.tm_sec
	           << " zone=" << (zoneSign?"-":"+") << zone;
}

void L3TimeZoneAndTime::parseV(const L3Frame& src, size_t& rp)
{
	// See GSM 03.40 9.2.3.11.

	// Read it all into a localtime struct tm,
	// then covert to Unix seconds.
	struct tm fields;
	// years since 1900
	fields.tm_year = 100 + src.readField(rp,4) + src.readField(rp,4)*10;
	// month
	fields.tm_mon = src.readField(rp,4) + src.readField(rp,4)*10;
	// day
	fields.tm_mday = src.readField(rp,4) + src.readField(rp,4)*10;
	// hour
	fields.tm_hour = src.readField(rp,4) + src.readField(rp,4)*10;
	// minute
	fields.tm_min = src.readField(rp,4) + src.readField(rp,4)*10;
	// second
	fields.tm_sec = src.readField(rp,4) + src.readField(rp,4)*10;
	// zone
	unsigned zone = src.readField(rp,4);
	unsigned zoneSign = src.readField(rp,1);
	zone += 10*src.readField(rp,3);
	if (zoneSign) zone = -zone;
	fields.tm_gmtoff = zone * 15 * 60;
	// convert
	mTime = Timeval(timegm(&fields),0);
}

void L3TimeZoneAndTime::text(ostream& os) const
{
	//char timeStr[26];
	const time_t seconds = mTime.sec();
        std::string timeStr;
        Timeval::isoTime(seconds, timeStr, true);
	//ctime_r(&seconds,timeStr);
	//timeStr[24]='\0';
	os << timeStr << " (local)";
}

// vim: ts=4 sw=4
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "cartrige.h"

struct rom_header
{
	u8 start_vector[4];
	u8 nintendo_logo[48];
	u8 game_title[11];
	u8 manufacturer_code[4];
	u8 cgb_flag;
	u8 new_license_code[2];
	u8 sgb_flag;
	u8 cartrige_type;
	u8 rom_size;
	u8 ram_size;
	u8 destination_code;
	u8 old_license_code;
	u8 rom_version;
	u8 checksum;
	u8 global_checksum[2];
};

bool in_range(u32 value, u32 begin, u32 end)
{
	return (value >= begin) && (value <= end);
}

u32 get_ram_size(u8 val)
{
	assert(val < 6);

	static const u32 sizes[] = { 0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000 };

	return sizes[val];
}

Cartrige::~Cartrige()
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	if (battery_ram)
		save_ram_callback(ram.get(), ram_size);

	if (in_range(header->cartrige_type, 0x0F, 0x10))
	{
		memory_interface.reset(); //make sure that MBC3 update rtc_regs

		auto epoch = std::chrono::system_clock::now().time_since_epoch();
		auto cur_timestamp = std::chrono::duration_cast<std::chrono::seconds>(epoch);

		save_rtc_callback(cur_timestamp, rtc_regs, 5);
	}
}

bool Cartrige::load_cartrige(std::ifstream& cart, std::ifstream& ram, std::ifstream& rtc)
{
	if (!cart.is_open())
		return false;

	cart.seekg(0, std::ios_base::end);
	size_t size = cart.tellg();
	cart.seekg(0, std::ios_base::beg);

	rom = std::make_unique<u8[]>(size);
	cart.read(reinterpret_cast<char*>(rom.get()), size);

	load_or_create_ram(ram);
	load_rtc(rtc);

	dispatch();

	return true;
}

std::string Cartrige::get_name() const
{
    const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);
    return std::string(std::begin(header->game_title), std::end(header->game_title));
}

void Cartrige::attach_endpoints(function<void(const u8*, u32)> ram_save, function<void(std::chrono::seconds, const u8*, u32)> rtc_save)
{
	save_ram_callback = ram_save;
	save_rtc_callback = rtc_save;
}

void Cartrige::load_or_create_ram(std::ifstream& ram_file)
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	//MBC2 has always header->ram_size == 0, but it has 512 bytes actually!
	if (in_range(header->cartrige_type, 0x05, 0x06))
		ram_size = 512;

	else
		ram_size = get_ram_size(header->ram_size);

	ram = ram_size ? std::make_unique<u8[]>(ram_size) : nullptr;

	switch (header->cartrige_type)
	{
		case 0x03:
		case 0x06:
		case 0x09:
		case 0x0D:
		case 0x0F:
		case 0x10:
		case 0x13:
		case 0x1B:
		case 0x1E:
			battery_ram = true;
			break;

		default:
			battery_ram = false;
			break;
	}

	if (battery_ram && ram_file.is_open())
		ram_file.read(reinterpret_cast<char*>(ram.get()), ram_size);
}

void Cartrige::load_rtc(std::ifstream& rtc_file)
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	if (in_range(header->cartrige_type, 0x0F, 0x10) && rtc_file.is_open())
	{
		i64 saved_timestamp;
		rtc_file >> saved_timestamp;
		rtc_file.read(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);

		auto epoch = std::chrono::system_clock::now().time_since_epoch();
		auto cur_timestamp = std::chrono::duration_cast<std::chrono::seconds>(epoch);
		auto delta = cur_timestamp.count() - saved_timestamp;

		if (delta <= 0 || check_bit(rtc_regs[4], 6))
			return;

		auto ns = rtc_regs[0] + delta;
		auto nm = rtc_regs[1] + ns / 60;
		auto nh = rtc_regs[2] + nm / 60;
		auto nd = (((rtc_regs[4] & 1) << 8) | rtc_regs[3]) + nh / 24;

		rtc_regs[0] = ns % 60;
		rtc_regs[1] = nm % 60;
		rtc_regs[2] = nh % 24;
		rtc_regs[3] = (nd % 512) & 0xFF;
		rtc_regs[4] = change_bit(rtc_regs[4], (nd % 512) > 255, 0);
		rtc_regs[4] = change_bit(rtc_regs[4], nd > 511, 7);
	}
}

IMemory* Cartrige::get_memory_controller() const
{
	return memory_interface.get();
}

IDmaMemory* Cartrige::get_dma_controller() const
{
	return dma_interface;
}

bool Cartrige::is_cgb_ready() const
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	return (header->cgb_flag == 0x80) || (header->cgb_flag == 0xC0);
}

void Cartrige::serialize(std::ostream& stream)
{
	//TODO: update rtc regs before serialization
	stream << battery_ram << ram_size;
	stream.write(reinterpret_cast<char*>(ram.get()), sizeof(u8) * ram_size);
	stream.write(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);
}

void Cartrige::deserialize(std::istream & stream)
{
	stream >> battery_ram >> ram_size;
	stream.read(reinterpret_cast<char*>(ram.get()), sizeof(u8) * ram_size);
	stream.read(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);
}

void Cartrige::dispatch()
{
	rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);
	u8 type = header->cartrige_type;

	if (type == 0x00 || type == 0x08 || type == 0x09)
	{
		auto tmp = std::make_unique<NoMBC>(NoMBC(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x01, 0x03))
	{
		auto tmp = std::make_unique<MBC1>(MBC1(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x05, 0x06))
	{
		auto tmp = std::make_unique<MBC2>(MBC2(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x0F, 0x13))
	{
		auto tmp = std::make_unique<MBC3>(MBC3(rom.get(), ram.get(), (type <= 0x10 ? rtc_regs : nullptr)));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x1A, 0x1E))
	{
		auto tmp = std::make_unique<MBC5>(MBC5(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else
		memory_interface = nullptr;
}
<commit_msg>added new MBC5 code<commit_after>#include "stdafx.h"
#include "cartrige.h"

struct rom_header
{
	u8 start_vector[4];
	u8 nintendo_logo[48];
	u8 game_title[11];
	u8 manufacturer_code[4];
	u8 cgb_flag;
	u8 new_license_code[2];
	u8 sgb_flag;
	u8 cartrige_type;
	u8 rom_size;
	u8 ram_size;
	u8 destination_code;
	u8 old_license_code;
	u8 rom_version;
	u8 checksum;
	u8 global_checksum[2];
};

bool in_range(u32 value, u32 begin, u32 end)
{
	return (value >= begin) && (value <= end);
}

u32 get_ram_size(u8 val)
{
	assert(val < 6);

	static const u32 sizes[] = { 0, 0x800, 0x2000, 0x8000, 0x20000, 0x10000 };

	return sizes[val];
}

Cartrige::~Cartrige()
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	if (battery_ram)
		save_ram_callback(ram.get(), ram_size);

	if (in_range(header->cartrige_type, 0x0F, 0x10))
	{
		memory_interface.reset(); //make sure that MBC3 update rtc_regs

		auto epoch = std::chrono::system_clock::now().time_since_epoch();
		auto cur_timestamp = std::chrono::duration_cast<std::chrono::seconds>(epoch);

		save_rtc_callback(cur_timestamp, rtc_regs, 5);
	}
}

bool Cartrige::load_cartrige(std::ifstream& cart, std::ifstream& ram, std::ifstream& rtc)
{
	if (!cart.is_open())
		return false;

	cart.seekg(0, std::ios_base::end);
	size_t size = cart.tellg();
	cart.seekg(0, std::ios_base::beg);

	rom = std::make_unique<u8[]>(size);
	cart.read(reinterpret_cast<char*>(rom.get()), size);

	load_or_create_ram(ram);
	load_rtc(rtc);

	dispatch();

	return true;
}

std::string Cartrige::get_name() const
{
    const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);
    return std::string(std::begin(header->game_title), std::end(header->game_title));
}

void Cartrige::attach_endpoints(function<void(const u8*, u32)> ram_save, function<void(std::chrono::seconds, const u8*, u32)> rtc_save)
{
	save_ram_callback = ram_save;
	save_rtc_callback = rtc_save;
}

void Cartrige::load_or_create_ram(std::ifstream& ram_file)
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	//MBC2 has always header->ram_size == 0, but it has 512 bytes actually!
	if (in_range(header->cartrige_type, 0x05, 0x06))
		ram_size = 512;

	else
		ram_size = get_ram_size(header->ram_size);

	ram = ram_size ? std::make_unique<u8[]>(ram_size) : nullptr;

	switch (header->cartrige_type)
	{
		case 0x03:
		case 0x06:
		case 0x09:
		case 0x0D:
		case 0x0F:
		case 0x10:
		case 0x13:
		case 0x1B:
		case 0x1E:
			battery_ram = true;
			break;

		default:
			battery_ram = false;
			break;
	}

	if (battery_ram && ram_file.is_open())
		ram_file.read(reinterpret_cast<char*>(ram.get()), ram_size);
}

void Cartrige::load_rtc(std::ifstream& rtc_file)
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	if (in_range(header->cartrige_type, 0x0F, 0x10) && rtc_file.is_open())
	{
		i64 saved_timestamp;
		rtc_file >> saved_timestamp;
		rtc_file.read(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);

		auto epoch = std::chrono::system_clock::now().time_since_epoch();
		auto cur_timestamp = std::chrono::duration_cast<std::chrono::seconds>(epoch);
		auto delta = cur_timestamp.count() - saved_timestamp;

		if (delta <= 0 || check_bit(rtc_regs[4], 6))
			return;

		auto ns = rtc_regs[0] + delta;
		auto nm = rtc_regs[1] + ns / 60;
		auto nh = rtc_regs[2] + nm / 60;
		auto nd = (((rtc_regs[4] & 1) << 8) | rtc_regs[3]) + nh / 24;

		rtc_regs[0] = ns % 60;
		rtc_regs[1] = nm % 60;
		rtc_regs[2] = nh % 24;
		rtc_regs[3] = (nd % 512) & 0xFF;
		rtc_regs[4] = change_bit(rtc_regs[4], (nd % 512) > 255, 0);
		rtc_regs[4] = change_bit(rtc_regs[4], nd > 511, 7);
	}
}

IMemory* Cartrige::get_memory_controller() const
{
	return memory_interface.get();
}

IDmaMemory* Cartrige::get_dma_controller() const
{
	return dma_interface;
}

bool Cartrige::is_cgb_ready() const
{
	const rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);

	return (header->cgb_flag == 0x80) || (header->cgb_flag == 0xC0);
}

void Cartrige::serialize(std::ostream& stream)
{
	//TODO: update rtc regs before serialization
	stream << battery_ram << ram_size;
	stream.write(reinterpret_cast<char*>(ram.get()), sizeof(u8) * ram_size);
	stream.write(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);
}

void Cartrige::deserialize(std::istream & stream)
{
	stream >> battery_ram >> ram_size;
	stream.read(reinterpret_cast<char*>(ram.get()), sizeof(u8) * ram_size);
	stream.read(reinterpret_cast<char*>(rtc_regs), sizeof(u8) * 5);
}

void Cartrige::dispatch()
{
	rom_header* header = reinterpret_cast<rom_header*>(&rom[0x100]);
	u8 type = header->cartrige_type;

	if (type == 0x00 || type == 0x08 || type == 0x09)
	{
		auto tmp = std::make_unique<NoMBC>(NoMBC(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x01, 0x03))
	{
		auto tmp = std::make_unique<MBC1>(MBC1(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x05, 0x06))
	{
		auto tmp = std::make_unique<MBC2>(MBC2(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x0F, 0x13))
	{
		auto tmp = std::make_unique<MBC3>(MBC3(rom.get(), ram.get(), (type <= 0x10 ? rtc_regs : nullptr)));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else if (in_range(type, 0x19, 0x1E))
	{
		auto tmp = std::make_unique<MBC5>(MBC5(rom.get(), ram.get()));
		dma_interface = tmp.get();
		memory_interface = std::move(tmp);
	}

	else
		memory_interface = nullptr;
}
<|endoftext|>


<commit_before>/**
 * lambdak.tcc -
 * @author: Jonathan Beard
 * @version: Thu Oct 30 10:12:36 2014
 *
 * Copyright 2014 Jonathan Beard
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _LAMBDAK_TCC_
#define _LAMBDAK_TCC_  1
#include <functional>
#include <utility>
#include <typeinfo>
#include <raft>

namespace raft
{
/** TODO, this needs some more error checking before production **/

/** pre-declare recursive struct / functions **/
template < class... PORTSL > struct AddPorts;
template < class... PORTSK > struct AddSamePorts;

template < class... PORTS >
   class lambdak : public raft::kernel
{
public:
   typedef std::function< raft::kstatus ( Port &input,
                                          Port &output ) > lambdafunc_t;
   lambdak( const std::size_t inputs,
            const std::size_t outputs,
            lambdafunc_t  func ) :   raft::kernel(),
                                     run_func( func )
   {
      add_ports< PORTS... >( inputs, outputs );
   }

   //lambdak( const std::size_t inputs,
   //         const std::size_t outputs,
   //         const lambdafunc_t  &&func ) : raft::kernel(),
   //                                        run_func( func )
   //{
   //   add_ports< PORTS... >( inputs, outputs );
   //}

   virtual raft::kstatus run()
   {
      return( run_func( input  /** input ports **/,
                        output /** output ports **/) );
   }

private:
   /** lambda func passed by user **/
   lambdafunc_t  run_func;

   /** function **/
   template < class... PORTSM >
      void add_ports( const std::size_t input_max,
                      const std::size_t output_max )
   {
      const auto num_types( sizeof... (PORTSM) );
      if( num_types == 1 )
      {
         /** everybody gets same type, add here **/
         AddSamePorts< PORTSM... >::add( input_max     /* count */,
                                         input         /* in-port obj */,
                                         output_max    /* count */,
                                         output        /* out-port obj */ );
      }
      /** no idea what type each port is, throw error **/
      else if( num_types != (input_max + output_max ) )
      {
         /** TODO, make exception for here **/
         assert( false );
      }
      /** multiple port type case **/
      std::size_t input_index(  0 );
      std::size_t output_index( 0 );
      AddPorts< PORTSM... >::add( input_index,
                                  input_max,
                                  input /* ports */,
                                  output_index,
                                  output_max,
                                  output /* ports */);
   }

}; /** end template lambdak **/

/** class recursion **/
template < class PORT, class... PORTSL > struct AddPorts< PORT, PORTSL...>
{
   static void add( std::size_t &input_index,
                    const std::size_t input_max,
                    Port &input_ports,
                    std::size_t &output_index,
                    const std::size_t output_max,
                    Port &output_ports )
   {
      if( input_index < input_max )
      {
         /** add ports in order, 0,1,2, etc. **/
         input_ports.addPort< PORT >( std::to_string( input_index++ ) );
         AddPorts< PORTSL... >::add( input_index,
                                     input_max,
                                     input_ports,
                                     output_index,
                                     output_max,
                                     output_ports );
      }
      else if( output_index < output_max )
      {
         /** add ports in order, 0, 1, 2, etc. **/
         output_ports.addPort< PORT >( std::to_string( output_index++ ) );
         AddPorts< PORTSL... >::add( input_index,
                                     input_max,
                                     input_ports,
                                     output_index,
                                     output_max,
                                     output_ports );
      }
      else
      {
         /**
          * I think it'll be okay here simply to return, however
          * we might need the blank specialization below
          */
      }
      return;
   }
};

template <> struct AddPorts<>
{
   static void add( std::size_t &input_index,
                    const std::size_t input_max,
                    Port &input_ports,
                    std::size_t &output_index,
                    const std::size_t output_max,
                    Port &output_ports )
   {
      return;
   }
};

/** single class type, no recursion **/
template < class PORT, class... PORTSK > struct AddSamePorts< PORT, PORTSK... >
{
   /** no recursion needed here **/
   static void add( const std::size_t input_count, Port &inputs,
                    const std::size_t output_count, Port &outputs )
   {
      for( auto it( 0 ); it < input_count; it++ )
      {
         inputs.addPort< PORT >( std::to_string( it ) );
      }
      for( auto it( 0 ); it < output_count; it++ )
      {
         outputs.addPort< PORT >( std::to_string( it ) );
      }
   }
};

template <> struct AddSamePorts<>
{
   static void add( const std::size_t input_count, Port &inputs,
                    const std::size_t output_count, Port &outputs )
   { return; }
};

} /* end namespace raft */
#endif /* END _LAMBDAK_TCC_ */
<commit_msg>updates<commit_after>/**
 * lambdak.tcc -
 * @author: Jonathan Beard
 * @version: Thu Oct 30 10:12:36 2014
 *
 * Copyright 2014 Jonathan Beard
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef _LAMBDAK_TCC_
#define _LAMBDAK_TCC_  1
#include <functional>
#include <utility>
#include <typeinfo>
#include <raft>

namespace raft
{
/** TODO, this needs some more error checking before production **/

/** pre-declare recursive struct / functions **/
template < class... PORTSL > struct AddPorts;
template < class... PORTSK > struct AddSamePorts;

template < class... PORTS >
   class lambdak : public raft::kernel
{
public:
   typedef std::function< raft::kstatus ( Port &input,
                                          Port &output ) > lambdafunc_t;
   /**
    * constructor -
    * @param   inputs - const std::size_t number of inputs to the kernel
    * @param   outputs - const std::size_t number of outputs to the kernel
    * @param   func - static or lambda function to execute.
    */
   lambdak( const std::size_t inputs,
            const std::size_t outputs,
            lambdafunc_t  func ) :   raft::kernel(),
                                     run_func( func )
   {
      add_ports< PORTS... >( inputs, outputs );
   }

   /**
    * run - implement the run function for this kernel,
    */
   virtual raft::kstatus run()
   {
      return( run_func( input  /** input ports **/,
                        output /** output ports **/) );
   }

private:
   /** lambda func passed by user **/
   lambdafunc_t  run_func;

   /** function **/
   template < class... PORTSM >
      void add_ports( const std::size_t input_max,
                      const std::size_t output_max )
   {
      const auto num_types( sizeof... (PORTSM) );
      if( num_types == 1 )
      {
         /** everybody gets same type, add here **/
         AddSamePorts< PORTSM... >::add( input_max     /* count */,
                                         input         /* in-port obj */,
                                         output_max    /* count */,
                                         output        /* out-port obj */ );
      }
      /** no idea what type each port is, throw error **/
      else if( num_types != (input_max + output_max ) )
      {
         /** TODO, make exception for here **/
         assert( false );
      }
      /** multiple port type case **/
      std::size_t input_index(  0 );
      std::size_t output_index( 0 );
      AddPorts< PORTSM... >::add( input_index,
                                  input_max,
                                  input /* ports */,
                                  output_index,
                                  output_max,
                                  output /* ports */);
   }

}; /** end template lambdak **/

/** class recursion **/
template < class PORT, class... PORTSL > struct AddPorts< PORT, PORTSL...>
{
   static void add( std::size_t &input_index,
                    const std::size_t input_max,
                    Port &input_ports,
                    std::size_t &output_index,
                    const std::size_t output_max,
                    Port &output_ports )
   {
      if( input_index < input_max )
      {
         /** add ports in order, 0,1,2, etc. **/
         input_ports.addPort< PORT >( std::to_string( input_index++ ) );
         AddPorts< PORTSL... >::add( input_index,
                                     input_max,
                                     input_ports,
                                     output_index,
                                     output_max,
                                     output_ports );
      }
      else if( output_index < output_max )
      {
         /** add ports in order, 0, 1, 2, etc. **/
         output_ports.addPort< PORT >( std::to_string( output_index++ ) );
         AddPorts< PORTSL... >::add( input_index,
                                     input_max,
                                     input_ports,
                                     output_index,
                                     output_max,
                                     output_ports );
      }
      else
      {
         /**
          * I think it'll be okay here simply to return, however
          * we might need the blank specialization below
          */
      }
      return;
   }
};

template <> struct AddPorts<>
{
   static void add( std::size_t &input_index,
                    const std::size_t input_max,
                    Port &input_ports,
                    std::size_t &output_index,
                    const std::size_t output_max,
                    Port &output_ports )
   {
      return;
   }
};

/** single class type, no recursion **/
template < class PORT, class... PORTSK > struct AddSamePorts< PORT, PORTSK... >
{
   /** no recursion needed here **/
   static void add( const std::size_t input_count, Port &inputs,
                    const std::size_t output_count, Port &outputs )
   {
      for( auto it( 0 ); it < input_count; it++ )
      {
         inputs.addPort< PORT >( std::to_string( it ) );
      }
      for( auto it( 0 ); it < output_count; it++ )
      {
         outputs.addPort< PORT >( std::to_string( it ) );
      }
   }
};

template <> struct AddSamePorts<>
{
   static void add( const std::size_t input_count, Port &inputs,
                    const std::size_t output_count, Port &outputs )
   { return; }
};

} /* end namespace raft */
#endif /* END _LAMBDAK_TCC_ */
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------
#include "DataFmtTransl.hxx"
#include <rtl/string.hxx>
#include <osl/diagnose.h>
#include <rtl/tencinfo.h>
#include "../misc/ImplHelper.hxx"
#include "../misc/WinClip.hxx"
#include "MimeAttrib.hxx"
#include "DTransHelper.hxx"
#include <rtl/string.h>
#include "Fetc.hxx"

#if defined _MSC_VER
#pragma warning(push,1)
#pragma warning(disable:4917)
#endif
#include <windows.h>
#if (_MSC_VER < 1300) && !defined(__MINGW32__)
#include <olestd.h>
#endif
#include <shlobj.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif

//------------------------------------------------------------------------
// namespace directives
//------------------------------------------------------------------------

using namespace std;
using namespace com::sun::star::uno;
using namespace com::sun::star::datatransfer;
using namespace com::sun::star::lang;

using ::rtl::OUString;

//------------------------------------------------------------------------
// const
//------------------------------------------------------------------------

const Type       CPPUTYPE_SALINT32   = getCppuType((sal_Int32*)0);
const Type       CPPUTYPE_SALINT8    = getCppuType((sal_Int8*)0);
const Type       CPPUTYPE_OUSTRING   = getCppuType((OUString*)0);
const Type       CPPUTYPE_SEQSALINT8 = getCppuType((Sequence< sal_Int8>*)0);
const sal_Int32  MAX_CLIPFORMAT_NAME = 256;

const OUString TEXT_PLAIN_CHARSET   ("text/plain;charset=");
const OUString HPNAME_OEM_ANSI_TEXT ("OEM/ANSI Text");

const OUString HTML_FORMAT_NAME_WINDOWS ("HTML Format");
const OUString HTML_FORMAT_NAME_SOFFICE ("HTML (HyperText Markup Language");

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CDataFormatTranslator::CDataFormatTranslator( const Reference< XMultiServiceFactory >& aServiceManager ) :
    m_SrvMgr( aServiceManager )
{
    m_XDataFormatTranslator = Reference< XDataFormatTranslator >(
        m_SrvMgr->createInstance( OUString("com.sun.star.datatransfer.DataFormatTranslator") ), UNO_QUERY );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CFormatEtc CDataFormatTranslator::getFormatEtcFromDataFlavor( const DataFlavor& aDataFlavor ) const
{
    sal_Int32 cf = CF_INVALID;

    try
    {
        if( m_XDataFormatTranslator.is( ) )
        {
            Any aFormat = m_XDataFormatTranslator->getSystemDataTypeFromDataFlavor( aDataFlavor );

            if ( aFormat.hasValue( ) )
            {
                if ( aFormat.getValueType( ) == CPPUTYPE_SALINT32 )
                {
                    aFormat >>= cf;
                    OSL_ENSURE( CF_INVALID != cf, "Invalid Clipboard format delivered" );
                }
                else if ( aFormat.getValueType( ) == CPPUTYPE_OUSTRING )
                {
                    OUString aClipFmtName;
                    aFormat >>= aClipFmtName;

                    OSL_ASSERT( aClipFmtName.getLength( ) );
                    cf = RegisterClipboardFormatW( reinterpret_cast<LPCWSTR>(aClipFmtName.getStr( )) );

                    OSL_ENSURE( CF_INVALID != cf, "RegisterClipboardFormat failed" );
                }
                else
                    OSL_FAIL( "Wrong Any-Type detected" );
            }
        }
    }
    catch( ... )
    {
        OSL_FAIL( "Unexpected error" );
    }

    return sal::static_int_cast<CFormatEtc>(getFormatEtcForClipformat( sal::static_int_cast<CLIPFORMAT>(cf) ));
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

DataFlavor CDataFormatTranslator::getDataFlavorFromFormatEtc( const FORMATETC& aFormatEtc, LCID lcid ) const
{
    DataFlavor aFlavor;

    try
    {
        CLIPFORMAT aClipformat = aFormatEtc.cfFormat;

        Any aAny;
        aAny <<= static_cast< sal_Int32 >( aClipformat );

        if ( isOemOrAnsiTextFormat( aClipformat ) )
        {
            aFlavor.MimeType             = TEXT_PLAIN_CHARSET;
            aFlavor.MimeType            += getTextCharsetFromLCID( lcid, aClipformat );

            aFlavor.HumanPresentableName = HPNAME_OEM_ANSI_TEXT;
            aFlavor.DataType             = CPPUTYPE_SEQSALINT8;
        }
        else if ( CF_INVALID != aClipformat )
        {
            if ( m_XDataFormatTranslator.is( ) )
            {
                aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );

                if ( !aFlavor.MimeType.getLength( ) )
                {
                    // lookup of DataFlavor from clipboard format id
                    // failed, so we try to resolve via clipboard
                    // format name
                    OUString clipFormatName = getClipboardFormatName( aClipformat );

                    // if we could not get a clipboard format name an
                    // error must have occurred or it is a standard
                    // clipboard format that we don't translate, e.g.
                    // CF_BITMAP (the office only uses CF_DIB)
                    if ( clipFormatName.getLength( ) )
                    {
                        aAny <<= clipFormatName;
                        aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );
                    }
                }
            }
        }
    }
    catch( ... )
    {
        OSL_FAIL( "Unexpected error" );
    }

    return aFlavor;
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CFormatEtc SAL_CALL CDataFormatTranslator::getFormatEtcForClipformatName( const OUString& aClipFmtName ) const
{
    // check parameter
    if ( !aClipFmtName.getLength( ) )
        return CFormatEtc( CF_INVALID );

    CLIPFORMAT cf = sal::static_int_cast<CLIPFORMAT>(RegisterClipboardFormatW( reinterpret_cast<LPCWSTR>(aClipFmtName.getStr( )) ));
    return getFormatEtcForClipformat( cf );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

OUString CDataFormatTranslator::getClipboardFormatName( CLIPFORMAT aClipformat ) const
{
    OSL_PRECOND( CF_INVALID != aClipformat, "Invalid clipboard format" );

    sal_Unicode wBuff[ MAX_CLIPFORMAT_NAME ];
    sal_Int32   nLen = GetClipboardFormatNameW( aClipformat, reinterpret_cast<LPWSTR>(wBuff), MAX_CLIPFORMAT_NAME );

    return OUString( wBuff, nLen );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CFormatEtc SAL_CALL CDataFormatTranslator::getFormatEtcForClipformat( CLIPFORMAT cf ) const
{
    CFormatEtc fetc( cf, TYMED_NULL, NULL, DVASPECT_CONTENT );

    switch( cf )
    {
    case CF_METAFILEPICT:
        fetc.setTymed( TYMED_MFPICT );
        break;

    case CF_ENHMETAFILE:
        fetc.setTymed( TYMED_ENHMF );
        break;

    default:
        fetc.setTymed( TYMED_HGLOBAL /*| TYMED_ISTREAM*/ );
    }

    /*
        hack: in order to paste urls copied by Internet Explorer
        with "copy link" we set the lindex member to 0
        but if we really want to support CFSTR_FILECONTENT and
        the accompany format CFSTR_FILEDESCRIPTOR (FileGroupDescriptor)
        the client of the clipboard service has to provide a id
        of which FileContents it wants to paste
        see MSDN: "Handling Shell Data Transfer Scenarios"
    */
    if ( cf == RegisterClipboardFormatA( CFSTR_FILECONTENTS ) )
         fetc.setLindex( 0 );

    return fetc;
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isOemOrAnsiTextFormat( CLIPFORMAT cf ) const
{
    return ( (cf == CF_TEXT) || (cf == CF_OEMTEXT) );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isUnicodeTextFormat( CLIPFORMAT cf ) const
{
    return ( cf == CF_UNICODETEXT );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isTextFormat( CLIPFORMAT cf ) const
{
    return ( isOemOrAnsiTextFormat( cf ) || isUnicodeTextFormat( cf ) );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isHTMLFormat( CLIPFORMAT cf ) const
{
    OUString clipFormatName = getClipboardFormatName( cf );
    return ( clipFormatName == HTML_FORMAT_NAME_WINDOWS );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isTextHtmlFormat( CLIPFORMAT cf ) const
{
    OUString clipFormatName = getClipboardFormatName( cf );
    return ( clipFormatName.equalsIgnoreAsciiCase( HTML_FORMAT_NAME_SOFFICE ) );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

OUString SAL_CALL CDataFormatTranslator::getTextCharsetFromLCID( LCID lcid, CLIPFORMAT aClipformat ) const
{
    OSL_ASSERT( isOemOrAnsiTextFormat( aClipformat ) );

    OUString charset;
    if ( CF_TEXT == aClipformat )
    {
        charset = getMimeCharsetFromLocaleId(
                    lcid,
                    LOCALE_IDEFAULTANSICODEPAGE,
                    PRE_WINDOWS_CODEPAGE );
    }
    else if ( CF_OEMTEXT == aClipformat )
    {
        charset = getMimeCharsetFromLocaleId(
                    lcid,
                    LOCALE_IDEFAULTCODEPAGE,
                    PRE_OEM_CODEPAGE );
    }
    else // CF_UNICODE
        OSL_ASSERT( sal_False );

    return charset;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>I think, this is what was intended<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

//------------------------------------------------------------------------
// includes
//------------------------------------------------------------------------
#include "DataFmtTransl.hxx"
#include <rtl/string.hxx>
#include <osl/diagnose.h>
#include <rtl/tencinfo.h>
#include "../misc/ImplHelper.hxx"
#include "../misc/WinClip.hxx"
#include "MimeAttrib.hxx"
#include "DTransHelper.hxx"
#include <rtl/string.h>
#include "Fetc.hxx"

#if defined _MSC_VER
#pragma warning(push,1)
#pragma warning(disable:4917)
#endif
#include <windows.h>
#if (_MSC_VER < 1300) && !defined(__MINGW32__)
#include <olestd.h>
#endif
#include <shlobj.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif

//------------------------------------------------------------------------
// namespace directives
//------------------------------------------------------------------------

using namespace std;
using namespace com::sun::star::uno;
using namespace com::sun::star::datatransfer;
using namespace com::sun::star::lang;

using ::rtl::OUString;

//------------------------------------------------------------------------
// const
//------------------------------------------------------------------------

const Type       CPPUTYPE_SALINT32   = getCppuType((sal_Int32*)0);
const Type       CPPUTYPE_SALINT8    = getCppuType((sal_Int8*)0);
const Type       CPPUTYPE_OUSTRING   = getCppuType((OUString*)0);
const Type       CPPUTYPE_SEQSALINT8 = getCppuType((Sequence< sal_Int8>*)0);
const sal_Int32  MAX_CLIPFORMAT_NAME = 256;

const OUString TEXT_PLAIN_CHARSET   ("text/plain;charset=");
const OUString HPNAME_OEM_ANSI_TEXT ("OEM/ANSI Text");

const OUString HTML_FORMAT_NAME_WINDOWS ("HTML Format");
const OUString HTML_FORMAT_NAME_SOFFICE ("HTML (HyperText Markup Language)");

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CDataFormatTranslator::CDataFormatTranslator( const Reference< XMultiServiceFactory >& aServiceManager ) :
    m_SrvMgr( aServiceManager )
{
    m_XDataFormatTranslator = Reference< XDataFormatTranslator >(
        m_SrvMgr->createInstance( OUString("com.sun.star.datatransfer.DataFormatTranslator") ), UNO_QUERY );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CFormatEtc CDataFormatTranslator::getFormatEtcFromDataFlavor( const DataFlavor& aDataFlavor ) const
{
    sal_Int32 cf = CF_INVALID;

    try
    {
        if( m_XDataFormatTranslator.is( ) )
        {
            Any aFormat = m_XDataFormatTranslator->getSystemDataTypeFromDataFlavor( aDataFlavor );

            if ( aFormat.hasValue( ) )
            {
                if ( aFormat.getValueType( ) == CPPUTYPE_SALINT32 )
                {
                    aFormat >>= cf;
                    OSL_ENSURE( CF_INVALID != cf, "Invalid Clipboard format delivered" );
                }
                else if ( aFormat.getValueType( ) == CPPUTYPE_OUSTRING )
                {
                    OUString aClipFmtName;
                    aFormat >>= aClipFmtName;

                    OSL_ASSERT( aClipFmtName.getLength( ) );
                    cf = RegisterClipboardFormatW( reinterpret_cast<LPCWSTR>(aClipFmtName.getStr( )) );

                    OSL_ENSURE( CF_INVALID != cf, "RegisterClipboardFormat failed" );
                }
                else
                    OSL_FAIL( "Wrong Any-Type detected" );
            }
        }
    }
    catch( ... )
    {
        OSL_FAIL( "Unexpected error" );
    }

    return sal::static_int_cast<CFormatEtc>(getFormatEtcForClipformat( sal::static_int_cast<CLIPFORMAT>(cf) ));
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

DataFlavor CDataFormatTranslator::getDataFlavorFromFormatEtc( const FORMATETC& aFormatEtc, LCID lcid ) const
{
    DataFlavor aFlavor;

    try
    {
        CLIPFORMAT aClipformat = aFormatEtc.cfFormat;

        Any aAny;
        aAny <<= static_cast< sal_Int32 >( aClipformat );

        if ( isOemOrAnsiTextFormat( aClipformat ) )
        {
            aFlavor.MimeType             = TEXT_PLAIN_CHARSET;
            aFlavor.MimeType            += getTextCharsetFromLCID( lcid, aClipformat );

            aFlavor.HumanPresentableName = HPNAME_OEM_ANSI_TEXT;
            aFlavor.DataType             = CPPUTYPE_SEQSALINT8;
        }
        else if ( CF_INVALID != aClipformat )
        {
            if ( m_XDataFormatTranslator.is( ) )
            {
                aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );

                if ( !aFlavor.MimeType.getLength( ) )
                {
                    // lookup of DataFlavor from clipboard format id
                    // failed, so we try to resolve via clipboard
                    // format name
                    OUString clipFormatName = getClipboardFormatName( aClipformat );

                    // if we could not get a clipboard format name an
                    // error must have occurred or it is a standard
                    // clipboard format that we don't translate, e.g.
                    // CF_BITMAP (the office only uses CF_DIB)
                    if ( clipFormatName.getLength( ) )
                    {
                        aAny <<= clipFormatName;
                        aFlavor = m_XDataFormatTranslator->getDataFlavorFromSystemDataType( aAny );
                    }
                }
            }
        }
    }
    catch( ... )
    {
        OSL_FAIL( "Unexpected error" );
    }

    return aFlavor;
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CFormatEtc SAL_CALL CDataFormatTranslator::getFormatEtcForClipformatName( const OUString& aClipFmtName ) const
{
    // check parameter
    if ( !aClipFmtName.getLength( ) )
        return CFormatEtc( CF_INVALID );

    CLIPFORMAT cf = sal::static_int_cast<CLIPFORMAT>(RegisterClipboardFormatW( reinterpret_cast<LPCWSTR>(aClipFmtName.getStr( )) ));
    return getFormatEtcForClipformat( cf );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

OUString CDataFormatTranslator::getClipboardFormatName( CLIPFORMAT aClipformat ) const
{
    OSL_PRECOND( CF_INVALID != aClipformat, "Invalid clipboard format" );

    sal_Unicode wBuff[ MAX_CLIPFORMAT_NAME ];
    sal_Int32   nLen = GetClipboardFormatNameW( aClipformat, reinterpret_cast<LPWSTR>(wBuff), MAX_CLIPFORMAT_NAME );

    return OUString( wBuff, nLen );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

CFormatEtc SAL_CALL CDataFormatTranslator::getFormatEtcForClipformat( CLIPFORMAT cf ) const
{
    CFormatEtc fetc( cf, TYMED_NULL, NULL, DVASPECT_CONTENT );

    switch( cf )
    {
    case CF_METAFILEPICT:
        fetc.setTymed( TYMED_MFPICT );
        break;

    case CF_ENHMETAFILE:
        fetc.setTymed( TYMED_ENHMF );
        break;

    default:
        fetc.setTymed( TYMED_HGLOBAL /*| TYMED_ISTREAM*/ );
    }

    /*
        hack: in order to paste urls copied by Internet Explorer
        with "copy link" we set the lindex member to 0
        but if we really want to support CFSTR_FILECONTENT and
        the accompany format CFSTR_FILEDESCRIPTOR (FileGroupDescriptor)
        the client of the clipboard service has to provide a id
        of which FileContents it wants to paste
        see MSDN: "Handling Shell Data Transfer Scenarios"
    */
    if ( cf == RegisterClipboardFormatA( CFSTR_FILECONTENTS ) )
         fetc.setLindex( 0 );

    return fetc;
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isOemOrAnsiTextFormat( CLIPFORMAT cf ) const
{
    return ( (cf == CF_TEXT) || (cf == CF_OEMTEXT) );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isUnicodeTextFormat( CLIPFORMAT cf ) const
{
    return ( cf == CF_UNICODETEXT );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isTextFormat( CLIPFORMAT cf ) const
{
    return ( isOemOrAnsiTextFormat( cf ) || isUnicodeTextFormat( cf ) );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isHTMLFormat( CLIPFORMAT cf ) const
{
    OUString clipFormatName = getClipboardFormatName( cf );
    return ( clipFormatName == HTML_FORMAT_NAME_WINDOWS );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

sal_Bool SAL_CALL CDataFormatTranslator::isTextHtmlFormat( CLIPFORMAT cf ) const
{
    OUString clipFormatName = getClipboardFormatName( cf );
    return ( clipFormatName.equalsIgnoreAsciiCase( HTML_FORMAT_NAME_SOFFICE ) );
}

//------------------------------------------------------------------------
//
//------------------------------------------------------------------------

OUString SAL_CALL CDataFormatTranslator::getTextCharsetFromLCID( LCID lcid, CLIPFORMAT aClipformat ) const
{
    OSL_ASSERT( isOemOrAnsiTextFormat( aClipformat ) );

    OUString charset;
    if ( CF_TEXT == aClipformat )
    {
        charset = getMimeCharsetFromLocaleId(
                    lcid,
                    LOCALE_IDEFAULTANSICODEPAGE,
                    PRE_WINDOWS_CODEPAGE );
    }
    else if ( CF_OEMTEXT == aClipformat )
    {
        charset = getMimeCharsetFromLocaleId(
                    lcid,
                    LOCALE_IDEFAULTCODEPAGE,
                    PRE_OEM_CODEPAGE );
    }
    else // CF_UNICODE
        OSL_ASSERT( sal_False );

    return charset;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>