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

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date: 2007-09-22 11:55:20 +0200 (Sa, 22 Sep 2007) $
Version:   $Revision: 12240 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "mitkVtkPropRenderer.h"

#include "picimage.h"

// MAPPERS
#include "mitkMapper.h"
#include "mitkImageMapper2D.h"
#include "mitkBaseVtkMapper2D.h"
#include "mitkBaseVtkMapper3D.h"
#include "mitkGeometry2DDataVtkMapper3D.h"
#include "mitkPointSetMapper2D.h"

#include "mitkImageSliceSelector.h"
#include "mitkRenderingManager.h"
#include "mitkGL.h"
#include "mitkGeometry3D.h"
#include "mitkDisplayGeometry.h"
#include "mitkLevelWindow.h"
#include "mitkCameraController.h"
#include "mitkVtkInteractorCameraController.h"
#include "mitkPlaneGeometry.h"
#include "mitkProperties.h"

// VTK
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkLight.h>
#include <vtkLightKit.h>
#include <vtkRenderWindow.h>
#include <vtkLinearTransform.h>
#include <vtkCamera.h>
#include <vtkWorldPointPicker.h>
#include <vtkPointPicker.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkProp.h>

mitk::VtkPropRenderer::VtkPropRenderer( const char* name, vtkRenderWindow * renWin )
  : BaseRenderer(name,renWin),
  m_VtkMapperPresent(false),
  m_NewRenderer(true)
{
  m_WorldPointPicker = vtkWorldPointPicker::New();
  m_PointPicker = vtkPointPicker::New();

  mitk::Geometry2DDataVtkMapper3D::Pointer geometryMapper = mitk::Geometry2DDataVtkMapper3D::New();
  m_CurrentWorldGeometry2DMapper = geometryMapper;
  m_CurrentWorldGeometry2DNode->SetMapper(2, geometryMapper);

  m_LightKit = vtkLightKit::New();
  m_LightKit->AddLightsToRenderer(m_VtkRenderer);
  m_PickingMode = WorldPointPicking;

  m_TextRenderer = vtkRenderer::New();
  m_TextRenderer->SetRenderWindow(renWin);
  m_TextRenderer->SetInteractive(0);
  #if ( VTK_MAJOR_VERSION >= 5 )
    m_TextRenderer->SetErase(0);
  #endif

}

void mitk::VtkPropRenderer::SetData(const mitk::DataTreeIteratorBase* iterator)
{
  if(iterator!=GetData())
  {
    BaseRenderer::SetData(iterator);
    static_cast<mitk::Geometry2DDataVtkMapper3D*>(m_CurrentWorldGeometry2DMapper.GetPointer())->SetDataIteratorForTexture(m_DataTreeIterator.GetPointer());

    if (iterator != NULL)
    {
      //initialize world geometry
      mitk::Geometry3D::Pointer geometry = mitk::DataTree::ComputeVisibleBoundingGeometry3D(const_cast<mitk::DataTreeIteratorBase*>(iterator), NULL, "includeInBoundingBox");
      if ( geometry.IsNotNull() )
      {
        SetWorldGeometry(geometry);
        GetDisplayGeometry()->Fit();
        GetVtkRenderer()->ResetCamera();
      }
    }

    Modified();
  }
}

/*!
\brief

Called by the vtkMitkRenderProp in order to start MITK rendering process.
*/
int mitk::VtkPropRenderer::Render(mitk::VtkPropRenderer::RenderType type)
{
  // Do we have to render ?
  if(GetEmptyWorldGeometry()) return 0;
  if(GetData() == NULL) return 0;
  if(dynamic_cast<mitk::DataTree*>(GetData()->GetTree()) == NULL ) return 0;

  // Update mappers and prepare mapper queue
  if(type == VtkPropRenderer::Opaque)
    PrepareMapperQueue();

  //go through the generated list and let the sorted mappers paint
  bool lastVtkBased = true;

  for(MappersMapType::iterator it = m_MappersMap.begin(); it != m_MappersMap.end(); it++)
  {
    Mapper * mapper = (*it).second;
    if((mapper->IsVtkBased() == true) )
    {
      mitk::BaseVtkMapper3D::Pointer vtkMapper = dynamic_cast<mitk::BaseVtkMapper3D*>(mapper);
      if(vtkMapper)
      {
         vtkMapper->GetProp()->SetAllocatedRenderTime(5000,GetVtkRenderer()); //B/ ToDo: rendering time calculation
         //vtkMapper->GetProp()->PokeMatrix(NULL); //B/ ToDo ??: VtkUserTransform
      }
      if(lastVtkBased == false)
      {
        Disable2DOpenGL();
        lastVtkBased = true;
      }
    }
    else
    if((mapper->IsVtkBased() == false) && (lastVtkBased == true))
    {
      Enable2DOpenGL();
      lastVtkBased = false;
    }

    switch(type)
    {
      case mitk::VtkPropRenderer::Opaque:        mapper->MitkRenderOpaqueGeometry(this); break;
      case mitk::VtkPropRenderer::Translucent:   mapper->MitkRenderTranslucentGeometry(this); break;
      case mitk::VtkPropRenderer::Overlay:       mapper->MitkRenderOverlay(this); break;
    }
  }

  if(lastVtkBased==false)
    Disable2DOpenGL();

  // Render text
  if(type == VtkPropRenderer::Overlay)
  {
    if(m_TextCollection.size() > 0)
    {
      for (TextMapType::iterator it = m_TextCollection.begin(); it != m_TextCollection.end() ; it++)
        m_TextRenderer->AddViewProp((*it).second);
      m_TextRenderer->Render();
    }
  }
  return 1;
}

/*!
\brief PrepareMapperQueue iterates the datatree

PrepareMapperQueue iterates the datatree in order to find mappers which shall be rendered. Also, it sortes the mappers wrt to their layer.
*/
void mitk::VtkPropRenderer::PrepareMapperQueue()
{
  // Do we have to update the mappers ?
  if ( m_LastUpdateTime < GetMTime() || m_LastUpdateTime < GetDisplayGeometry()->GetMTime() )
    Update();
  else if(m_MapperID>=2 && m_MapperID < 6)
    Update();

  // remove all text properties before mappers will add new ones
  m_TextRenderer->RemoveAllViewProps();
  m_TextCollection.clear();

  // clear priority_queue
  m_MappersMap.clear();

  int mapperNo = 0;
  mitk::DataTreeIteratorClone it = m_DataTreeIterator;
  for(;it->IsAtEnd()==false;++it)
  {
    mitk::DataTreeNode::Pointer node = it->Get();
    if(node.IsNull())
      continue;
    mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID);
    if(mapper.IsNull())
      continue;

    //if(GetDisplayGeometry()->IsValid())
    //{

    //}

    if(m_MapperID == 1 && mapper->IsVtkBased())
      continue; //B/ no vtk mappers in 2D windows

    // mapper without a layer property get layer number 1
    int layer=1;
    node->GetIntProperty("layer", layer, this);

    int nr = (layer<<16) + mapperNo;
    m_MappersMap.insert(std::pair<int,Mapper*>(nr, mapper));
    mapperNo++;
  }
}

/*!
\brief

Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection)
*/
void mitk::VtkPropRenderer::Enable2DOpenGL()
{
  GLint iViewport[4];

  // Get a copy of the viewport
  glGetIntegerv( GL_VIEWPORT, iViewport );

  // Save a copy of the projection matrix so that we can restore it
  // when it's time to do 3D rendering again.
  glMatrixMode( GL_PROJECTION );
  glPushMatrix();
  glLoadIdentity();

  // Set up the orthographic projection
  glOrtho( iViewport[0], iViewport[0]+iViewport[2],
  iViewport[1]+iViewport[3], iViewport[1], -1, 1 );
  glMatrixMode( GL_MODELVIEW );
  glPushMatrix();
  glLoadIdentity();

  // Make sure depth testing and lighting are disabled for 2D rendering until
  // we are finished rendering in 2D
  glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT );
  glDisable( GL_DEPTH_TEST );
  glDisable( GL_LIGHTING );
}

/*!
\brief Initialize the VtkPropRenderer

Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection)
*/
void mitk::VtkPropRenderer::Disable2DOpenGL()
{
  glPopAttrib();
  glMatrixMode( GL_PROJECTION );
  glPopMatrix();
  glMatrixMode( GL_MODELVIEW );
  glPopMatrix();
}

void mitk::VtkPropRenderer::Update(mitk::DataTreeNode* datatreenode)
{
  if(datatreenode!=NULL)
  {
    mitk::Mapper::Pointer mapper = datatreenode->GetMapper(m_MapperID);
    if(mapper.IsNotNull())
    {
      Mapper2D* mapper2d=dynamic_cast<Mapper2D*>(mapper.GetPointer());
      if(mapper2d != NULL)
      {
        if(GetDisplayGeometry()->IsValid())
        {
          BaseVtkMapper2D* vtkmapper2d=dynamic_cast<BaseVtkMapper2D*>(mapper.GetPointer());
          if(vtkmapper2d != NULL)
          {
            vtkmapper2d->Update(this);
            m_VtkMapperPresent=true;
          }
          else
            mapper2d->Update(this);
        }
      }
      else
      {
        BaseVtkMapper3D* vtkmapper3d=dynamic_cast<BaseVtkMapper3D*>(mapper.GetPointer());
        if(vtkmapper3d != NULL)
        {
          vtkmapper3d->Update(this);
          vtkmapper3d->UpdateVtkTransform(this);
          m_VtkMapperPresent=true;
        }
      }
    }
  }
}

void mitk::VtkPropRenderer::Update()
{
  if(m_DataTreeIterator.IsNull()) return;

  m_VtkMapperPresent=false;

  mitk::DataTreeIteratorClone it=m_DataTreeIterator;

  while(!it->IsAtEnd())
  {
    Update(it->Get());
    ++it;
  }
  Modified();
  m_LastUpdateTime=GetMTime();
}

/*!
\brief

This method is called from the two Constructors
*/
void mitk::VtkPropRenderer::InitRenderer(vtkRenderWindow* renderWindow)
{
  BaseRenderer::InitRenderer(renderWindow);

  if(renderWindow == NULL)
  {
    m_InitNeeded = false;
    m_ResizeNeeded = false;
    return;
  }

  m_InitNeeded = true;
  m_ResizeNeeded = true;

  m_LastUpdateTime = 0;

}

/*!
\brief Destructs the VtkPropRenderer.
*/
mitk::VtkPropRenderer::~VtkPropRenderer()
{
  if(m_VtkRenderer!=NULL)
  {
     m_CameraController = NULL;
     m_VtkRenderer->Delete();
  }
  else
    m_CameraController = NULL;
}

/*!
\brief Resize the OpenGL Window
*/
void mitk::VtkPropRenderer::Resize(int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho( 0.0, w, 0.0, h , 0.0 , 1.0);
  glMatrixMode( GL_MODELVIEW );

  BaseRenderer::Resize(w, h);

  Update();
}

void mitk::VtkPropRenderer::InitSize(int w, int h)
{
  m_RenderWindow->SetSize(w,h);
  Superclass::InitSize(w, h);
  Modified();
  Update();
  if(m_VtkRenderer!=NULL)
  {
    int w=vtkObject::GetGlobalWarningDisplay();
    vtkObject::GlobalWarningDisplayOff();
    m_VtkRenderer->ResetCamera();
    vtkObject::SetGlobalWarningDisplay(w);
  }
}

void mitk::VtkPropRenderer::SetMapperID(const MapperSlotId mapperId)
{
  if(m_MapperID != mapperId)
    Superclass::SetMapperID(mapperId);
}

/*!
\brief Activates the current renderwindow.
*/
void mitk::VtkPropRenderer::MakeCurrent()
{
  if(m_RenderWindow!=NULL)
     m_RenderWindow->MakeCurrent();
}

void mitk::VtkPropRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const
{
  if(m_VtkMapperPresent)
  {
    //m_WorldPointPicker->SetTolerance (0.0001);
    switch ( m_PickingMode )
    {
     case (WorldPointPicking) :
     {
       m_WorldPointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer);
       vtk2itk(m_WorldPointPicker->GetPickPosition(), worldPoint);
       break;
     }
     case (PointPicking) :
     {
       m_PointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer);
       vtk2itk(m_PointPicker->GetPickPosition(), worldPoint);
       break;
     }
    }
  }
  else
    Superclass::PickWorldPoint(displayPoint, worldPoint);
}

/*!
\brief Writes some 2D text as overlay. Function returns an unique int Text_ID for each call, which can be used via the GetTextLabelProperty(int text_id) function
in order to get a vtkTextProperty. This property enables the setup of font, font size, etc.
*/
int mitk::VtkPropRenderer::WriteSimpleText(std::string text, double posX, double posY, double color1, double color2, double color3)
{
 if(text.size() > 0)
  {
    vtkTextActor* textActor = vtkTextActor::New();

    textActor->SetPosition(posX,posY);
    textActor->SetInput(text.c_str());
    textActor->GetTextProperty()->SetColor(color1, color2, color3); //TODO: Read color from node property
    int text_id = m_TextCollection.size();
    m_TextCollection.insert(TextMapType::value_type(text_id,textActor));
    return text_id;
  }
  return -1;
}

/*!
\brief Can be used in order to get a vtkTextProperty for a specific text_id. This property enables the setup of font, font size, etc.
*/
vtkTextProperty* mitk::VtkPropRenderer::GetTextLabelProperty(int text_id)
{
	return this->m_TextCollection[text_id]->GetTextProperty();
}
<commit_msg>FIX (#1157): glOrtho was wrong in mitk::VtkPropRenderer::Enable2DOpenGL(): caused upside down rendering of surface contours<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile$
Language:  C++
Date:      $Date: 2007-09-22 11:55:20 +0200 (Sa, 22 Sep 2007) $
Version:   $Revision: 12240 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

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

#include "mitkVtkPropRenderer.h"

#include "picimage.h"

// MAPPERS
#include "mitkMapper.h"
#include "mitkImageMapper2D.h"
#include "mitkBaseVtkMapper2D.h"
#include "mitkBaseVtkMapper3D.h"
#include "mitkGeometry2DDataVtkMapper3D.h"
#include "mitkPointSetMapper2D.h"

#include "mitkImageSliceSelector.h"
#include "mitkRenderingManager.h"
#include "mitkGL.h"
#include "mitkGeometry3D.h"
#include "mitkDisplayGeometry.h"
#include "mitkLevelWindow.h"
#include "mitkCameraController.h"
#include "mitkVtkInteractorCameraController.h"
#include "mitkPlaneGeometry.h"
#include "mitkProperties.h"

// VTK
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkLight.h>
#include <vtkLightKit.h>
#include <vtkRenderWindow.h>
#include <vtkLinearTransform.h>
#include <vtkCamera.h>
#include <vtkWorldPointPicker.h>
#include <vtkPointPicker.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkProp.h>

mitk::VtkPropRenderer::VtkPropRenderer( const char* name, vtkRenderWindow * renWin )
  : BaseRenderer(name,renWin),
  m_VtkMapperPresent(false),
  m_NewRenderer(true)
{
  m_WorldPointPicker = vtkWorldPointPicker::New();
  m_PointPicker = vtkPointPicker::New();

  mitk::Geometry2DDataVtkMapper3D::Pointer geometryMapper = mitk::Geometry2DDataVtkMapper3D::New();
  m_CurrentWorldGeometry2DMapper = geometryMapper;
  m_CurrentWorldGeometry2DNode->SetMapper(2, geometryMapper);

  m_LightKit = vtkLightKit::New();
  m_LightKit->AddLightsToRenderer(m_VtkRenderer);
  m_PickingMode = WorldPointPicking;

  m_TextRenderer = vtkRenderer::New();
  m_TextRenderer->SetRenderWindow(renWin);
  m_TextRenderer->SetInteractive(0);
  #if ( VTK_MAJOR_VERSION >= 5 )
    m_TextRenderer->SetErase(0);
  #endif

}

void mitk::VtkPropRenderer::SetData(const mitk::DataTreeIteratorBase* iterator)
{
  if(iterator!=GetData())
  {
    BaseRenderer::SetData(iterator);
    static_cast<mitk::Geometry2DDataVtkMapper3D*>(m_CurrentWorldGeometry2DMapper.GetPointer())->SetDataIteratorForTexture(m_DataTreeIterator.GetPointer());

    if (iterator != NULL)
    {
      //initialize world geometry
      mitk::Geometry3D::Pointer geometry = mitk::DataTree::ComputeVisibleBoundingGeometry3D(const_cast<mitk::DataTreeIteratorBase*>(iterator), NULL, "includeInBoundingBox");
      if ( geometry.IsNotNull() )
      {
        SetWorldGeometry(geometry);
        GetDisplayGeometry()->Fit();
        GetVtkRenderer()->ResetCamera();
      }
    }

    Modified();
  }
}

/*!
\brief

Called by the vtkMitkRenderProp in order to start MITK rendering process.
*/
int mitk::VtkPropRenderer::Render(mitk::VtkPropRenderer::RenderType type)
{
  // Do we have to render ?
  if(GetEmptyWorldGeometry()) return 0;
  if(GetData() == NULL) return 0;
  if(dynamic_cast<mitk::DataTree*>(GetData()->GetTree()) == NULL ) return 0;

  // Update mappers and prepare mapper queue
  if(type == VtkPropRenderer::Opaque)
    PrepareMapperQueue();

  //go through the generated list and let the sorted mappers paint
  bool lastVtkBased = true;

  for(MappersMapType::iterator it = m_MappersMap.begin(); it != m_MappersMap.end(); it++)
  {
    Mapper * mapper = (*it).second;
    if((mapper->IsVtkBased() == true) )
    {
      mitk::BaseVtkMapper3D::Pointer vtkMapper = dynamic_cast<mitk::BaseVtkMapper3D*>(mapper);
      if(vtkMapper)
      {
         vtkMapper->GetProp()->SetAllocatedRenderTime(5000,GetVtkRenderer()); //B/ ToDo: rendering time calculation
         //vtkMapper->GetProp()->PokeMatrix(NULL); //B/ ToDo ??: VtkUserTransform
      }
      if(lastVtkBased == false)
      {
        Disable2DOpenGL();
        lastVtkBased = true;
      }
    }
    else
    if((mapper->IsVtkBased() == false) && (lastVtkBased == true))
    {
      Enable2DOpenGL();
      lastVtkBased = false;
    }

    switch(type)
    {
      case mitk::VtkPropRenderer::Opaque:        mapper->MitkRenderOpaqueGeometry(this); break;
      case mitk::VtkPropRenderer::Translucent:   mapper->MitkRenderTranslucentGeometry(this); break;
      case mitk::VtkPropRenderer::Overlay:       mapper->MitkRenderOverlay(this); break;
    }
  }

  if(lastVtkBased==false)
    Disable2DOpenGL();

  // Render text
  if(type == VtkPropRenderer::Overlay)
  {
    if(m_TextCollection.size() > 0)
    {
      for (TextMapType::iterator it = m_TextCollection.begin(); it != m_TextCollection.end() ; it++)
        m_TextRenderer->AddViewProp((*it).second);
      m_TextRenderer->Render();
    }
  }
  return 1;
}

/*!
\brief PrepareMapperQueue iterates the datatree

PrepareMapperQueue iterates the datatree in order to find mappers which shall be rendered. Also, it sortes the mappers wrt to their layer.
*/
void mitk::VtkPropRenderer::PrepareMapperQueue()
{
  // Do we have to update the mappers ?
  if ( m_LastUpdateTime < GetMTime() || m_LastUpdateTime < GetDisplayGeometry()->GetMTime() )
    Update();
  else if(m_MapperID>=2 && m_MapperID < 6)
    Update();

  // remove all text properties before mappers will add new ones
  m_TextRenderer->RemoveAllViewProps();
  m_TextCollection.clear();

  // clear priority_queue
  m_MappersMap.clear();

  int mapperNo = 0;
  mitk::DataTreeIteratorClone it = m_DataTreeIterator;
  for(;it->IsAtEnd()==false;++it)
  {
    mitk::DataTreeNode::Pointer node = it->Get();
    if(node.IsNull())
      continue;
    mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID);
    if(mapper.IsNull())
      continue;

    //if(GetDisplayGeometry()->IsValid())
    //{

    //}

    if(m_MapperID == 1 && mapper->IsVtkBased())
      continue; //B/ no vtk mappers in 2D windows

    // mapper without a layer property get layer number 1
    int layer=1;
    node->GetIntProperty("layer", layer, this);

    int nr = (layer<<16) + mapperNo;
    m_MappersMap.insert(std::pair<int,Mapper*>(nr, mapper));
    mapperNo++;
  }
}

/*!
\brief

Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection)
*/
void mitk::VtkPropRenderer::Enable2DOpenGL()
{
  GLint iViewport[4];

  // Get a copy of the viewport
  glGetIntegerv( GL_VIEWPORT, iViewport );

  // Save a copy of the projection matrix so that we can restore it
  // when it's time to do 3D rendering again.
  glMatrixMode( GL_PROJECTION );
  glPushMatrix();
  glLoadIdentity();

  // Set up the orthographic projection
  glOrtho(
    iViewport[0], iViewport[0]+iViewport[2],
    iViewport[1], iViewport[1]+iViewport[3],
    -1.0, 1.0
  );
  glMatrixMode( GL_MODELVIEW );
  glPushMatrix();
  glLoadIdentity();

  // Make sure depth testing and lighting are disabled for 2D rendering until
  // we are finished rendering in 2D
  glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT );
  glDisable( GL_DEPTH_TEST );
  glDisable( GL_LIGHTING );
}

/*!
\brief Initialize the VtkPropRenderer

Enable2DOpenGL() and Disable2DOpenGL() are used to switch between 2D rendering (orthographic projection) and 3D rendering (perspective projection)
*/
void mitk::VtkPropRenderer::Disable2DOpenGL()
{
  glPopAttrib();
  glMatrixMode( GL_PROJECTION );
  glPopMatrix();
  glMatrixMode( GL_MODELVIEW );
  glPopMatrix();
}

void mitk::VtkPropRenderer::Update(mitk::DataTreeNode* datatreenode)
{
  if(datatreenode!=NULL)
  {
    mitk::Mapper::Pointer mapper = datatreenode->GetMapper(m_MapperID);
    if(mapper.IsNotNull())
    {
      Mapper2D* mapper2d=dynamic_cast<Mapper2D*>(mapper.GetPointer());
      if(mapper2d != NULL)
      {
        if(GetDisplayGeometry()->IsValid())
        {
          BaseVtkMapper2D* vtkmapper2d=dynamic_cast<BaseVtkMapper2D*>(mapper.GetPointer());
          if(vtkmapper2d != NULL)
          {
            vtkmapper2d->Update(this);
            m_VtkMapperPresent=true;
          }
          else
            mapper2d->Update(this);
        }
      }
      else
      {
        BaseVtkMapper3D* vtkmapper3d=dynamic_cast<BaseVtkMapper3D*>(mapper.GetPointer());
        if(vtkmapper3d != NULL)
        {
          vtkmapper3d->Update(this);
          vtkmapper3d->UpdateVtkTransform(this);
          m_VtkMapperPresent=true;
        }
      }
    }
  }
}

void mitk::VtkPropRenderer::Update()
{
  if(m_DataTreeIterator.IsNull()) return;

  m_VtkMapperPresent=false;

  mitk::DataTreeIteratorClone it=m_DataTreeIterator;

  while(!it->IsAtEnd())
  {
    Update(it->Get());
    ++it;
  }
  Modified();
  m_LastUpdateTime=GetMTime();
}

/*!
\brief

This method is called from the two Constructors
*/
void mitk::VtkPropRenderer::InitRenderer(vtkRenderWindow* renderWindow)
{
  BaseRenderer::InitRenderer(renderWindow);

  if(renderWindow == NULL)
  {
    m_InitNeeded = false;
    m_ResizeNeeded = false;
    return;
  }

  m_InitNeeded = true;
  m_ResizeNeeded = true;

  m_LastUpdateTime = 0;

}

/*!
\brief Destructs the VtkPropRenderer.
*/
mitk::VtkPropRenderer::~VtkPropRenderer()
{
  if(m_VtkRenderer!=NULL)
  {
     m_CameraController = NULL;
     m_VtkRenderer->Delete();
  }
  else
    m_CameraController = NULL;
}

/*!
\brief Resize the OpenGL Window
*/
void mitk::VtkPropRenderer::Resize(int w, int h)
{
  glViewport (0, 0, w, h);
  glMatrixMode( GL_PROJECTION );
  glLoadIdentity();
  glOrtho( 0.0, w, 0.0, h , 0.0 , 1.0);
  glMatrixMode( GL_MODELVIEW );

  BaseRenderer::Resize(w, h);

  Update();
}

void mitk::VtkPropRenderer::InitSize(int w, int h)
{
  m_RenderWindow->SetSize(w,h);
  Superclass::InitSize(w, h);
  Modified();
  Update();
  if(m_VtkRenderer!=NULL)
  {
    int w=vtkObject::GetGlobalWarningDisplay();
    vtkObject::GlobalWarningDisplayOff();
    m_VtkRenderer->ResetCamera();
    vtkObject::SetGlobalWarningDisplay(w);
  }
}

void mitk::VtkPropRenderer::SetMapperID(const MapperSlotId mapperId)
{
  if(m_MapperID != mapperId)
    Superclass::SetMapperID(mapperId);
}

/*!
\brief Activates the current renderwindow.
*/
void mitk::VtkPropRenderer::MakeCurrent()
{
  if(m_RenderWindow!=NULL)
     m_RenderWindow->MakeCurrent();
}

void mitk::VtkPropRenderer::PickWorldPoint(const mitk::Point2D& displayPoint, mitk::Point3D& worldPoint) const
{
  if(m_VtkMapperPresent)
  {
    //m_WorldPointPicker->SetTolerance (0.0001);
    switch ( m_PickingMode )
    {
     case (WorldPointPicking) :
     {
       m_WorldPointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer);
       vtk2itk(m_WorldPointPicker->GetPickPosition(), worldPoint);
       break;
     }
     case (PointPicking) :
     {
       m_PointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer);
       vtk2itk(m_PointPicker->GetPickPosition(), worldPoint);
       break;
     }
    }
  }
  else
    Superclass::PickWorldPoint(displayPoint, worldPoint);
}

/*!
\brief Writes some 2D text as overlay. Function returns an unique int Text_ID for each call, which can be used via the GetTextLabelProperty(int text_id) function
in order to get a vtkTextProperty. This property enables the setup of font, font size, etc.
*/
int mitk::VtkPropRenderer::WriteSimpleText(std::string text, double posX, double posY, double color1, double color2, double color3)
{
 if(text.size() > 0)
  {
    vtkTextActor* textActor = vtkTextActor::New();

    textActor->SetPosition(posX,posY);
    textActor->SetInput(text.c_str());
    textActor->GetTextProperty()->SetColor(color1, color2, color3); //TODO: Read color from node property
    int text_id = m_TextCollection.size();
    m_TextCollection.insert(TextMapType::value_type(text_id,textActor));
    return text_id;
  }
  return -1;
}

/*!
\brief Can be used in order to get a vtkTextProperty for a specific text_id. This property enables the setup of font, font size, etc.
*/
vtkTextProperty* mitk::VtkPropRenderer::GetTextLabelProperty(int text_id)
{
	return this->m_TextCollection[text_id]->GetTextProperty();
}
<|endoftext|>


<commit_before>/* Generated from orogen/lib/orogen/templates/typekit/typelib/TransportPlugin.cpp */

// First load all RTT interfaces so that we get all "extern template"
// declarations in the TypekitImpl files
#include "Registration.hpp"
#include "TransportPlugin.hpp"
#include <rtt/types/TypekitPlugin.hpp>
#include <typelib/pluginmanager.hh>
#include <utilmm/configfile/pkgconfig.hh>
using namespace RTT;

#define TYPEKIT_PACKAGE_NAME_aux0(target) #target
#define TYPEKIT_PACKAGE_NAME_aux(target) "<%= typekit.name %>-typekit-" TYPEKIT_PACKAGE_NAME_aux0(target)
#define TYPEKIT_PACKAGE_NAME TYPEKIT_PACKAGE_NAME_aux(OROCOS_TARGET)

orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::<%= typekit.name %>TypelibTransportPlugin()
    : m_registry(0)
{
    try {
        m_registry = Typelib::PluginManager::load("tlb", TYPEKIT_REGISTRY);
    }
    catch(std::exception const& e) {
        std::cerr << "cannot load the typekit's Typelib registry from" << std::endl;
        std::cerr << "  " << TYPEKIT_REGISTRY << std::endl;
        std::cerr << "remember to do 'make install' before you use the oroGen-generated libraries ?" << std::endl;
        std::cerr << std::endl;
        std::cerr << "the Typelib transport will not be available for types defined in this typekit" << std::endl;
    }
}

bool orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::registerTransport(std::string type_name, RTT::types::TypeInfo* ti)
{
    if (!m_registry)
        return false;

    <% first_type = true;
       typesets.registered_types.each do |type| %>
    <%= 'else ' unless first_type %>if ("<%= type.name %>" == type_name)
    {
        ti->addProtocol(orogen_transports::TYPELIB_MARSHALLER_ID,
            <%= type.method_name %>_TypelibMarshaller(*m_registry));
        return true;
    }
    <% first_type = false
    end %>
    return false;
}
std::string orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::getTransportName() const
{ return "Typelib"; }
std::string orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::getTypekitName() const
{ return "/orogen/<%= typekit.name %>"; }
std::string orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::getName() const
{ return "/orogen/<%= typekit.name %>/TYPELIB"; }

ORO_TYPEKIT_PLUGIN(orogen_typekits::<%= typekit.name %>TypelibTransportPlugin);

<commit_msg>use the RTT logger for error display in typelib transport plugins<commit_after>/* Generated from orogen/lib/orogen/templates/typekit/typelib/TransportPlugin.cpp */

// First load all RTT interfaces so that we get all "extern template"
// declarations in the TypekitImpl files
#include "Registration.hpp"
#include "TransportPlugin.hpp"
#include <rtt/types/TypekitPlugin.hpp>
#include <typelib/pluginmanager.hh>
#include <utilmm/configfile/pkgconfig.hh>
#include <rtt/Logger.hpp>
using namespace RTT;

#define TYPEKIT_PACKAGE_NAME_aux0(target) #target
#define TYPEKIT_PACKAGE_NAME_aux(target) "<%= typekit.name %>-typekit-" TYPEKIT_PACKAGE_NAME_aux0(target)
#define TYPEKIT_PACKAGE_NAME TYPEKIT_PACKAGE_NAME_aux(OROCOS_TARGET)

orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::<%= typekit.name %>TypelibTransportPlugin()
    : m_registry(0)
{
    try {
        m_registry = Typelib::PluginManager::load("tlb", TYPEKIT_REGISTRY);
    }
    catch(std::exception const& e) {
        log(Error) << "cannot load the typekit's Typelib registry from" << endlog();
        log(Error) << "  " << TYPEKIT_REGISTRY << endlog();
        log(Error) << "remember to do 'make install' before you use the oroGen-generated libraries ?" << endlog();
        log(Error) << endlog();
        log(Error) << "the Typelib transport will not be available for types defined in this typekit" << endlog();
    }
}

bool orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::registerTransport(std::string type_name, RTT::types::TypeInfo* ti)
{
    if (!m_registry)
        return false;

    <% first_type = true;
       typesets.registered_types.each do |type| %>
    <%= 'else ' unless first_type %>if ("<%= type.name %>" == type_name)
    {
        ti->addProtocol(orogen_transports::TYPELIB_MARSHALLER_ID,
            <%= type.method_name %>_TypelibMarshaller(*m_registry));
        return true;
    }
    <% first_type = false
    end %>
    return false;
}
std::string orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::getTransportName() const
{ return "Typelib"; }
std::string orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::getTypekitName() const
{ return "/orogen/<%= typekit.name %>"; }
std::string orogen_typekits::<%= typekit.name %>TypelibTransportPlugin::getName() const
{ return "/orogen/<%= typekit.name %>/TYPELIB"; }

ORO_TYPEKIT_PLUGIN(orogen_typekits::<%= typekit.name %>TypelibTransportPlugin);

<|endoftext|>


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

#include <cmake.h>
#include <sstream>
#include <inttypes.h>
#include <signal.h>
#include <Context.h>
#include <Color.h>
#include <text.h>
#include <util.h>
#include <i18n.h>
#include <CmdSync.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdSync::CmdSync ()
{
  _keyword     = "synchronize";
  _usage       = "task          synchronize [initialize]";
  _description = STRING_CMD_SYNC_USAGE;
  _read_only   = false;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdSync::execute (std::string& output)
{
  int status = 0;
#ifdef HAVE_LIBGNUTLS
  std::stringstream out;

  // Loog for the 'init' keyword to indicate one-time pending.data upload.
  bool first_time_init = false;
  std::vector <std::string> words = context.cli.getWords ();
  for (auto& word : words)
  {
    if (closeEnough ("initialize", word, 4))
    {
      if (!context.config.getBoolean ("confirmation") ||
          confirm (STRING_CMD_SYNC_INIT))
        first_time_init = true;
      else
        throw std::string (STRING_CMD_SYNC_NO_INIT);
    }
  }

  // If no server is set up, quit.
  std::string connection = context.config.get ("taskd.server");
  if (connection == "" ||
      connection.rfind (':') == std::string::npos)
    throw std::string (STRING_CMD_SYNC_NO_SERVER);

  // Obtain credentials.
  std::string credentials_string = context.config.get ("taskd.credentials");
  if (credentials_string == "")
    throw std::string (STRING_CMD_SYNC_BAD_CRED);

  std::vector <std::string> credentials;
  split (credentials, credentials_string, "/");
  if (credentials.size () != 3)
    throw std::string (STRING_CMD_SYNC_BAD_CRED);

  // This was a Boolean value in 2.3.0, and is a tri-state since 2.4.0.
  std::string trust_value = context.config.get ("taskd.trust");
  if (trust_value != "strict" &&
      trust_value != "ignore hostname" &&
      trust_value != "allow all")
    throw std::string (STRING_CMD_SYNC_TRUST_OBS);

  enum TLSClient::trust_level trust = TLSClient::strict;
  if (trust_value  == "allow all")
    trust = TLSClient::allow_all;
  else if (trust_value == "ignore hostname")
    trust = TLSClient::ignore_hostname;

  // CA must exist, if provided.
  File ca (context.config.get ("taskd.ca"));
  if (ca._data != "" && ! ca.exists ())
    throw std::string (STRING_CMD_SYNC_BAD_CA);

  if (trust == TLSClient::allow_all && ca._data != "")
    throw std::string (STRING_CMD_SYNC_TRUST_CA);

  File certificate (context.config.get ("taskd.certificate"));
  if (! certificate.exists ())
    throw std::string (STRING_CMD_SYNC_BAD_CERT);

  File key (context.config.get ("taskd.key"));
  if (! key.exists ())
    throw std::string (STRING_CMD_SYNC_BAD_KEY);

  // If this is a first-time initialization, send pending.data, not
  // backlog.data.
  std::string payload = "";
  int upload_count = 0;
  if (first_time_init)
  {
    // Delete backlog.data.  Because if we're uploading everything, the list of
    // deltas is meaningless.
    context.tdb2.backlog._file.truncate ();

    auto pending = context.tdb2.pending.get_tasks ();
    for (auto& i : pending)
    {
      payload += i.composeJSON () + "\n";
      ++upload_count;
    }
  }
  else
  {
    std::vector <std::string> lines = context.tdb2.backlog.get_lines ();
    for (auto& i : lines)
    {
      if (i[0] == '{')
        ++upload_count;

      payload += i + "\n";
    }
  }

  // Send 'sync' + payload.
  Msg request;
  request.set ("protocol", "v1");
  request.set ("type",     "sync");
  request.set ("org",      credentials[0]);
  request.set ("user",     credentials[1]);
  request.set ("key",      credentials[2]);

  request.setPayload (payload);

  if (context.verbose ("sync"))
    out << format (STRING_CMD_SYNC_PROGRESS, connection)
        << "\n";

  // Ignore harmful signals.
  signal (SIGHUP,    SIG_IGN);
  signal (SIGINT,    SIG_IGN);
  signal (SIGKILL,   SIG_IGN);
  signal (SIGPIPE,   SIG_IGN);
  signal (SIGTERM,   SIG_IGN);
  signal (SIGUSR1,   SIG_IGN);
  signal (SIGUSR2,   SIG_IGN);

  Msg response;
  if (send (connection, ca._data, certificate._data, key._data, trust, request, response))
  {
    std::string code = response.get ("code");
    if (code == "200")
    {
      Color colorAdded    (context.config.get ("color.sync.added"));
      Color colorChanged  (context.config.get ("color.sync.changed"));

      int download_count = 0;
      payload = response.getPayload ();
      std::vector <std::string> lines;
      split (lines, payload, '\n');

      // Load all tasks, but only if necessary.  There is always a sync key in
      // the payload, so if there are two or more lines, then we have merging
      // to perform, otherwise it's just a backlog.data update.
      if (lines.size () > 1)
        context.tdb2.all_tasks ();

      std::string sync_key = "";
      for (auto& line : lines)
      {
        if (line[0] == '{')
        {
          ++download_count;

          Task from_server (line);
          std::string uuid = from_server.get ("uuid");

          // Is it a new task from the server, or an update to an existing one?
          Task dummy;
          if (context.tdb2.get (uuid, dummy))
          {
            if (context.verbose ("sync"))
              out << "  "
                  << colorChanged.colorize (
                       format (STRING_CMD_SYNC_MOD,
                               uuid,
                               from_server.get ("description")))
                  << "\n";
            context.tdb2.modify (from_server, false);
          }
          else
          {
            if (context.verbose ("sync"))
              out << "  "
                  << colorAdded.colorize (
                       format (STRING_CMD_SYNC_ADD,
                               uuid,
                               from_server.get ("description")))
                  << "\n";
            context.tdb2.add (from_server, false);
          }
        }
        else if (line != "")
        {
          sync_key = line;
          context.debug ("Sync key " + sync_key);
        }

        // Otherwise line is blank, so ignore it.
      }

      // Only update everything if there is a new sync_key.  No sync_key means
      // something horrible happened on the other end of the wire.
      if (sync_key != "")
      {
        // Truncate backlog.data, save new sync_key.
        context.tdb2.backlog._file.truncate ();
        context.tdb2.backlog.clear_tasks ();
        context.tdb2.backlog.clear_lines ();
        context.tdb2.backlog.add_line (sync_key + "\n");

        // Present a clear status message.
        if (upload_count == 0 && download_count == 0)
          // Note: should not happen - expect code 201 instead.
          context.footnote (STRING_CMD_SYNC_SUCCESS0);
        else if (upload_count == 0 && download_count > 0)
          context.footnote (format (STRING_CMD_SYNC_SUCCESS2, download_count));
        else if (upload_count > 0 && download_count == 0)
          context.footnote (format (STRING_CMD_SYNC_SUCCESS1, upload_count));
        else if (upload_count > 0 && download_count > 0)
          context.footnote (format (STRING_CMD_SYNC_SUCCESS3, upload_count, download_count));
      }

      status = 0;
    }
    else if (code == "201")
    {
      context.footnote (STRING_CMD_SYNC_SUCCESS_NOP);
      status = 0;
    }
    else if (code == "301")
    {
      std::string new_server = response.get ("info");
      context.config.set ("taskd.server", new_server);
      context.error (STRING_CMD_SYNC_RELOCATE0);
      context.error ("  " + format (STRING_CMD_SYNC_RELOCATE1, new_server));
      status = 2;
    }
    else if (code == "430")
    {
      context.error (STRING_CMD_SYNC_FAIL_ACCOUNT);
      status = 2;
    }
    else
    {
      context.error (format (STRING_CMD_SYNC_FAIL_ERROR,
                             code,
                             response.get ("status")));
      status = 2;
    }

    // Display all errors returned.  This is recommended by the server protocol.
    std::string to_be_displayed = response.get ("messages");
    if (to_be_displayed != "")
    {
      if (context.verbose ("footnote"))
        context.footnote (to_be_displayed);
      else
        context.debug (to_be_displayed);
    }
  }

  // Some kind of low-level error:
  //   - Server down
  //   - Wrong address
  //   - Wrong port
  //   - Firewall
  //   - Network error
  //   - No signal/cable
  else
  {
    context.error (STRING_CMD_SYNC_FAIL_CONNECT);
    status = 1;
  }

  if (context.verbose ("sync"))
    out << "\n";
  output = out.str ();

  // Restore signal handling.
  signal (SIGHUP,    SIG_DFL);
  signal (SIGINT,    SIG_DFL);
  signal (SIGKILL,   SIG_DFL);
  signal (SIGPIPE,   SIG_DFL);
  signal (SIGTERM,   SIG_DFL);
  signal (SIGUSR1,   SIG_DFL);
  signal (SIGUSR2,   SIG_DFL);

#else
  // Without GnuTLS found at compile time, there is no working sync command.
  throw std::string (STRING_CMD_SYNC_NO_TLS);
#endif
  return status;
}

#ifdef HAVE_LIBGNUTLS
////////////////////////////////////////////////////////////////////////////////
bool CmdSync::send (
  const std::string& to,
  const std::string& ca,
  const std::string& certificate,
  const std::string& key,
  const enum TLSClient::trust_level trust,
  const Msg& request,
  Msg& response)
{
  // It is important that the ':' be the *last* colon, in order to support
  // IPv6 addresses.
  auto colon = to.rfind (':');
  if (colon == std::string::npos)
    throw format (STRING_CMD_SYNC_BAD_SERVER, to);

  std::string server = to.substr (0, colon);
  std::string port = to.substr (colon + 1);

  try
  {
    TLSClient client;
    client.debug (context.config.getInteger ("debug.tls"));

    client.trust (trust);
    client.ciphers (context.config.get ("taskd.ciphers"));
    client.init (ca, certificate, key);
    client.connect (server, port);
    client.send (request.serialize () + "\n");

    std::string incoming;
    client.recv (incoming);
    client.bye ();

    response.parse (incoming);
    return true;
  }

  catch (std::string& error)
  {
    context.error (error);
  }

  // Indicate message failed.
  return false;
}
#endif

////////////////////////////////////////////////////////////////////////////////
<commit_msg>CmdSync: Converted from CLI to CLI2<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2006 - 2015, Paul Beckingham, Federico Hernandez.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// http://www.opensource.org/licenses/mit-license.php
//
////////////////////////////////////////////////////////////////////////////////

#include <cmake.h>
#include <sstream>
#include <inttypes.h>
#include <signal.h>
#include <Context.h>
#include <Color.h>
#include <text.h>
#include <util.h>
#include <i18n.h>
#include <CmdSync.h>

extern Context context;

////////////////////////////////////////////////////////////////////////////////
CmdSync::CmdSync ()
{
  _keyword     = "synchronize";
  _usage       = "task          synchronize [initialize]";
  _description = STRING_CMD_SYNC_USAGE;
  _read_only   = false;
  _displays_id = false;
}

////////////////////////////////////////////////////////////////////////////////
int CmdSync::execute (std::string& output)
{
  int status = 0;
#ifdef HAVE_LIBGNUTLS
  std::stringstream out;

  // Loog for the 'init' keyword to indicate one-time pending.data upload.
  bool first_time_init = false;
  std::vector <std::string> words = context.cli2.getWords ();
  for (auto& word : words)
  {
    if (closeEnough ("initialize", word, 4))
    {
      if (!context.config.getBoolean ("confirmation") ||
          confirm (STRING_CMD_SYNC_INIT))
        first_time_init = true;
      else
        throw std::string (STRING_CMD_SYNC_NO_INIT);
    }
  }

  // If no server is set up, quit.
  std::string connection = context.config.get ("taskd.server");
  if (connection == "" ||
      connection.rfind (':') == std::string::npos)
    throw std::string (STRING_CMD_SYNC_NO_SERVER);

  // Obtain credentials.
  std::string credentials_string = context.config.get ("taskd.credentials");
  if (credentials_string == "")
    throw std::string (STRING_CMD_SYNC_BAD_CRED);

  std::vector <std::string> credentials;
  split (credentials, credentials_string, "/");
  if (credentials.size () != 3)
    throw std::string (STRING_CMD_SYNC_BAD_CRED);

  // This was a Boolean value in 2.3.0, and is a tri-state since 2.4.0.
  std::string trust_value = context.config.get ("taskd.trust");
  if (trust_value != "strict" &&
      trust_value != "ignore hostname" &&
      trust_value != "allow all")
    throw std::string (STRING_CMD_SYNC_TRUST_OBS);

  enum TLSClient::trust_level trust = TLSClient::strict;
  if (trust_value  == "allow all")
    trust = TLSClient::allow_all;
  else if (trust_value == "ignore hostname")
    trust = TLSClient::ignore_hostname;

  // CA must exist, if provided.
  File ca (context.config.get ("taskd.ca"));
  if (ca._data != "" && ! ca.exists ())
    throw std::string (STRING_CMD_SYNC_BAD_CA);

  if (trust == TLSClient::allow_all && ca._data != "")
    throw std::string (STRING_CMD_SYNC_TRUST_CA);

  File certificate (context.config.get ("taskd.certificate"));
  if (! certificate.exists ())
    throw std::string (STRING_CMD_SYNC_BAD_CERT);

  File key (context.config.get ("taskd.key"));
  if (! key.exists ())
    throw std::string (STRING_CMD_SYNC_BAD_KEY);

  // If this is a first-time initialization, send pending.data, not
  // backlog.data.
  std::string payload = "";
  int upload_count = 0;
  if (first_time_init)
  {
    // Delete backlog.data.  Because if we're uploading everything, the list of
    // deltas is meaningless.
    context.tdb2.backlog._file.truncate ();

    auto pending = context.tdb2.pending.get_tasks ();
    for (auto& i : pending)
    {
      payload += i.composeJSON () + "\n";
      ++upload_count;
    }
  }
  else
  {
    std::vector <std::string> lines = context.tdb2.backlog.get_lines ();
    for (auto& i : lines)
    {
      if (i[0] == '{')
        ++upload_count;

      payload += i + "\n";
    }
  }

  // Send 'sync' + payload.
  Msg request;
  request.set ("protocol", "v1");
  request.set ("type",     "sync");
  request.set ("org",      credentials[0]);
  request.set ("user",     credentials[1]);
  request.set ("key",      credentials[2]);

  request.setPayload (payload);

  if (context.verbose ("sync"))
    out << format (STRING_CMD_SYNC_PROGRESS, connection)
        << "\n";

  // Ignore harmful signals.
  signal (SIGHUP,    SIG_IGN);
  signal (SIGINT,    SIG_IGN);
  signal (SIGKILL,   SIG_IGN);
  signal (SIGPIPE,   SIG_IGN);
  signal (SIGTERM,   SIG_IGN);
  signal (SIGUSR1,   SIG_IGN);
  signal (SIGUSR2,   SIG_IGN);

  Msg response;
  if (send (connection, ca._data, certificate._data, key._data, trust, request, response))
  {
    std::string code = response.get ("code");
    if (code == "200")
    {
      Color colorAdded    (context.config.get ("color.sync.added"));
      Color colorChanged  (context.config.get ("color.sync.changed"));

      int download_count = 0;
      payload = response.getPayload ();
      std::vector <std::string> lines;
      split (lines, payload, '\n');

      // Load all tasks, but only if necessary.  There is always a sync key in
      // the payload, so if there are two or more lines, then we have merging
      // to perform, otherwise it's just a backlog.data update.
      if (lines.size () > 1)
        context.tdb2.all_tasks ();

      std::string sync_key = "";
      for (auto& line : lines)
      {
        if (line[0] == '{')
        {
          ++download_count;

          Task from_server (line);
          std::string uuid = from_server.get ("uuid");

          // Is it a new task from the server, or an update to an existing one?
          Task dummy;
          if (context.tdb2.get (uuid, dummy))
          {
            if (context.verbose ("sync"))
              out << "  "
                  << colorChanged.colorize (
                       format (STRING_CMD_SYNC_MOD,
                               uuid,
                               from_server.get ("description")))
                  << "\n";
            context.tdb2.modify (from_server, false);
          }
          else
          {
            if (context.verbose ("sync"))
              out << "  "
                  << colorAdded.colorize (
                       format (STRING_CMD_SYNC_ADD,
                               uuid,
                               from_server.get ("description")))
                  << "\n";
            context.tdb2.add (from_server, false);
          }
        }
        else if (line != "")
        {
          sync_key = line;
          context.debug ("Sync key " + sync_key);
        }

        // Otherwise line is blank, so ignore it.
      }

      // Only update everything if there is a new sync_key.  No sync_key means
      // something horrible happened on the other end of the wire.
      if (sync_key != "")
      {
        // Truncate backlog.data, save new sync_key.
        context.tdb2.backlog._file.truncate ();
        context.tdb2.backlog.clear_tasks ();
        context.tdb2.backlog.clear_lines ();
        context.tdb2.backlog.add_line (sync_key + "\n");

        // Present a clear status message.
        if (upload_count == 0 && download_count == 0)
          // Note: should not happen - expect code 201 instead.
          context.footnote (STRING_CMD_SYNC_SUCCESS0);
        else if (upload_count == 0 && download_count > 0)
          context.footnote (format (STRING_CMD_SYNC_SUCCESS2, download_count));
        else if (upload_count > 0 && download_count == 0)
          context.footnote (format (STRING_CMD_SYNC_SUCCESS1, upload_count));
        else if (upload_count > 0 && download_count > 0)
          context.footnote (format (STRING_CMD_SYNC_SUCCESS3, upload_count, download_count));
      }

      status = 0;
    }
    else if (code == "201")
    {
      context.footnote (STRING_CMD_SYNC_SUCCESS_NOP);
      status = 0;
    }
    else if (code == "301")
    {
      std::string new_server = response.get ("info");
      context.config.set ("taskd.server", new_server);
      context.error (STRING_CMD_SYNC_RELOCATE0);
      context.error ("  " + format (STRING_CMD_SYNC_RELOCATE1, new_server));
      status = 2;
    }
    else if (code == "430")
    {
      context.error (STRING_CMD_SYNC_FAIL_ACCOUNT);
      status = 2;
    }
    else
    {
      context.error (format (STRING_CMD_SYNC_FAIL_ERROR,
                             code,
                             response.get ("status")));
      status = 2;
    }

    // Display all errors returned.  This is recommended by the server protocol.
    std::string to_be_displayed = response.get ("messages");
    if (to_be_displayed != "")
    {
      if (context.verbose ("footnote"))
        context.footnote (to_be_displayed);
      else
        context.debug (to_be_displayed);
    }
  }

  // Some kind of low-level error:
  //   - Server down
  //   - Wrong address
  //   - Wrong port
  //   - Firewall
  //   - Network error
  //   - No signal/cable
  else
  {
    context.error (STRING_CMD_SYNC_FAIL_CONNECT);
    status = 1;
  }

  if (context.verbose ("sync"))
    out << "\n";
  output = out.str ();

  // Restore signal handling.
  signal (SIGHUP,    SIG_DFL);
  signal (SIGINT,    SIG_DFL);
  signal (SIGKILL,   SIG_DFL);
  signal (SIGPIPE,   SIG_DFL);
  signal (SIGTERM,   SIG_DFL);
  signal (SIGUSR1,   SIG_DFL);
  signal (SIGUSR2,   SIG_DFL);

#else
  // Without GnuTLS found at compile time, there is no working sync command.
  throw std::string (STRING_CMD_SYNC_NO_TLS);
#endif
  return status;
}

#ifdef HAVE_LIBGNUTLS
////////////////////////////////////////////////////////////////////////////////
bool CmdSync::send (
  const std::string& to,
  const std::string& ca,
  const std::string& certificate,
  const std::string& key,
  const enum TLSClient::trust_level trust,
  const Msg& request,
  Msg& response)
{
  // It is important that the ':' be the *last* colon, in order to support
  // IPv6 addresses.
  auto colon = to.rfind (':');
  if (colon == std::string::npos)
    throw format (STRING_CMD_SYNC_BAD_SERVER, to);

  std::string server = to.substr (0, colon);
  std::string port = to.substr (colon + 1);

  try
  {
    TLSClient client;
    client.debug (context.config.getInteger ("debug.tls"));

    client.trust (trust);
    client.ciphers (context.config.get ("taskd.ciphers"));
    client.init (ca, certificate, key);
    client.connect (server, port);
    client.send (request.serialize () + "\n");

    std::string incoming;
    client.recv (incoming);
    client.bye ();

    response.parse (incoming);
    return true;
  }

  catch (std::string& error)
  {
    context.error (error);
  }

  // Indicate message failed.
  return false;
}
#endif

////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>
#include "CustomObjectExample.h"
#include "NNInputSystem.h"

CustomObjectExample::CustomObjectExample()
{
	m_CustomObject = CustomObject::Create();
	AddChild( m_CustomObject );
}
CustomObjectExample::~CustomObjectExample()
{

}

void CustomObjectExample::Render()
{
	NNObject::Render();
}
void CustomObjectExample::Update( float dTime )
{
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_LEFT ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(-100.f,0.f) * dTime );
	}
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_RIGHT ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(100.f,0.f) * dTime );
	}
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_UP ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(0.f,-100.f) * dTime );
	}
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_DOWN ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(0.f,100.f) * dTime );
	}
}<commit_msg>change obj speed<commit_after>
#include "CustomObjectExample.h"
#include "NNInputSystem.h"

CustomObjectExample::CustomObjectExample()
{
	m_CustomObject = CustomObject::Create();
	AddChild( m_CustomObject );
}
CustomObjectExample::~CustomObjectExample()
{

}

void CustomObjectExample::Render()
{
	NNObject::Render();
}
void CustomObjectExample::Update( float dTime )
{
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_LEFT ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(-50.f,0.f) * dTime );
	}
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_RIGHT ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(50.f,0.f) * dTime );
	}
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_UP ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(0.f,-50.f) * dTime );
	}
	if ( NNInputSystem::GetInstance()->GetKeyState( VK_DOWN ) == KEY_PRESSED )
	{
		m_CustomObject->SetPosition( m_CustomObject->GetPosition() + NNPoint(0.f,50.f) * dTime );
	}
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: selectlabeldialog.hxx,v $
 *
 *  $Revision: 1.1 $
 *
 *  last change: $Author: fs $ $Date: 2001-01-12 11:33:05 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _EXTENSIONS_PROPCTRLR_SELECTLABELDIALOG_HXX_
#define _EXTENSIONS_PROPCTRLR_SELECTLABELDIALOG_HXX_

#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#ifndef _SVTREEBOX_HXX
#include <svtools/svtreebx.hxx>
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _SV_IMAGE_HXX
#include <vcl/image.hxx>
#endif
#ifndef _SV_DIALOG_HXX
#include <vcl/dialog.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertyset.hpp>
#endif
#ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_
#include "modulepcr.hxx"
#endif

//............................................................................
namespace pcr
{
//............................................................................

    //========================================================================
    // OSelectLabelDialog
    //========================================================================
    class OSelectLabelDialog
            :public ModalDialog
            ,public OModuleResourceClient
    {
        FixedText       m_aMainDesc;
        SvTreeListBox   m_aControlTree;
        CheckBox        m_aNoAssignment;
        FixedLine       m_aSeparator;
        OKButton        m_aOk;
        CancelButton    m_aCancel;

        ImageList       m_aModelImages;
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >   m_xControlModel;
        ::rtl::OUString m_sRequiredService;
        Image           m_aRequiredControlImage;
        SvLBoxEntry*    m_pInitialSelection;
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >   m_xInitialLabelControl;

        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >   m_xSelectedControl;
        SvLBoxEntry*    m_pLastSelected;
        sal_Bool        m_bHaveAssignableControl;

    public:
        OSelectLabelDialog(Window* pParent, ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >  _xControlModel);
        ~OSelectLabelDialog();

        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >  GetSelected() const { return m_aNoAssignment.IsChecked() ? ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > () : m_xSelectedControl; }

    protected:
        sal_Int32 InsertEntries(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xContainer, SvLBoxEntry* pContainerEntry);

        DECL_LINK(OnEntrySelected, SvTreeListBox*);
        DECL_LINK(OnNoAssignmentClicked, Button*);
    };

//............................................................................
}   // namespace pcr
//............................................................................

#endif // _EXTENSIONS_PROPCTRLR_SELECTLABELDIALOG_HXX_

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *
 *  Revision 1.0 09.01.01 14:06:24  fs
 ************************************************************************/

<commit_msg>#65293# wrong haeder name<commit_after>/*************************************************************************
 *
 *  $RCSfile: selectlabeldialog.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: obo $ $Date: 2001-01-18 14:04:09 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc..
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _EXTENSIONS_PROPCTRLR_SELECTLABELDIALOG_HXX_
#define _EXTENSIONS_PROPCTRLR_SELECTLABELDIALOG_HXX_

#ifndef _SV_FIXED_HXX
#include <vcl/fixed.hxx>
#endif
#ifndef _SVTREEBOX_HXX
#include <svtools/svtreebx.hxx>
#endif
#ifndef _SV_BUTTON_HXX
#include <vcl/button.hxx>
#endif
#ifndef _SV_IMAGE_HXX
#include <vcl/image.hxx>
#endif
#ifndef _SV_DIALOG_HXX
#include <vcl/dialog.hxx>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _EXTENSIONS_PROPCTRLR_MODULEPRC_HXX_
#include "modulepcr.hxx"
#endif

//............................................................................
namespace pcr
{
//............................................................................

    //========================================================================
    // OSelectLabelDialog
    //========================================================================
    class OSelectLabelDialog
            :public ModalDialog
            ,public OModuleResourceClient
    {
        FixedText       m_aMainDesc;
        SvTreeListBox   m_aControlTree;
        CheckBox        m_aNoAssignment;
        FixedLine       m_aSeparator;
        OKButton        m_aOk;
        CancelButton    m_aCancel;

        ImageList       m_aModelImages;
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >   m_xControlModel;
        ::rtl::OUString m_sRequiredService;
        Image           m_aRequiredControlImage;
        SvLBoxEntry*    m_pInitialSelection;
        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >   m_xInitialLabelControl;

        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >   m_xSelectedControl;
        SvLBoxEntry*    m_pLastSelected;
        sal_Bool        m_bHaveAssignableControl;

    public:
        OSelectLabelDialog(Window* pParent, ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >  _xControlModel);
        ~OSelectLabelDialog();

        ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >  GetSelected() const { return m_aNoAssignment.IsChecked() ? ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > () : m_xSelectedControl; }

    protected:
        sal_Int32 InsertEntries(const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xContainer, SvLBoxEntry* pContainerEntry);

        DECL_LINK(OnEntrySelected, SvTreeListBox*);
        DECL_LINK(OnNoAssignmentClicked, Button*);
    };

//............................................................................
}   // namespace pcr
//............................................................................

#endif // _EXTENSIONS_PROPCTRLR_SELECTLABELDIALOG_HXX_

/*************************************************************************
 * history:
 *  $Log: not supported by cvs2svn $
 *  Revision 1.1  2001/01/12 11:33:05  fs
 *  initial checkin - outsourced the form property browser
 *
 *
 *  Revision 1.0 09.01.01 14:06:24  fs
 ************************************************************************/

<|endoftext|>


<commit_before>#include "Precompiled.hpp"
#include "HttpResponseParser.hpp"

namespace http
{
    HttpResponseParser::HttpResponseParser()
    {
        reset();
    }
    void HttpResponseParser::reset()
    {
        parser_status = NOT_STARTED;
        status_code = 0;
        status_message.clear();
        headers.headers.clear();
        expected_body_len = 0;
        body.clear();
        buffer.clear();
    }
    size_t HttpResponseParser::read(const uint8_t * data, size_t len)
    {
        std::string line;
        auto p = data, end = data + len;

        while (p != end)
        {
            size_t len2 = 0;
            if (parser_status == NOT_STARTED && read_line(&line, &len2, p, end - p))
            {
                assert(buffer.empty());
                parser_status = READING_HEADERS;
                auto ver_end = line.find(' ', 0);
                auto code_end = line.find(' ', ver_end + 1);
                std::string code_str = line.substr(ver_end + 1, code_end - ver_end);
                status_code = std::stoi(code_str);
                status_message = line.substr(code_end + 1);
            }
            p += len2; len2 = 0;

            if (parser_status == READING_HEADERS && read_line(&line, &len2, p, end - p))
            {
                assert(buffer.empty());
                if (line.empty())
                {
                    //end of headers
                    if (headers.get("Transfer-Encoding") == "chunked")
                    {
                        expected_body_len = 0;
                        parser_status = READING_BODY_CHUNKED_LENGTH;
                    }
                    else
                    {
                        auto header_len = headers.find("Content-Length");
                        if (!header_len) throw std::runtime_error("'Content-Length' or 'Transfer-Encoding: chunked' required");
                        expected_body_len = std::stoul(header_len->value);
                        parser_status = READING_BODY;
                    }
                }
                else add_header(line);
            }
            p += len2; len2 = 0;

            if (parser_status == READING_BODY || parser_status == READING_BODY_CHUNKED)
            {
                assert(!buffer.size());
                assert(expected_body_len > 0);
                auto remaining = expected_body_len - body.size();
                size_t len = end - p;
                if (len >= remaining)
                {
                    body.insert(body.end(), p, p + remaining);
                    p += remaining;
                    parser_status = parser_status == READING_BODY ? COMPLETED : READING_BODY_CHUNKED_TERMINATOR;
                    expected_body_len = 0;
                }
                else
                {
                    body.insert(body.end(), p, p + len);
                    p = end;
                }
            }

            if (parser_status == READING_BODY_CHUNKED_TERMINATOR && read_line(&line, &len2, p, end - p))
            {
                if (line.empty()) parser_status = READING_BODY_CHUNKED_LENGTH;
                else throw std::runtime_error("Expected chunk \r\n terminator");
            }
            p += len2; len2 = 0;

            if (parser_status == READING_BODY_CHUNKED_LENGTH && read_line(&line, &len2, p, end - p))
            {
                expected_body_len = std::stoul(line, nullptr, 16);
                if (expected_body_len) parser_status = READING_BODY_CHUNKED;
                else parser_status = READING_TRAILER_HEADERS;
            }
            p += len2; len2 = 0;

            if (parser_status == READING_TRAILER_HEADERS && read_line(&line, &len2, p, end - p))
            {
                assert(buffer.empty());
                if (line.empty()) parser_status = COMPLETED; //end of headers
                else add_header(line);
            }
            p += len2; len2 = 0;
        }

        assert(p > data && p <= end);
        assert(p == end || is_completed());
        return p - data;
    }
    bool HttpResponseParser::read_line(std::string * line, size_t *consumed_len, const uint8_t *data, size_t len)
    {
        //The last byte of buffer might be a \r, and the first byte of data might be a \n
        if (buffer.size() && buffer.back() == '\r' && data[0] == '\n')
        {
            line->assign(buffer.data(), buffer.data() + buffer.size() - 1); //assign, but exclude the \r
            buffer.clear();
            *consumed_len =  1; //1 for the \n
            return true;
        }

        auto p = data;
        auto end = data + len - 1;
        while (true)
        {
            //looking for \r\n, so search for \r first and ignore the last byte
            auto p2 = (const uint8_t*)memchr(p, '\r', end - p);
            if (p2)
            {
                if (p2[1] == '\n')
                {
                    //found end of string
                    line->assign(buffer.data(), buffer.data() + buffer.size());
                    line->insert(line->end(), data, p2);
                    *consumed_len = p2 - data + 2;
                    buffer.clear();
                    return true;
                }
                else
                {
                    //just a \r by itself, look for the next one
                    p = p2 + 1;
                }
            }
            else break; //reached end of buffer
        }
        //not found, so all of data must be part of the line
        buffer.insert(buffer.end(), data, data + len);
        *consumed_len = len;
        return false;
    }

    void HttpResponseParser::add_header(const std::string &line)
    {
        auto colon = line.find(':', 0);
        auto first_val = line.find_first_not_of(' ', colon + 1);
        std::string name = line.substr(0, colon);
        std::string value = line.substr(first_val);
        headers.add(name, value);
    }
}
<commit_msg>Fixed HttpResponseParser::read_line when len is zero<commit_after>#include "Precompiled.hpp"
#include "HttpResponseParser.hpp"

namespace http
{
    HttpResponseParser::HttpResponseParser()
    {
        reset();
    }
    void HttpResponseParser::reset()
    {
        parser_status = NOT_STARTED;
        status_code = 0;
        status_message.clear();
        headers.headers.clear();
        expected_body_len = 0;
        body.clear();
        buffer.clear();
    }
    size_t HttpResponseParser::read(const uint8_t * data, size_t len)
    {
        std::string line;
        auto p = data, end = data + len;

        while (p != end)
        {
            size_t len2 = 0;
            if (parser_status == NOT_STARTED && read_line(&line, &len2, p, end - p))
            {
                assert(buffer.empty());
                parser_status = READING_HEADERS;
                auto ver_end = line.find(' ', 0);
                auto code_end = line.find(' ', ver_end + 1);
                std::string code_str = line.substr(ver_end + 1, code_end - ver_end);
                status_code = std::stoi(code_str);
                status_message = line.substr(code_end + 1);
            }
            p += len2; len2 = 0;

            if (parser_status == READING_HEADERS && read_line(&line, &len2, p, end - p))
            {
                assert(buffer.empty());
                if (line.empty())
                {
                    //end of headers
                    if (headers.get("Transfer-Encoding") == "chunked")
                    {
                        expected_body_len = 0;
                        parser_status = READING_BODY_CHUNKED_LENGTH;
                    }
                    else
                    {
                        auto header_len = headers.find("Content-Length");
                        if (!header_len) throw std::runtime_error("'Content-Length' or 'Transfer-Encoding: chunked' required");
                        expected_body_len = std::stoul(header_len->value);
                        parser_status = READING_BODY;
                    }
                }
                else add_header(line);
            }
            p += len2; len2 = 0;

            if (parser_status == READING_BODY || parser_status == READING_BODY_CHUNKED)
            {
                assert(!buffer.size());
                assert(expected_body_len > 0);
                auto remaining = expected_body_len - body.size();
                size_t len = end - p;
                if (len >= remaining)
                {
                    body.insert(body.end(), p, p + remaining);
                    p += remaining;
                    parser_status = parser_status == READING_BODY ? COMPLETED : READING_BODY_CHUNKED_TERMINATOR;
                    expected_body_len = 0;
                }
                else
                {
                    body.insert(body.end(), p, p + len);
                    p = end;
                }
            }

            if (parser_status == READING_BODY_CHUNKED_TERMINATOR && read_line(&line, &len2, p, end - p))
            {
                if (line.empty()) parser_status = READING_BODY_CHUNKED_LENGTH;
                else throw std::runtime_error("Expected chunk \r\n terminator");
            }
            p += len2; len2 = 0;

            if (parser_status == READING_BODY_CHUNKED_LENGTH && read_line(&line, &len2, p, end - p))
            {
                expected_body_len = std::stoul(line, nullptr, 16);
                if (expected_body_len) parser_status = READING_BODY_CHUNKED;
                else parser_status = READING_TRAILER_HEADERS;
            }
            p += len2; len2 = 0;

            if (parser_status == READING_TRAILER_HEADERS && read_line(&line, &len2, p, end - p))
            {
                assert(buffer.empty());
                if (line.empty()) parser_status = COMPLETED; //end of headers
                else add_header(line);
            }
            p += len2; len2 = 0;
        }

        assert(p > data && p <= end);
        assert(p == end || is_completed());
        return p - data;
    }
    bool HttpResponseParser::read_line(std::string * line, size_t *consumed_len, const uint8_t *data, size_t len)
    {
        if (!len) return false;

        //The last byte of buffer might be a \r, and the first byte of data might be a \n
        if (buffer.size() && buffer.back() == '\r' && data[0] == '\n')
        {
            line->assign(buffer.data(), buffer.data() + buffer.size() - 1); //assign, but exclude the \r
            buffer.clear();
            *consumed_len =  1; //1 for the \n
            return true;
        }

        auto p = data;
        auto end = data + len - 1;
        while (true)
        {
            //looking for \r\n, so search for \r first and ignore the last byte
            auto p2 = (const uint8_t*)memchr(p, '\r', end - p);
            if (p2)
            {
                if (p2[1] == '\n')
                {
                    //found end of string
                    line->assign(buffer.data(), buffer.data() + buffer.size());
                    line->insert(line->end(), data, p2);
                    *consumed_len = p2 - data + 2;
                    buffer.clear();
                    return true;
                }
                else
                {
                    //just a \r by itself, look for the next one
                    p = p2 + 1;
                }
            }
            else break; //reached end of buffer
        }
        //not found, so all of data must be part of the line
        buffer.insert(buffer.end(), data, data + len);
        *consumed_len = len;
        return false;
    }

    void HttpResponseParser::add_header(const std::string &line)
    {
        auto colon = line.find(':', 0);
        auto first_val = line.find_first_not_of(' ', colon + 1);
        std::string name = line.substr(0, colon);
        std::string value = line.substr(first_val);
        headers.add(name, value);
    }
}
<|endoftext|>