<commit_before>/*
 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

/**
 * @file text-scrolling-example.cpp
 * @brief Shows text labels with scrolling text and allows a text label and text field control to be scrolled vertically
 */

// EXTERNAL INCLUDES
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/controls/buttons/button-devel.h>

using namespace Dali;
using namespace Dali::Toolkit;

namespace
{
const Vector2 DESKTOP_SIZE( Vector2( 1440.f, 1600.f ) );
const Vector2 BOX_SIZE( Vector2(330.0f, 80.0f ) );
const Vector2 SCROLLING_BOX_SIZE( Vector2(330.0f, 40.0f ) );
const float MAX_OFFSCREEN_RENDERING_SIZE = 2048.f;
const float SCREEN_BORDER = 5.0f; // Border around screen that Popups and handles will not exceed

enum Labels
{
  SMALL = 1u,
  RTL = 1u << 1,
  LARGE = 1u << 2,
  RTL_LONG = 1u << 4,
  NONE = 1u << 6,
};
}
/**
 * @brief The main class of the demo.
 */
class TextScrollingExample : public ConnectionTracker
{
public:

  TextScrollingExample( Application& application )
  : mApplication( application ),
    mTargetActorPosition(),
    mTargetActorSize(),
    mToggleColor( false )
  {
    // Connect to the Application's Init signal
    mApplication.InitSignal().Connect( this, &TextScrollingExample::Create );
  }

  ~TextScrollingExample()
  {
    // Nothing to do here.
  }

  void CreateBox( const std::string& name, Actor& box, Actor parent, const Vector2& size )
  {
    box.SetName(name);
    box.SetAnchorPoint( AnchorPoint::CENTER );
    box.SetParentOrigin( ParentOrigin::CENTER );
    box.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
    box.SetResizePolicy( ResizePolicy::FIXED, Dimension::WIDTH );
    box.SetSize( size.width, 0.f );
    parent.Add( box );

    Dali::Property::Map border;
    border.Insert( Visual::Property::TYPE,  Visual::BORDER );
    border.Insert( BorderVisual::Property::COLOR,  Color::BLUE );
    border.Insert( BorderVisual::Property::SIZE,  1.f );
    box.SetProperty( Control::Property::BACKGROUND, border );
  }

  void CreateLabel( Actor& label, const std::string text, Actor parent, bool scrollOnStart, PushButton button )
  {
    label = TextLabel::New( text );
    label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    label.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
    label.SetPadding( Padding( 1.0f, 1.0f, 1.0f, 1.0f ) );
    label.SetAnchorPoint( AnchorPoint::CENTER );
    label.SetParentOrigin( ParentOrigin::CENTER );
    parent.Add( label );

    if ( scrollOnStart )
    {
      label.SetProperty(TextLabel::Property::ENABLE_AUTO_SCROLL, true);
    }

    button.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
    button.SetSize(BOX_SIZE.height,BOX_SIZE.height);
    button.SetParentOrigin( ParentOrigin::TOP_RIGHT );
    button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    parent.Add(button);
  }

  /**
   * One-time setup in response to Application InitSignal.
   */
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();
    mStageSize = stage.GetSize();

    stage.KeyEventSignal().Connect(this, &TextScrollingExample::OnKeyEvent);

    // Create Root actor
    Actor rootActor = Actor::New();
    rootActor.SetName("rootActor");
    rootActor.SetResizePolicy( ResizePolicy::FIXED,  Dimension::ALL_DIMENSIONS );
    rootActor.SetSize( mStageSize );
    rootActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );

    stage.Add( rootActor );

    mAnimation = Animation::New( 1.0f );

    const Size mTargetActorSize( mStageSize.width, DESKTOP_SIZE.height );

    // Create Desktop
    Control desktop = Control::New();
    desktop.SetBackgroundColor( Color::WHITE );
    desktop.SetName("desktopActor");
    desktop.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    desktop.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
    desktop.SetSize( mTargetActorSize );

    rootActor.Add( desktop ); // Add desktop (content) to offscreen actor

    // Create Boxes
    Control boxA = Control::New();
    Control boxB = Control::New();
    Control boxC = Control::New();
    Control boxD = Control::New();
    Control boxE = Control::New();

    CreateBox( "boxA", boxA, desktop, BOX_SIZE );
    boxA.SetPosition( 0.0f, -500.0f, 1.0f );

    // Create TextField
    TextField field = TextField::New();
    field.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
    field.SetPadding( Padding( 1.0f, 1.0f, 1.0f, 1.0f ) );
    field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "Enter Folder Name" );
    field.SetProperty( TextField::Property::DECORATION_BOUNDING_BOX, Rect<int>( SCREEN_BORDER, SCREEN_BORDER, mStageSize.width - SCREEN_BORDER*2, mStageSize.height - SCREEN_BORDER*2 ) );
    boxA.Add( field );
    boxA.SetSize(BOX_SIZE);

    CreateBox( "boxB", boxB, desktop, SCROLLING_BOX_SIZE );
    boxB.SetPosition( 0.0f, -400.0f, 1.0f );
    Toolkit::PushButton scrollLargeButton = Toolkit::PushButton::New();
    scrollLargeButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedLarge );
    CreateLabel( mLargeLabel, "A Quick Brown Fox Jumps Over The Lazy Dog", boxB, false ,scrollLargeButton );

    CreateBox( "boxC", boxC, desktop, SCROLLING_BOX_SIZE );
    boxC.SetPosition( 0.0f, -300.0f, 1.0f );
    Toolkit::PushButton scrollSmallButton = Toolkit::PushButton::New();
    scrollSmallButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedSmall );
    CreateLabel( mSmallLabel, "A Quick Brown Fox", boxC , true, scrollSmallButton );
    mSmallLabel.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLACK );
    mSmallLabel.SetProperty( TextLabel::Property::SHADOW_OFFSET, Vector2( 1.0f, 1.0f ) );
    mSmallLabel.SetProperty( TextLabel::Property::SHADOW_COLOR, Color::CYAN );

    CreateBox( "boxD", boxD, desktop, SCROLLING_BOX_SIZE );
    boxD.SetPosition( 0.0f, -200.0f, 1.0f );
    Toolkit::PushButton scrollRtlButton = Toolkit::PushButton::New();
    scrollRtlButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedRtl );
    CreateLabel( mRtlLabel, "مرحبا بالعالم", boxD , true, scrollRtlButton );

    CreateBox( "boxE", boxE, desktop, SCROLLING_BOX_SIZE );
    boxE.SetPosition( 0.0f, -100.0f, 1.0f );
    Toolkit::PushButton scrollRtlLongButton = Toolkit::PushButton::New();
    scrollRtlLongButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedRtlLong );
    CreateLabel( mRtlLongLabel, " مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم", boxE , false, scrollRtlLongButton );
    mRtlLongLabel.SetProperty(TextLabel::Property::AUTO_SCROLL_SPEED, 500);
    mRtlLongLabel.SetProperty(TextLabel::Property::AUTO_SCROLL_GAP, 500);
    mRtlLongLabel.SetProperty(TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3);

    mPanGestureDetector = PanGestureDetector::New();
    mPanGestureDetector.DetectedSignal().Connect(this, &TextScrollingExample::OnPanGesture );
    mPanGestureDetector.Attach( desktop );

    Toolkit::PushButton colorButton = Toolkit::PushButton::New();
    colorButton.SetProperty( Button::Property::TOGGLABLE, true );
    colorButton.SetProperty( DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL, Property::Map().Add ( Visual::Property::TYPE, Visual::COLOR ).Add( ColorVisual::Property::MIX_COLOR, Color::RED ) );
    colorButton.SetProperty( DevelButton::Property::SELECTED_BACKGROUND_VISUAL, Property::Map().Add ( Visual::Property::TYPE, Visual::COLOR ).Add( ColorVisual::Property::MIX_COLOR, Color::BLACK ) );
    colorButton.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
    colorButton.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
    colorButton.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
    colorButton.SetSize(BOX_SIZE.height,BOX_SIZE.height);
    colorButton.ClickedSignal().Connect( this, &TextScrollingExample::OnColorButtonClicked );
    rootActor.Add( colorButton );
  }

  void EnableScrolling( Labels labels )
    {
      Actor label;
      switch( labels )
      {
        case LARGE:
        {
          label = mLargeLabel;
          break;
        }
        case RTL:
        {
          label = mRtlLabel;
          break;
        }
        case SMALL:
        {
          label = mSmallLabel;
          break;
        }
        case RTL_LONG:
        {
          label = mRtlLongLabel;
          break;
        }
        case NONE:
        {
          return;
        }
      }

      if ( labels != NONE )
      {
        Property::Value value = label.GetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL);
        if (value.Get< bool >())
        {
          label.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false  );
        }
        else
        {
          label.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true  );
        }
      }
    }

  bool OnButtonClickedSmall( Toolkit::Button button )
  {
    EnableScrolling( SMALL );
    return true;
  }

  bool OnButtonClickedLarge( Toolkit::Button button )
  {
    EnableScrolling( LARGE );
    return true;
  }

  bool OnButtonClickedRtl( Toolkit::Button button )
  {
    EnableScrolling( RTL );
    return true;
  }

  bool OnButtonClickedRtlLong( Toolkit::Button button )
  {
    EnableScrolling( RTL_LONG );
    return true;
  }

  bool OnColorButtonClicked( Toolkit::Button button )
 {
   Vector4 color = Color::RED;

  if ( mToggleColor )
  {
    color = Color::BLACK;
    mToggleColor = false;
  }
  else
  {
    mToggleColor = true;
  }

  mSmallLabel.SetProperty( TextLabel::Property::SHADOW_COLOR, Color::BLACK );
  mSmallLabel.SetProperty( TextLabel::Property::TEXT_COLOR, color );
  mLargeLabel.SetProperty( TextLabel::Property::TEXT_COLOR, color );
  mRtlLongLabel.SetProperty( TextLabel::Property::TEXT_COLOR, color );

  return true;
 }

  /**
   * Main key event handler
   */
  void OnKeyEvent(const KeyEvent& event)
  {
    if(event.state == KeyEvent::Down)
    {
      if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
      {
        mApplication.Quit();
      }
      else
      {
        if ( event.keyPressedName == "2" )
        {
          mAnimation.AnimateTo( Property( mSmallLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );
          mAnimation.AnimateTo( Property( mLargeLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );
          mAnimation.AnimateTo( Property( mRtlLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );
          mAnimation.AnimateTo( Property( mRtlLongLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );

          mAnimation.Play();
        }
      }
    }
  }

  void OnPanGesture( Actor actor, const PanGesture& gesture )
  {
    if( gesture.state == Gesture::Continuing )
    {
      Vector2 position = Vector2( gesture.displacement );
      mTargetActorPosition.y = mTargetActorPosition.y + position.y;
      mTargetActorPosition.y = std::min( mTargetActorPosition.y, -mTargetActorSize.height );
      mTargetActorPosition.y = std::max( mTargetActorPosition.y, ( mTargetActorSize.height - mStageSize.height*0.25f ) );
      actor.SetPosition( 0.0f, mTargetActorPosition.y );
    }
  }

private:

  Application& mApplication;
  PanGestureDetector mPanGestureDetector;

  Vector2 mTargetActorPosition;
  Vector2 mTargetActorSize;
  Vector2 mStageSize;

  TextLabel mLargeLabel;
  TextLabel mSmallLabel;
  TextLabel mRtlLabel;
  TextLabel mRtlLongLabel;

  Animation mAnimation;

  bool mToggleColor;
};

void RunTest( Application& application )
{
  TextScrollingExample test( application );

  application.MainLoop();
}

/** Entry point for Linux & Tizen applications */
int DALI_EXPORT_API main( int argc, char **argv )
{
  Application application = Application::New( &argc, &argv, DEMO_THEME_PATH );

  RunTest( application );

  return 0;
}
<commit_msg>Text scrolling example use scrolling stop mode(FINISH_LOOP, IMMEDIATE) and loop delay<commit_after>/*
 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
 *
 * 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.
 *
 */

/**
 * @file text-scrolling-example.cpp
 * @brief Shows text labels with scrolling text and allows a text label and text field control to be scrolled vertically
 */

// EXTERNAL INCLUDES
#include <dali-toolkit/dali-toolkit.h>
#include <dali-toolkit/devel-api/controls/buttons/button-devel.h>
#include <dali-toolkit/devel-api/controls/text-controls/text-label-devel.h>

using namespace Dali;
using namespace Dali::Toolkit;

namespace
{
const Vector2 DESKTOP_SIZE( Vector2( 1440.f, 1600.f ) );
const Vector2 BOX_SIZE( Vector2(330.0f, 80.0f ) );
const Vector2 SCROLLING_BOX_SIZE( Vector2(330.0f, 40.0f ) );
const float MAX_OFFSCREEN_RENDERING_SIZE = 2048.f;
const float SCREEN_BORDER = 5.0f; // Border around screen that Popups and handles will not exceed

enum Labels
{
  SMALL = 1u,
  RTL = 1u << 1,
  LARGE = 1u << 2,
  RTL_LONG = 1u << 4,
  NONE = 1u << 6,
};
}
/**
 * @brief The main class of the demo.
 */
class TextScrollingExample : public ConnectionTracker
{
public:

  TextScrollingExample( Application& application )
  : mApplication( application ),
    mTargetActorPosition(),
    mTargetActorSize(),
    mToggleColor( false )
  {
    // Connect to the Application's Init signal
    mApplication.InitSignal().Connect( this, &TextScrollingExample::Create );
  }

  ~TextScrollingExample()
  {
    // Nothing to do here.
  }

  void CreateBox( const std::string& name, Actor& box, Actor parent, const Vector2& size )
  {
    box.SetName(name);
    box.SetAnchorPoint( AnchorPoint::CENTER );
    box.SetParentOrigin( ParentOrigin::CENTER );
    box.SetResizePolicy( ResizePolicy::FIT_TO_CHILDREN, Dimension::HEIGHT );
    box.SetResizePolicy( ResizePolicy::FIXED, Dimension::WIDTH );
    box.SetSize( size.width, 0.f );
    parent.Add( box );

    Dali::Property::Map border;
    border.Insert( Visual::Property::TYPE,  Visual::BORDER );
    border.Insert( BorderVisual::Property::COLOR,  Color::BLUE );
    border.Insert( BorderVisual::Property::SIZE,  1.f );
    box.SetProperty( Control::Property::BACKGROUND, border );
  }

  void CreateLabel( Actor& label, const std::string text, Actor parent, bool scrollOnStart, PushButton button )
  {
    label = TextLabel::New( text );
    label.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::WIDTH );
    label.SetResizePolicy( ResizePolicy::DIMENSION_DEPENDENCY, Dimension::HEIGHT );
    label.SetPadding( Padding( 1.0f, 1.0f, 1.0f, 1.0f ) );
    label.SetAnchorPoint( AnchorPoint::CENTER );
    label.SetParentOrigin( ParentOrigin::CENTER );
    parent.Add( label );

    if ( scrollOnStart )
    {
      label.SetProperty(TextLabel::Property::ENABLE_AUTO_SCROLL, true);
    }

    button.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
    button.SetSize(BOX_SIZE.height,BOX_SIZE.height);
    button.SetParentOrigin( ParentOrigin::TOP_RIGHT );
    button.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    parent.Add(button);
  }

  /**
   * One-time setup in response to Application InitSignal.
   */
  void Create( Application& application )
  {
    Stage stage = Stage::GetCurrent();
    mStageSize = stage.GetSize();

    stage.KeyEventSignal().Connect(this, &TextScrollingExample::OnKeyEvent);

    // Create Root actor
    Actor rootActor = Actor::New();
    rootActor.SetName("rootActor");
    rootActor.SetResizePolicy( ResizePolicy::FIXED,  Dimension::ALL_DIMENSIONS );
    rootActor.SetSize( mStageSize );
    rootActor.SetAnchorPoint( AnchorPoint::TOP_LEFT );

    stage.Add( rootActor );

    mAnimation = Animation::New( 1.0f );

    const Size mTargetActorSize( mStageSize.width, DESKTOP_SIZE.height );

    // Create Desktop
    Control desktop = Control::New();
    desktop.SetBackgroundColor( Color::WHITE );
    desktop.SetName("desktopActor");
    desktop.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    desktop.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
    desktop.SetSize( mTargetActorSize );

    rootActor.Add( desktop ); // Add desktop (content) to offscreen actor

    // Create Boxes
    Control boxA = Control::New();
    Control boxB = Control::New();
    Control boxC = Control::New();
    Control boxD = Control::New();
    Control boxE = Control::New();

    CreateBox( "boxA", boxA, desktop, BOX_SIZE );
    boxA.SetPosition( 0.0f, -500.0f, 1.0f );

    // Create TextField
    TextField field = TextField::New();
    field.SetResizePolicy( ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS );
    field.SetPadding( Padding( 1.0f, 1.0f, 1.0f, 1.0f ) );
    field.SetAnchorPoint( AnchorPoint::TOP_LEFT );
    field.SetProperty( TextField::Property::PLACEHOLDER_TEXT, "Enter Folder Name" );
    field.SetProperty( TextField::Property::DECORATION_BOUNDING_BOX, Rect<int>( SCREEN_BORDER, SCREEN_BORDER, mStageSize.width - SCREEN_BORDER*2, mStageSize.height - SCREEN_BORDER*2 ) );
    boxA.Add( field );
    boxA.SetSize(BOX_SIZE);

    CreateBox( "boxB", boxB, desktop, SCROLLING_BOX_SIZE );
    boxB.SetPosition( 0.0f, -400.0f, 1.0f );
    Toolkit::PushButton scrollLargeButton = Toolkit::PushButton::New();
    scrollLargeButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedLarge );
    CreateLabel( mLargeLabel, "A Quick Brown Fox Jumps Over The Lazy Dog", boxB, false ,scrollLargeButton );

    CreateBox( "boxC", boxC, desktop, SCROLLING_BOX_SIZE );
    boxC.SetPosition( 0.0f, -300.0f, 1.0f );
    Toolkit::PushButton scrollSmallButton = Toolkit::PushButton::New();
    scrollSmallButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedSmall );
    CreateLabel( mSmallLabel, "A Quick Brown Fox", boxC , true, scrollSmallButton );
    mSmallLabel.SetProperty( TextLabel::Property::TEXT_COLOR, Color::BLACK );
    mSmallLabel.SetProperty( TextLabel::Property::SHADOW_OFFSET, Vector2( 1.0f, 1.0f ) );
    mSmallLabel.SetProperty( TextLabel::Property::SHADOW_COLOR, Color::CYAN );

    CreateBox( "boxD", boxD, desktop, SCROLLING_BOX_SIZE );
    boxD.SetPosition( 0.0f, -200.0f, 1.0f );
    Toolkit::PushButton scrollRtlButton = Toolkit::PushButton::New();
    scrollRtlButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedRtl );
    CreateLabel( mRtlLabel, "مرحبا بالعالم", boxD , true, scrollRtlButton );
    mRtlLabel.SetProperty(DevelTextLabel::Property::AUTO_SCROLL_STOP_MODE, DevelTextLabel::AutoScrollStopMode::IMMEDIATE );
    mRtlLabel.SetProperty(DevelTextLabel::Property::AUTO_SCROLL_LOOP_DELAY, 0.3f );

    CreateBox( "boxE", boxE, desktop, SCROLLING_BOX_SIZE );
    boxE.SetPosition( 0.0f, -100.0f, 1.0f );
    Toolkit::PushButton scrollRtlLongButton = Toolkit::PushButton::New();
    scrollRtlLongButton.ClickedSignal().Connect( this, &TextScrollingExample::OnButtonClickedRtlLong );
    CreateLabel( mRtlLongLabel, " مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم", boxE , false, scrollRtlLongButton );
    mRtlLongLabel.SetProperty(TextLabel::Property::AUTO_SCROLL_SPEED, 500);
    mRtlLongLabel.SetProperty(TextLabel::Property::AUTO_SCROLL_GAP, 500);
    mRtlLongLabel.SetProperty(TextLabel::Property::AUTO_SCROLL_LOOP_COUNT, 3);
    mRtlLongLabel.SetProperty(DevelTextLabel::Property::AUTO_SCROLL_STOP_MODE, DevelTextLabel::AutoScrollStopMode::FINISH_LOOP );

    mPanGestureDetector = PanGestureDetector::New();
    mPanGestureDetector.DetectedSignal().Connect(this, &TextScrollingExample::OnPanGesture );
    mPanGestureDetector.Attach( desktop );

    Toolkit::PushButton colorButton = Toolkit::PushButton::New();
    colorButton.SetProperty( Button::Property::TOGGLABLE, true );
    colorButton.SetProperty( DevelButton::Property::UNSELECTED_BACKGROUND_VISUAL, Property::Map().Add ( Visual::Property::TYPE, Visual::COLOR ).Add( ColorVisual::Property::MIX_COLOR, Color::RED ) );
    colorButton.SetProperty( DevelButton::Property::SELECTED_BACKGROUND_VISUAL, Property::Map().Add ( Visual::Property::TYPE, Visual::COLOR ).Add( ColorVisual::Property::MIX_COLOR, Color::BLACK ) );
    colorButton.SetAnchorPoint( AnchorPoint::BOTTOM_CENTER );
    colorButton.SetParentOrigin( ParentOrigin::BOTTOM_CENTER );
    colorButton.SetResizePolicy( ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS );
    colorButton.SetSize(BOX_SIZE.height,BOX_SIZE.height);
    colorButton.ClickedSignal().Connect( this, &TextScrollingExample::OnColorButtonClicked );
    rootActor.Add( colorButton );
  }

  void EnableScrolling( Labels labels )
    {
      Actor label;
      switch( labels )
      {
        case LARGE:
        {
          label = mLargeLabel;
          break;
        }
        case RTL:
        {
          label = mRtlLabel;
          break;
        }
        case SMALL:
        {
          label = mSmallLabel;
          break;
        }
        case RTL_LONG:
        {
          label = mRtlLongLabel;
          break;
        }
        case NONE:
        {
          return;
        }
      }

      if ( labels != NONE )
      {
        Property::Value value = label.GetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL);
        if (value.Get< bool >())
        {
          label.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, false  );
        }
        else
        {
          label.SetProperty( TextLabel::Property::ENABLE_AUTO_SCROLL, true  );
        }
      }
    }

  bool OnButtonClickedSmall( Toolkit::Button button )
  {
    EnableScrolling( SMALL );
    return true;
  }

  bool OnButtonClickedLarge( Toolkit::Button button )
  {
    EnableScrolling( LARGE );
    return true;
  }

  bool OnButtonClickedRtl( Toolkit::Button button )
  {
    EnableScrolling( RTL );
    return true;
  }

  bool OnButtonClickedRtlLong( Toolkit::Button button )
  {
    EnableScrolling( RTL_LONG );
    return true;
  }

  bool OnColorButtonClicked( Toolkit::Button button )
 {
   Vector4 color = Color::RED;

  if ( mToggleColor )
  {
    color = Color::BLACK;
    mToggleColor = false;
  }
  else
  {
    mToggleColor = true;
  }

  mSmallLabel.SetProperty( TextLabel::Property::SHADOW_COLOR, Color::BLACK );
  mSmallLabel.SetProperty( TextLabel::Property::TEXT_COLOR, color );
  mLargeLabel.SetProperty( TextLabel::Property::TEXT_COLOR, color );
  mRtlLongLabel.SetProperty( TextLabel::Property::TEXT_COLOR, color );

  return true;
 }

  /**
   * Main key event handler
   */
  void OnKeyEvent(const KeyEvent& event)
  {
    if(event.state == KeyEvent::Down)
    {
      if( IsKey( event, DALI_KEY_ESCAPE) || IsKey( event, DALI_KEY_BACK ) )
      {
        mApplication.Quit();
      }
      else
      {
        if ( event.keyPressedName == "2" )
        {
          mAnimation.AnimateTo( Property( mSmallLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );
          mAnimation.AnimateTo( Property( mLargeLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );
          mAnimation.AnimateTo( Property( mRtlLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );
          mAnimation.AnimateTo( Property( mRtlLongLabel, Actor::Property::SCALE ), Vector3(1.2f, 1.2f, 0.0f), AlphaFunction::BOUNCE, TimePeriod( 1.0f, 1.0f ) );

          mAnimation.Play();
        }
      }
    }
  }

  void OnPanGesture( Actor actor, const PanGesture& gesture )
  {
    if( gesture.state == Gesture::Continuing )
    {
      Vector2 position = Vector2( gesture.displacement );
      mTargetActorPosition.y = mTargetActorPosition.y + position.y;
      mTargetActorPosition.y = std::min( mTargetActorPosition.y, -mTargetActorSize.height );
      mTargetActorPosition.y = std::max( mTargetActorPosition.y, ( mTargetActorSize.height - mStageSize.height*0.25f ) );
      actor.SetPosition( 0.0f, mTargetActorPosition.y );
    }
  }

private:

  Application& mApplication;
  PanGestureDetector mPanGestureDetector;

  Vector2 mTargetActorPosition;
  Vector2 mTargetActorSize;
  Vector2 mStageSize;

  TextLabel mLargeLabel;
  TextLabel mSmallLabel;
  TextLabel mRtlLabel;
  TextLabel mRtlLongLabel;

  Animation mAnimation;

  bool mToggleColor;
};

void RunTest( Application& application )
{
  TextScrollingExample test( application );

  application.MainLoop();
}

/** Entry point for Linux & Tizen applications */
int DALI_EXPORT_API main( int argc, char **argv )
{
  Application application = Application::New( &argc, &argv, DEMO_THEME_PATH );

  RunTest( application );

  return 0;
}
<|endoftext|>


<commit_before>/**
 * @file main.cc
 *
 * Implementation of the AllkNN executable.  Allows some number of standard
 * options.
 *
 * @author Ryan Curtin
 */
#include <fastlib/fastlib.h>
#include "allknn.h"

#include <string>
#include <errno.h>

#include <armadillo>

using namespace std;

// Define our input parameters that this program will take.
PARAM_MODULE("allknn", "The all-k-nearest-neighbors computation.");
PARAM_STRING_REQ("reference_file", "CSV file containing the reference dataset.",
    "allknn");
PARAM_STRING("query_file", "CSV file containing query points (optional).",
    "allknn", "");
PARAM_STRING_REQ("output_file", "File to output CSV-formatted results into.",
    "allknn");
PARAM_INT("k", "Number of nearest neighbors to compute.", "allknn", 5);
PARAM_INT("leaf_size", "Leaf size for kd-tree calculation.", "allknn", 20);
PARAM_FLAG("single_mode", "If set, use single-tree mode (instead of "
    "dual-tree).", "allknn");
PARAM_FLAG("naive_mode", "If set, use naive computation (no trees).  This "
    "overrides single_mode.", "allknn");

using namespace mlpack;
using namespace mlpack::allknn;

int main(int argc, char *argv[]) {
  // Give IO the command line parameters the user passed in.
  IO::ParseCommandLine(argc, argv);

  std::string reference_file =
      IO::GetValue<std::string>("allknn/reference_file");
  std::string output_file = IO::GetValue<std::string>("allknn/output_file");

  arma::mat reference_data;

  bool single_mode = IO::GetValue<bool>("allknn/single_mode");
  bool naive_mode = IO::GetValue<bool>("allknn/naive_mode");
  index_t knn_options = (single_mode ? AllkNN::MODE_SINGLE : 0) |
      (naive_mode ? AllkNN::NAIVE : 0);

  arma::Col<index_t> neighbors;
  arma::vec distances;

  if (data::Load(reference_file.c_str(), reference_data) == SUCCESS_FAIL)
    IO::Fatal << "Reference file " << reference_file << "not found." << endl;

  IO::Info << "Loaded reference data from " << reference_file << endl;

  // Sanity check on k value: must be greater than 0, must be less than the
  // number of reference points.
  int k = IO::GetValue<int>("allknn/k");
  if ((k <= 0) || (k >= reference_data.n_cols)) {
    IO::Fatal << "Invalid k: " << k << "; must be greater than 0 and less ";
    IO::Fatal << "than the number of reference points (";
    IO::Fatal << reference_data.n_cols << ")." << endl;
  }

  // Sanity check on leaf size.
  if (IO::GetValue<int>("allknn/leaf_size") <= 0) {
    IO::Fatal << "Invalid leaf size: " << IO::GetValue<int>("allknn/leaf_size")
        << endl;
  }

  AllkNN* allknn = NULL;

  if (IO::CheckValue("query_file")) {
    std::string query_file = IO::GetValue<std::string>("query_file");
    arma::mat query_data;

    if (data::Load(query_file.c_str(), query_data) == SUCCESS_FAIL)
      IO::Fatal << "Query file " << query_file << " not found" << endl;

    IO::Info << "Query data loaded from " << query_file << endl;

    IO::Info << "Building query and reference trees..." << endl;
    allknn = new AllkNN(query_data, reference_data, (datanode*) NULL,
        knn_options);

  } else {
    IO::Info << "Building reference tree..." << endl;
    allknn = new AllkNN(reference_data, (datanode*) NULL, knn_options);
  }

  IO::Info << "Tree(s) built." << endl;

  IO::Info << "Computing " << k << " nearest neighbors..." << endl;
  allknn->ComputeNeighbors(neighbors, distances);

  IO::Info << "Neighbors computed." << endl;
  IO::Info << "Exporting results..." << endl;

  // Should be using data::Save or a related function instead of being written
  // by hand.
  FILE *fp = fopen(output_file.c_str(), "w");
  if (fp == NULL) {
    IO::Fatal << "Error while opening " << output_file << ": " <<
        strerror(errno) << endl;
  }

  for(index_t i = 0; i < neighbors.n_elem / k; i++) {
    for(int j = 0; j < k; j++) {
      fprintf(fp, "%"LI"d %"LI"d %lg\n", i, neighbors[i * k + j], distances[i * k + j]);
    }
  }
  fclose(fp);

  delete allknn;
}
<commit_msg>Update program documentation.<commit_after>/**
 * @file main.cc
 *
 * Implementation of the AllkNN executable.  Allows some number of standard
 * options.
 *
 * @author Ryan Curtin
 */
#include <fastlib/fastlib.h>
#include "allknn.h"

#include <string>
#include <errno.h>

#include <armadillo>

using namespace std;

// Information about the program itself.
PROGRAM_INFO("All K-Nearest-Neighbors",
    "This program will calculate the all k-nearest-neighbors of a set of "
    "points. You may specify a separate set of reference points and query "
    "points, or just a reference set which will be used as both the reference "
    "and query set."
    "\n\n"
    "For example, the following will calculate the 5 nearest neighbors of each"
    "point in 'input.csv' and store the results in 'output.csv':"
    "\n\n"
    "$ allknn --allknn/k=5 --allknn/reference_file=input.csv \n"
    "    --allknn/output_file=output.csv");

// Define our input parameters that this program will take.
PARAM_MODULE("allknn",
    "Parameters for the all-k-nearest-neighbors computation.");
PARAM_STRING_REQ("reference_file", "CSV file containing the reference dataset.",
    "allknn");
PARAM_STRING("query_file", "CSV file containing query points (optional).",
    "allknn", "");
PARAM_STRING_REQ("output_file", "File to output CSV-formatted results into.",
    "allknn");
PARAM_INT("k", "Number of nearest neighbors to compute.", "allknn", 5);
PARAM_INT("leaf_size", "Leaf size for kd-tree calculation.", "allknn", 20);
PARAM_FLAG("single_mode", "If set, use single-tree mode (instead of "
    "dual-tree).", "allknn");
PARAM_FLAG("naive_mode", "If set, use naive computation (no trees).  This "
    "overrides single_mode.", "allknn");

using namespace mlpack;
using namespace mlpack::allknn;

int main(int argc, char *argv[]) {
  // Give IO the command line parameters the user passed in.
  IO::ParseCommandLine(argc, argv);

  std::string reference_file =
      IO::GetValue<std::string>("allknn/reference_file");
  std::string output_file = IO::GetValue<std::string>("allknn/output_file");

  arma::mat reference_data;

  bool single_mode = IO::GetValue<bool>("allknn/single_mode");
  bool naive_mode = IO::GetValue<bool>("allknn/naive_mode");
  index_t knn_options = (single_mode ? AllkNN::MODE_SINGLE : 0) |
      (naive_mode ? AllkNN::NAIVE : 0);

  arma::Col<index_t> neighbors;
  arma::vec distances;

  if (data::Load(reference_file.c_str(), reference_data) == SUCCESS_FAIL)
    IO::Fatal << "Reference file " << reference_file << "not found." << endl;

  IO::Info << "Loaded reference data from " << reference_file << endl;

  // Sanity check on k value: must be greater than 0, must be less than the
  // number of reference points.
  int k = IO::GetValue<int>("allknn/k");
  if ((k <= 0) || (k >= reference_data.n_cols)) {
    IO::Fatal << "Invalid k: " << k << "; must be greater than 0 and less ";
    IO::Fatal << "than the number of reference points (";
    IO::Fatal << reference_data.n_cols << ")." << endl;
  }

  // Sanity check on leaf size.
  if (IO::GetValue<int>("allknn/leaf_size") <= 0) {
    IO::Fatal << "Invalid leaf size: " << IO::GetValue<int>("allknn/leaf_size")
        << endl;
  }

  AllkNN* allknn = NULL;

  if (IO::CheckValue("query_file")) {
    std::string query_file = IO::GetValue<std::string>("query_file");
    arma::mat query_data;

    if (data::Load(query_file.c_str(), query_data) == SUCCESS_FAIL)
      IO::Fatal << "Query file " << query_file << " not found" << endl;

    IO::Info << "Query data loaded from " << query_file << endl;

    IO::Info << "Building query and reference trees..." << endl;
    allknn = new AllkNN(query_data, reference_data, (datanode*) NULL,
        knn_options);

  } else {
    IO::Info << "Building reference tree..." << endl;
    allknn = new AllkNN(reference_data, (datanode*) NULL, knn_options);
  }

  IO::Info << "Tree(s) built." << endl;

  IO::Info << "Computing " << k << " nearest neighbors..." << endl;
  allknn->ComputeNeighbors(neighbors, distances);

  IO::Info << "Neighbors computed." << endl;
  IO::Info << "Exporting results..." << endl;

  // Should be using data::Save or a related function instead of being written
  // by hand.
  FILE *fp = fopen(output_file.c_str(), "w");
  if (fp == NULL) {
    IO::Fatal << "Error while opening " << output_file << ": " <<
        strerror(errno) << endl;
  }

  for(index_t i = 0; i < neighbors.n_elem / k; i++) {
    for(int j = 0; j < k; j++) {
      fprintf(fp, "%"LI"d %"LI"d %lg\n", i, neighbors[i * k + j], distances[i * k + j]);
    }
  }
  fclose(fp);

  delete allknn;
}
<|endoftext|>


<commit_before>#include <reactive/coroutine.hpp>
#include <silicium/http/http.hpp>
#include <silicium/fast_variant.hpp>
#include <reactive/total_consumer.hpp>
#include <boost/asio.hpp>
#include <boost/ref.hpp>

namespace rx
{
	using tcp_acceptor_result = Si::fast_variant<
		std::shared_ptr<boost::asio::ip::tcp::socket>, //until socket itself is noexcept-movable
		boost::system::error_code
	>;

	struct tcp_acceptor : observable<tcp_acceptor_result>, boost::noncopyable
	{
		typedef tcp_acceptor_result element_type;

		explicit tcp_acceptor(boost::asio::ip::tcp::acceptor &underlying)
			: underlying(underlying)
		{
		}

		~tcp_acceptor()
		{
			if (!receiver_)
			{
				return;
			}
			underlying.cancel();
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			assert(!receiver_);
			next_client = std::make_shared<boost::asio::ip::tcp::socket>(underlying.get_io_service());
			underlying.async_accept(*next_client, [this](boost::system::error_code error)
			{
				if (!this->receiver_)
				{
					//can happen when cancel has been called on the observable when the callback was
					//already posted to the io_service
					return;
				}
				if (error)
				{
					if (error == boost::asio::error::operation_aborted)
					{
						return;
					}
					exchange(this->receiver_, nullptr)->got_element(tcp_acceptor_result{error});
				}
				else
				{
					exchange(this->receiver_, nullptr)->got_element(tcp_acceptor_result{std::move(next_client)});
				}
			});
			receiver_ = &receiver;
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			underlying.cancel();
			receiver_ = nullptr;
		}

	private:

		boost::asio::ip::tcp::acceptor &underlying;
		std::shared_ptr<boost::asio::ip::tcp::socket> next_client;
		observer<element_type> *receiver_ = nullptr;
	};

	template <class Observable>
	struct observable_source : Si::source<typename Observable::element_type>
	{
		typedef typename Observable::element_type element_type;

		observable_source(Observable input, yield_context<element_type> &yield)
			: input(std::move(input))
			, yield(yield)
		{
		}

		virtual boost::iterator_range<element_type const *> map_next(std::size_t size) SILICIUM_OVERRIDE
		{
			(void)size;
			return {};
		}

		virtual element_type *copy_next(boost::iterator_range<element_type *> destination) SILICIUM_OVERRIDE
		{
			auto i = begin(destination);
			for (; i != end(destination); ++i)
			{
				auto element = yield.get_one(input);
				if (!element)
				{
					break;
				}
				*i = std::move(*element);
			}
			return i;
		}

		virtual boost::uintmax_t minimum_size() SILICIUM_OVERRIDE
		{
			return 0;
		}

		virtual boost::optional<boost::uintmax_t> maximum_size() SILICIUM_OVERRIDE
		{
			return boost::none;
		}

		virtual std::size_t skip(std::size_t count) SILICIUM_OVERRIDE
		{
			size_t skipped = 0;
			while ((skipped < count) && yield.get_one(input))
			{
			}
			return skipped;
		}

	private:

		Observable input;
		yield_context<element_type> &yield;
	};

	template <class Observable, class YieldContext>
	auto make_observable_source(Observable &&input, YieldContext &yield)
	{
		return observable_source<typename std::decay<Observable>::type>(std::forward<Observable>(input), yield);
	}
}

namespace
{
	struct accept_handler : boost::static_visitor<bool>
	{
		bool operator()(std::shared_ptr<boost::asio::ip::tcp::socket> client) const
		{
			return true;
		}

		bool operator()(boost::system::error_code error) const
		{
			return false;
		}
	};
}

int main()
{
	boost::asio::io_service io;
	boost::asio::ip::tcp::acceptor acceptor(io, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), 8080));
	rx::tcp_acceptor clients(acceptor);
	auto handling_clients = rx::make_coroutine<rx::detail::nothing>([&clients](rx::yield_context<rx::detail::nothing> &yield) -> void
	{
		for (;;)
		{
			auto result = yield.get_one(clients);
			if (!result)
			{
				break;
			}
			accept_handler handler;
			bool continue_ = Si::apply_visitor(handler, *result);
			if (!continue_)
			{
				break;
			}

		}
	});
	auto handle_all = rx::make_total_consumer(rx::ref(handling_clients));
	handle_all.start();
	io.run();
}
<commit_msg>write an observable that receives from an asio socket<commit_after>#include <reactive/coroutine.hpp>
#include <silicium/http/http.hpp>
#include <silicium/fast_variant.hpp>
#include <reactive/total_consumer.hpp>
#include <boost/asio.hpp>
#include <boost/ref.hpp>

namespace rx
{
	using tcp_acceptor_result = Si::fast_variant<
		std::shared_ptr<boost::asio::ip::tcp::socket>, //until socket itself is noexcept-movable
		boost::system::error_code
	>;

	struct tcp_acceptor : observable<tcp_acceptor_result>, boost::noncopyable
	{
		typedef tcp_acceptor_result element_type;

		explicit tcp_acceptor(boost::asio::ip::tcp::acceptor &underlying)
			: underlying(underlying)
		{
		}

		~tcp_acceptor()
		{
			if (!receiver_)
			{
				return;
			}
			underlying.cancel();
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			assert(!receiver_);
			next_client = std::make_shared<boost::asio::ip::tcp::socket>(underlying.get_io_service());
			underlying.async_accept(*next_client, [this](boost::system::error_code error)
			{
				if (!this->receiver_)
				{
					//can happen when cancel has been called on the observable when the callback was
					//already posted to the io_service
					return;
				}
				if (error)
				{
					if (error == boost::asio::error::operation_aborted)
					{
						return;
					}
					exchange(this->receiver_, nullptr)->got_element(tcp_acceptor_result{error});
				}
				else
				{
					exchange(this->receiver_, nullptr)->got_element(tcp_acceptor_result{std::move(next_client)});
				}
			});
			receiver_ = &receiver;
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			underlying.cancel();
			receiver_ = nullptr;
		}

	private:

		boost::asio::ip::tcp::acceptor &underlying;
		std::shared_ptr<boost::asio::ip::tcp::socket> next_client;
		observer<element_type> *receiver_ = nullptr;
	};

	template <class Observable>
	struct observable_source : Si::source<typename Observable::element_type>
	{
		typedef typename Observable::element_type element_type;

		observable_source(Observable input, yield_context<element_type> &yield)
			: input(std::move(input))
			, yield(yield)
		{
		}

		virtual boost::iterator_range<element_type const *> map_next(std::size_t size) SILICIUM_OVERRIDE
		{
			(void)size;
			return {};
		}

		virtual element_type *copy_next(boost::iterator_range<element_type *> destination) SILICIUM_OVERRIDE
		{
			auto i = begin(destination);
			for (; i != end(destination); ++i)
			{
				auto element = yield.get_one(input);
				if (!element)
				{
					break;
				}
				*i = std::move(*element);
			}
			return i;
		}

		virtual boost::uintmax_t minimum_size() SILICIUM_OVERRIDE
		{
			return 0;
		}

		virtual boost::optional<boost::uintmax_t> maximum_size() SILICIUM_OVERRIDE
		{
			return boost::none;
		}

		virtual std::size_t skip(std::size_t count) SILICIUM_OVERRIDE
		{
			size_t skipped = 0;
			while ((skipped < count) && yield.get_one(input))
			{
			}
			return skipped;
		}

	private:

		Observable input;
		yield_context<element_type> &yield;
	};

	template <class Observable, class YieldContext>
	auto make_observable_source(Observable &&input, YieldContext &yield)
	{
		return observable_source<typename std::decay<Observable>::type>(std::forward<Observable>(input), yield);
	}

	typedef Si::fast_variant<std::size_t, boost::system::error_code> received_from_socket;

	struct socket_observable : observable<received_from_socket>
	{
		typedef received_from_socket element_type;
		typedef boost::iterator_range<char *> buffer_type;

		socket_observable(boost::asio::ip::tcp::socket &socket, buffer_type buffer)
			: socket(&socket)
			, buffer(buffer)
		{
			assert(!buffer.empty());
		}

		virtual void async_get_one(observer<element_type> &receiver) SILICIUM_OVERRIDE
		{
			assert(!receiver_);
			socket->async_receive(boost::asio::buffer(buffer.begin(), buffer.size()), [this](boost::system::error_code error, std::size_t bytes_received)
			{
				if (error)
				{
					if (error == boost::asio::error::operation_aborted)
					{
						return;
					}
					exchange(this->receiver_, nullptr)->got_element(error);
				}
				else
				{
					exchange(this->receiver_, nullptr)->got_element(bytes_received);
				}
			});
			receiver_ = &receiver;
		}

		virtual void cancel() SILICIUM_OVERRIDE
		{
			assert(receiver_);
			socket->cancel();
			receiver_ = nullptr;
		}

	private:

		boost::asio::ip::tcp::socket *socket;
		buffer_type buffer;
		observer<element_type> *receiver_ = nullptr;
	};
}

namespace
{
	struct accept_handler : boost::static_visitor<rx::detail::nothing>
	{
		rx::detail::nothing operator()(std::shared_ptr<boost::asio::ip::tcp::socket> client) const
		{
			throw std::logic_error("not implemented");
		}

		rx::detail::nothing operator()(boost::system::error_code error) const
		{
			throw std::logic_error("not implemented");
		}
	};
}

int main()
{
	boost::asio::io_service io;
	boost::asio::ip::tcp::acceptor acceptor(io, boost::asio::ip::tcp::endpoint(boost::asio::ip::address_v4(), 8080));
	rx::tcp_acceptor clients(acceptor);
	auto handling_clients = rx::make_coroutine<rx::detail::nothing>([&clients](rx::yield_context<rx::detail::nothing> &yield) -> void
	{
		for (;;)
		{
			auto result = yield.get_one(clients);
			if (!result)
			{
				break;
			}
			accept_handler handler;
			yield(Si::apply_visitor(handler, *result));
		}
	});
	auto all = rx::make_total_consumer(rx::ref(handling_clients));
	all.start();
	io.run();
}
<|endoftext|>


<commit_before>/*************************************************************************************
 *  Copyright (C) 2012 by Alejandro Fiestas Olivares <afiestas@kde.org>              *
 *                                                                                *
 *  This program is free software; you can redistribute it and/or                    *
 *  modify it under the terms of the GNU General Public License                      *
 *  as published by the Free Software Foundation; either version 2                   *
 *  of the License, or (at your option) any later version.                           *
 *                                                                                *
 *  This program is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
 *  GNU General Public License for more details.                                     *
 *                                                                                *
 *  You should have received a copy of the GNU General Public License                *
 *  along with this program; if not, write to the Free Software                      *
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
 *************************************************************************************/

#include "daemon.h"
#include "serializer.h"
#include "generator.h"
#include "device.h"

#include <QtCore/QTimer>

#include <kdebug.h>
#include <kdemacros.h>
#include <kaction.h>
#include <KLocalizedString>
#include <KActionCollection>
#include <KPluginFactory>

#include <kscreen/config.h>
#include <kscreen/configmonitor.h>

K_PLUGIN_FACTORY(KScreenDaemonFactory, registerPlugin<KScreenDaemon>();)
K_EXPORT_PLUGIN(KScreenDaemonFactory("kscreen", "kscreen"))

KScreenDaemon::KScreenDaemon(QObject* parent, const QList< QVariant >& )
 : KDEDModule(parent)
 , m_monitoredConfig(0)
 , m_iteration(0)
 , m_pendingSave(false)
 , m_monitoring(false)
 , m_timer(new QTimer())
{
    setenv("KSCREEN_BACKEND", "XRandR", 1);
    KActionCollection *coll = new KActionCollection(this);
    KAction* action = coll->addAction("display");
    action->setText(i18n("Switch Display" ));
    action->setGlobalShortcut(KShortcut(Qt::Key_Display));

    connect(Device::self(), SIGNAL(lidIsClosedChanged(bool,bool)), SLOT(lidClosedChanged()));

    m_timer->setInterval(300);
    m_timer->setSingleShot(true);
    connect(m_timer, SIGNAL(timeout()), SLOT(applyGenericConfig()));
    connect(action, SIGNAL(triggered(bool)), SLOT(displayButton()));
    connect(Generator::self(), SIGNAL(ready()), SLOT(init()));
    monitorConnectedChange();
}

KScreenDaemon::~KScreenDaemon()
{
    Generator::destroy();
    Device::destroy();
}

void KScreenDaemon::init()
{
    applyConfig();
}

void KScreenDaemon::applyConfig()
{
    kDebug() << "Applying config";
    if (Serializer::configExists()) {
        applyKnownConfig();
        return;
    }

    applyIdealConfig();
}

void KScreenDaemon::applyKnownConfig()
{
    setMonitorForChanges(false);
    KScreen::Config::setConfig(Serializer::config(Serializer::currentId()));
    QMetaObject::invokeMethod(this, "scheduleMonitorChange", Qt::QueuedConnection);
}

void KScreenDaemon::applyIdealConfig()
{
    setMonitorForChanges(true);
    KScreen::Config::setConfig(Generator::self()->idealConfig());
}

void KScreenDaemon::configChanged()
{
    kDebug() << "Change detected";
    if (m_pendingSave) {
        return;
    }

    kDebug() << "Scheduling screen save";
    m_pendingSave = true;
    QMetaObject::invokeMethod(this, "saveCurrentConfig", Qt::QueuedConnection);
}

void KScreenDaemon::saveCurrentConfig()
{
    kDebug() << "Saving current config";
    m_pendingSave = false;
    Serializer::saveConfig(KScreen::Config::current());
}

void KScreenDaemon::displayButton()
{
    kDebug() << "displayBtn triggered";
    if (m_timer->isActive()) {
        kDebug() << "Too fast cowboy";
        return;
    }

    m_timer->start();
}

void KScreenDaemon::resetDisplaySwitch()
{
    kDebug();
    m_iteration = 0;
}

void KScreenDaemon::applyGenericConfig()
{
    if (m_iteration == 5) {
        m_iteration = 0;
    }

    setMonitorForChanges(true);
    m_iteration++;
    kDebug() << "displayButton: " << m_iteration;
    KDebug::Block genericConfig("Applying display switch");
    KScreen::Config::setConfig(Generator::self()->displaySwitch(m_iteration));
}

void KScreenDaemon::lidClosedChanged(bool lidIsClosed)
{
    KDebug::Block genericConfig(" Lid closed");
    kDebug() << "Lid is closed:" << lidIsClosed;
    //If the laptop is closed, use ideal config WITHOUT saving it
    if (lidIsClosed) {
        setMonitorForChanges(false);
        KScreen::Config::setConfig(Generator::self()->idealConfig());
        return;
    }

    //If the lid is open, restore config (or generate a new one if needed
    applyConfig();
}

void KScreenDaemon::monitorConnectedChange()
{
    if (!m_monitoredConfig) {
        m_monitoredConfig = KScreen::Config::current();
        if (!m_monitoredConfig) {
            return;
        }

        KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig);
    }

    KScreen::OutputList outputs = m_monitoredConfig->outputs();
    Q_FOREACH(KScreen::Output* output, outputs) {
        connect(output, SIGNAL(isConnectedChanged()), SLOT(applyConfig()));
        connect(output, SIGNAL(isConnectedChanged()), SLOT(resetDisplaySwitch()));
    }
}

void KScreenDaemon::setMonitorForChanges(bool enabled)
{
    if (m_monitoring == enabled) {
        return;
    }
    kDebug() << "Monitor for changes: " << enabled;
    if (!m_monitoredConfig) {
        m_monitoredConfig = KScreen::Config::current();
        if (!m_monitoredConfig) {
            return;
        }
        KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig);
    }

    m_monitoring = enabled;

    KScreen::OutputList outputs = m_monitoredConfig->outputs();
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (m_monitoring) {
            enableMonitor(output);
        } else {
            disableMonitor(output);
        }
    }
}

void KScreenDaemon::scheduleMonitorChange()
{
    QMetaObject::invokeMethod(this, "setMonitorForChanges", Qt::QueuedConnection, Q_ARG(bool, true));
}

void KScreenDaemon::enableMonitor(KScreen::Output* output)
{
    connect(output, SIGNAL(currentModeChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(isEnabledChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(isPrimaryChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(outputChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(clonesChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(posChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(rotationChanged()), SLOT(configChanged()));
}

void KScreenDaemon::disableMonitor(KScreen::Output* output)
{
    disconnect(output, SIGNAL(currentModeChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(isEnabledChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(isPrimaryChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(outputChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(clonesChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(posChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(rotationChanged()), this, SLOT(configChanged()));
}<commit_msg>Fix runtime warning: No such slot KScreenDaemon::lidClosedChanged()<commit_after>/*************************************************************************************
 *  Copyright (C) 2012 by Alejandro Fiestas Olivares <afiestas@kde.org>              *
 *                                                                                *
 *  This program is free software; you can redistribute it and/or                    *
 *  modify it under the terms of the GNU General Public License                      *
 *  as published by the Free Software Foundation; either version 2                   *
 *  of the License, or (at your option) any later version.                           *
 *                                                                                *
 *  This program is distributed in the hope that it will be useful,                  *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
 *  GNU General Public License for more details.                                     *
 *                                                                                *
 *  You should have received a copy of the GNU General Public License                *
 *  along with this program; if not, write to the Free Software                      *
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
 *************************************************************************************/

#include "daemon.h"
#include "serializer.h"
#include "generator.h"
#include "device.h"

#include <QtCore/QTimer>

#include <kdebug.h>
#include <kdemacros.h>
#include <kaction.h>
#include <KLocalizedString>
#include <KActionCollection>
#include <KPluginFactory>

#include <kscreen/config.h>
#include <kscreen/configmonitor.h>

K_PLUGIN_FACTORY(KScreenDaemonFactory, registerPlugin<KScreenDaemon>();)
K_EXPORT_PLUGIN(KScreenDaemonFactory("kscreen", "kscreen"))

KScreenDaemon::KScreenDaemon(QObject* parent, const QList< QVariant >& )
 : KDEDModule(parent)
 , m_monitoredConfig(0)
 , m_iteration(0)
 , m_pendingSave(false)
 , m_monitoring(false)
 , m_timer(new QTimer())
{
    setenv("KSCREEN_BACKEND", "XRandR", 1);
    KActionCollection *coll = new KActionCollection(this);
    KAction* action = coll->addAction("display");
    action->setText(i18n("Switch Display" ));
    action->setGlobalShortcut(KShortcut(Qt::Key_Display));

    connect(Device::self(), SIGNAL(lidIsClosedChanged(bool,bool)), SLOT(lidClosedChanged(bool)));

    m_timer->setInterval(300);
    m_timer->setSingleShot(true);
    connect(m_timer, SIGNAL(timeout()), SLOT(applyGenericConfig()));
    connect(action, SIGNAL(triggered(bool)), SLOT(displayButton()));
    connect(Generator::self(), SIGNAL(ready()), SLOT(init()));
    monitorConnectedChange();
}

KScreenDaemon::~KScreenDaemon()
{
    Generator::destroy();
    Device::destroy();
}

void KScreenDaemon::init()
{
    applyConfig();
}

void KScreenDaemon::applyConfig()
{
    kDebug() << "Applying config";
    if (Serializer::configExists()) {
        applyKnownConfig();
        return;
    }

    applyIdealConfig();
}

void KScreenDaemon::applyKnownConfig()
{
    setMonitorForChanges(false);
    KScreen::Config::setConfig(Serializer::config(Serializer::currentId()));
    QMetaObject::invokeMethod(this, "scheduleMonitorChange", Qt::QueuedConnection);
}

void KScreenDaemon::applyIdealConfig()
{
    setMonitorForChanges(true);
    KScreen::Config::setConfig(Generator::self()->idealConfig());
}

void KScreenDaemon::configChanged()
{
    kDebug() << "Change detected";
    if (m_pendingSave) {
        return;
    }

    kDebug() << "Scheduling screen save";
    m_pendingSave = true;
    QMetaObject::invokeMethod(this, "saveCurrentConfig", Qt::QueuedConnection);
}

void KScreenDaemon::saveCurrentConfig()
{
    kDebug() << "Saving current config";
    m_pendingSave = false;
    Serializer::saveConfig(KScreen::Config::current());
}

void KScreenDaemon::displayButton()
{
    kDebug() << "displayBtn triggered";
    if (m_timer->isActive()) {
        kDebug() << "Too fast cowboy";
        return;
    }

    m_timer->start();
}

void KScreenDaemon::resetDisplaySwitch()
{
    kDebug();
    m_iteration = 0;
}

void KScreenDaemon::applyGenericConfig()
{
    if (m_iteration == 5) {
        m_iteration = 0;
    }

    setMonitorForChanges(true);
    m_iteration++;
    kDebug() << "displayButton: " << m_iteration;
    KDebug::Block genericConfig("Applying display switch");
    KScreen::Config::setConfig(Generator::self()->displaySwitch(m_iteration));
}

void KScreenDaemon::lidClosedChanged(bool lidIsClosed)
{
    KDebug::Block genericConfig(" Lid closed");
    kDebug() << "Lid is closed:" << lidIsClosed;
    //If the laptop is closed, use ideal config WITHOUT saving it
    if (lidIsClosed) {
        setMonitorForChanges(false);
        KScreen::Config::setConfig(Generator::self()->idealConfig());
        return;
    }

    //If the lid is open, restore config (or generate a new one if needed
    applyConfig();
}

void KScreenDaemon::monitorConnectedChange()
{
    if (!m_monitoredConfig) {
        m_monitoredConfig = KScreen::Config::current();
        if (!m_monitoredConfig) {
            return;
        }

        KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig);
    }

    KScreen::OutputList outputs = m_monitoredConfig->outputs();
    Q_FOREACH(KScreen::Output* output, outputs) {
        connect(output, SIGNAL(isConnectedChanged()), SLOT(applyConfig()));
        connect(output, SIGNAL(isConnectedChanged()), SLOT(resetDisplaySwitch()));
    }
}

void KScreenDaemon::setMonitorForChanges(bool enabled)
{
    if (m_monitoring == enabled) {
        return;
    }
    kDebug() << "Monitor for changes: " << enabled;
    if (!m_monitoredConfig) {
        m_monitoredConfig = KScreen::Config::current();
        if (!m_monitoredConfig) {
            return;
        }
        KScreen::ConfigMonitor::instance()->addConfig(m_monitoredConfig);
    }

    m_monitoring = enabled;

    KScreen::OutputList outputs = m_monitoredConfig->outputs();
    Q_FOREACH(KScreen::Output* output, outputs) {
        if (m_monitoring) {
            enableMonitor(output);
        } else {
            disableMonitor(output);
        }
    }
}

void KScreenDaemon::scheduleMonitorChange()
{
    QMetaObject::invokeMethod(this, "setMonitorForChanges", Qt::QueuedConnection, Q_ARG(bool, true));
}

void KScreenDaemon::enableMonitor(KScreen::Output* output)
{
    connect(output, SIGNAL(currentModeChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(isEnabledChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(isPrimaryChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(outputChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(clonesChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(posChanged()), SLOT(configChanged()));
    connect(output, SIGNAL(rotationChanged()), SLOT(configChanged()));
}

void KScreenDaemon::disableMonitor(KScreen::Output* output)
{
    disconnect(output, SIGNAL(currentModeChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(isEnabledChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(isPrimaryChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(outputChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(clonesChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(posChanged()), this, SLOT(configChanged()));
    disconnect(output, SIGNAL(rotationChanged()), this, SLOT(configChanged()));
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libetonyek project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "IWASnappyStream.h"

#include <cassert>
#include <limits>
#include <utility>
#include <vector>

#include <boost/make_shared.hpp>

#include "IWORKMemoryStream.h"

using std::vector;

namespace libetonyek
{

namespace
{

struct CompressionException
{
};

struct Data
{
  explicit Data(vector<unsigned char> &data);

  vector<unsigned char> &m_data; //! Uncompressed data.
  size_t m_blockStart; //! A position in m_data where data from the current block start.
};

Data::Data(vector<unsigned char> &data)
  : m_data(data)
  , m_blockStart(m_data.size())
{
}

unsigned long readVarlen(const RVNGInputStreamPtr_t &input)
{
  vector<unsigned char> bytes;
  bytes.reserve(8);

  bool cont = true;
  while (!input->isEnd() && cont)
  {
    const unsigned char c = readU8(input);
    bytes.push_back(c & ~0x80);
    cont = c & 0x80;
  }

  if (cont && input->isEnd())
    throw CompressionException();

  unsigned long value = 0;

  for (vector<unsigned char>::const_reverse_iterator it = bytes.rbegin(); it != bytes.rend(); ++it)
  {
    if (std::numeric_limits<unsigned long>::max() - value < *it) // overflow
      throw CompressionException();
    value += *it;
  }

  return value;
}

void appendRef(Data &data, const unsigned offset, const unsigned length)
{
  if (length > data.m_data.size() - data.m_blockStart) // we don't have enough uncompressed data in the current block
    throw CompressionException();

  data.m_data.resize(data.m_data.size() + length);
  const vector<unsigned char>::iterator end = data.m_data.end();
  vector<unsigned char>::iterator dest = data.m_data.end() - length;
  vector<unsigned char>::iterator src = dest - offset;

  if (offset >= length)
  {
    std::copy(src, src + length, dest);
  }
  else // the run is inserted repeatedly
  {
    while (end - dest >= offset) // as long as the whole run fits
    {
      std::copy(src, src + offset, dest);
      dest += offset;
    }
    if (dest != end) // copy the remainder
      std::copy(src, src + (end - dest), dest);
  }
}

bool uncompressBlock(const RVNGInputStreamPtr_t &input, const unsigned long length, vector<unsigned char> &uncompressed)
{
  Data data(uncompressed);

  const unsigned long uncompressedLength = readVarlen(input);
  const size_t maxSize = size_t((std::min)(2 * length, uncompressedLength)); // don't want unbounded allocation
  size_t newSize = data.m_data.size() + maxSize;
  data.m_data.reserve(newSize);

  while (!input->isEnd())
  {
    const unsigned char c = readU8(input);
    switch (c & 0x3)
    {
    case 0: // a run of literals
    {
      unsigned runLength = 0;
      if ((c & 0xf0) == 0xf0)
      {
        const unsigned count = (c >> 2) & 0x3;
        if (count >= 4)
        {
          ETONYEK_DEBUG_MSG(("uncompressBlock: Invalid number of count bytes: %u\n", count));
        }
        for (unsigned shift = 8; shift <= 8 * count; shift += 8)
        {
          const unsigned b = readU8(input);
          runLength += b << shift;
        }
      }
      else
      {
        runLength = (c >> 2) + 1;
      }
      unsigned long bytesRead = 0;
      const unsigned char *const bytes = input->read(runLength, bytesRead);
      if (bytesRead != runLength)
        return false;
      data.m_data.insert(data.m_data.end(), bytes, bytes + runLength);
      break;
    }
    case 1: // near ref
    {
      const unsigned runLength = ((c >> 2) & 0x7) + 4;
      const unsigned high = c >> 5;
      const unsigned low = readU8(input);
      const unsigned offset = (high << 8) | low;
      appendRef(data, offset, runLength);
      break;
    }
    case 2: // far ref
    {
      const unsigned runLength = (c >> 2) + 1;
      const unsigned low = readU8(input);
      const unsigned high = readU8(input);
      const unsigned offset = (high << 8) | low;
      appendRef(data, offset, runLength);
      break;
    }
    case 3: // unknown
      ETONYEK_DEBUG_MSG(("uncompressBlock: Found an unexpected mark value 3\n"));
      return false;
    default:
      assert(0);
    }
  }

  return true;
}

RVNGInputStreamPtr_t uncompress(const RVNGInputStreamPtr_t &input)
{
  vector<unsigned char> data;

  while (!input->isEnd())
  {
    const unsigned long blockLength = readVarlen(input);
    if (!uncompressBlock(input, (std::min)(blockLength, getRemainingLength(input)), data))
      throw CompressionException();
  }

  return boost::make_shared<IWORKMemoryStream>(data);
}

}

IWASnappyStream::IWASnappyStream(const RVNGInputStreamPtr_t &stream)
  : m_stream()
{
  if (0 != stream->seek(0, librevenge::RVNG_SEEK_SET))
    throw EndOfStreamException();

  m_stream = uncompress(stream);
}

IWASnappyStream::~IWASnappyStream()
{
}

bool IWASnappyStream::isStructured()
{
  return false;
}

unsigned IWASnappyStream::subStreamCount()
{
  return 0;
}

const char *IWASnappyStream::subStreamName(unsigned)
{
  return 0;
}

librevenge::RVNGInputStream *IWASnappyStream::getSubStreamByName(const char *)
{
  return 0;
}

librevenge::RVNGInputStream *IWASnappyStream::getSubStreamById(unsigned)
{
  return 0;
}

const unsigned char *IWASnappyStream::read(const unsigned long numBytes, unsigned long &numBytesRead)
{
  return m_stream->read(numBytes, numBytesRead);
}

int IWASnappyStream::seek(long offset, const librevenge::RVNG_SEEK_TYPE seekType)
{
  return m_stream->seek(offset, seekType);
}

long IWASnappyStream::tell()
{
  return m_stream->tell();
}

bool IWASnappyStream::isEnd()
{
  return m_stream->isEnd();
}

}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>add missing function impl.<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libetonyek project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include "IWASnappyStream.h"

#include <cassert>
#include <limits>
#include <utility>
#include <vector>

#include <boost/make_shared.hpp>

#include "IWORKMemoryStream.h"

using std::vector;

namespace libetonyek
{

namespace
{

struct CompressionException
{
};

struct Data
{
  explicit Data(vector<unsigned char> &data);

  vector<unsigned char> &m_data; //! Uncompressed data.
  size_t m_blockStart; //! A position in m_data where data from the current block start.
};

Data::Data(vector<unsigned char> &data)
  : m_data(data)
  , m_blockStart(m_data.size())
{
}

unsigned long readVarlen(const RVNGInputStreamPtr_t &input)
{
  vector<unsigned char> bytes;
  bytes.reserve(8);

  bool cont = true;
  while (!input->isEnd() && cont)
  {
    const unsigned char c = readU8(input);
    bytes.push_back(c & ~0x80);
    cont = c & 0x80;
  }

  if (cont && input->isEnd())
    throw CompressionException();

  unsigned long value = 0;

  for (vector<unsigned char>::const_reverse_iterator it = bytes.rbegin(); it != bytes.rend(); ++it)
  {
    if (std::numeric_limits<unsigned long>::max() - value < *it) // overflow
      throw CompressionException();
    value += *it;
  }

  return value;
}

void appendRef(Data &data, const unsigned offset, const unsigned length)
{
  if (length > data.m_data.size() - data.m_blockStart) // we don't have enough uncompressed data in the current block
    throw CompressionException();

  data.m_data.resize(data.m_data.size() + length);
  const vector<unsigned char>::iterator end = data.m_data.end();
  vector<unsigned char>::iterator dest = data.m_data.end() - length;
  vector<unsigned char>::iterator src = dest - offset;

  if (offset >= length)
  {
    std::copy(src, src + length, dest);
  }
  else // the run is inserted repeatedly
  {
    while (end - dest >= offset) // as long as the whole run fits
    {
      std::copy(src, src + offset, dest);
      dest += offset;
    }
    if (dest != end) // copy the remainder
      std::copy(src, src + (end - dest), dest);
  }
}

bool uncompressBlock(const RVNGInputStreamPtr_t &input, const unsigned long length, vector<unsigned char> &uncompressed)
{
  Data data(uncompressed);

  const unsigned long uncompressedLength = readVarlen(input);
  const size_t maxSize = size_t((std::min)(2 * length, uncompressedLength)); // don't want unbounded allocation
  size_t newSize = data.m_data.size() + maxSize;
  data.m_data.reserve(newSize);

  while (!input->isEnd())
  {
    const unsigned char c = readU8(input);
    switch (c & 0x3)
    {
    case 0: // a run of literals
    {
      unsigned runLength = 0;
      if ((c & 0xf0) == 0xf0)
      {
        const unsigned count = (c >> 2) & 0x3;
        if (count >= 4)
        {
          ETONYEK_DEBUG_MSG(("uncompressBlock: Invalid number of count bytes: %u\n", count));
        }
        for (unsigned shift = 8; shift <= 8 * count; shift += 8)
        {
          const unsigned b = readU8(input);
          runLength += b << shift;
        }
      }
      else
      {
        runLength = (c >> 2) + 1;
      }
      unsigned long bytesRead = 0;
      const unsigned char *const bytes = input->read(runLength, bytesRead);
      if (bytesRead != runLength)
        return false;
      data.m_data.insert(data.m_data.end(), bytes, bytes + runLength);
      break;
    }
    case 1: // near ref
    {
      const unsigned runLength = ((c >> 2) & 0x7) + 4;
      const unsigned high = c >> 5;
      const unsigned low = readU8(input);
      const unsigned offset = (high << 8) | low;
      appendRef(data, offset, runLength);
      break;
    }
    case 2: // far ref
    {
      const unsigned runLength = (c >> 2) + 1;
      const unsigned low = readU8(input);
      const unsigned high = readU8(input);
      const unsigned offset = (high << 8) | low;
      appendRef(data, offset, runLength);
      break;
    }
    case 3: // unknown
      ETONYEK_DEBUG_MSG(("uncompressBlock: Found an unexpected mark value 3\n"));
      return false;
    default:
      assert(0);
    }
  }

  return true;
}

RVNGInputStreamPtr_t uncompress(const RVNGInputStreamPtr_t &input)
{
  vector<unsigned char> data;

  while (!input->isEnd())
  {
    const unsigned long blockLength = readVarlen(input);
    if (!uncompressBlock(input, (std::min)(blockLength, getRemainingLength(input)), data))
      throw CompressionException();
  }

  return boost::make_shared<IWORKMemoryStream>(data);
}

}

IWASnappyStream::IWASnappyStream(const RVNGInputStreamPtr_t &stream)
  : m_stream()
{
  if (0 != stream->seek(0, librevenge::RVNG_SEEK_SET))
    throw EndOfStreamException();

  m_stream = uncompress(stream);
}

IWASnappyStream::~IWASnappyStream()
{
}

bool IWASnappyStream::isStructured()
{
  return false;
}

unsigned IWASnappyStream::subStreamCount()
{
  return 0;
}

const char *IWASnappyStream::subStreamName(unsigned)
{
  return 0;
}

bool IWASnappyStream::existsSubStream(const char *)
{
  return false;
}

librevenge::RVNGInputStream *IWASnappyStream::getSubStreamByName(const char *)
{
  return 0;
}

librevenge::RVNGInputStream *IWASnappyStream::getSubStreamById(unsigned)
{
  return 0;
}

const unsigned char *IWASnappyStream::read(const unsigned long numBytes, unsigned long &numBytesRead)
{
  return m_stream->read(numBytes, numBytesRead);
}

int IWASnappyStream::seek(long offset, const librevenge::RVNG_SEEK_TYPE seekType)
{
  return m_stream->seek(offset, seekType);
}

long IWASnappyStream::tell()
{
  return m_stream->tell();
}

bool IWASnappyStream::isEnd()
{
  return m_stream->isEnd();
}

}

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


<commit_before>#include "fetchers.hh"
#include "store-api.hh"

#include <nlohmann/json.hpp>

namespace nix::fetchers {

std::unique_ptr<std::vector<std::shared_ptr<InputScheme>>> inputSchemes = nullptr;

void registerInputScheme(std::shared_ptr<InputScheme> && inputScheme)
{
    if (!inputSchemes) inputSchemes = std::make_unique<std::vector<std::shared_ptr<InputScheme>>>();
    inputSchemes->push_back(std::move(inputScheme));
}

Input Input::fromURL(const std::string & url)
{
    return fromURL(parseURL(url));
}

static void fixupInput(Input & input)
{
    // Check common attributes.
    input.getType();
    input.getRef();
    if (input.getRev())
        input.immutable = true;
    input.getRevCount();
    input.getLastModified();
    if (input.getNarHash())
        input.immutable = true;
}

Input Input::fromURL(const ParsedURL & url)
{
    for (auto & inputScheme : *inputSchemes) {
        auto res = inputScheme->inputFromURL(url);
        if (res) {
            res->scheme = inputScheme;
            fixupInput(*res);
            return std::move(*res);
        }
    }

    throw Error("input '%s' is unsupported", url.url);
}

Input Input::fromAttrs(Attrs && attrs)
{
    for (auto & inputScheme : *inputSchemes) {
        auto res = inputScheme->inputFromAttrs(attrs);
        if (res) {
            res->scheme = inputScheme;
            fixupInput(*res);
            return std::move(*res);
        }
    }

    Input input;
    input.attrs = attrs;
    fixupInput(input);
    return input;
}

ParsedURL Input::toURL() const
{
    if (!scheme)
        throw Error("cannot show unsupported input '%s'", attrsToJson(attrs));
    return scheme->toURL(*this);
}

std::string Input::to_string() const
{
    return toURL().to_string();
}

Attrs Input::toAttrs() const
{
    return attrs;
}

bool Input::hasAllInfo() const
{
    return getNarHash() && scheme && scheme->hasAllInfo(*this);
}

bool Input::operator ==(const Input & other) const
{
    return attrs == other.attrs;
}

bool Input::contains(const Input & other) const
{
    if (*this == other) return true;
    auto other2(other);
    other2.attrs.erase("ref");
    other2.attrs.erase("rev");
    if (*this == other2) return true;
    return false;
}

std::pair<Tree, Input> Input::fetch(ref<Store> store) const
{
    if (!scheme)
        throw Error("cannot fetch unsupported input '%s'", attrsToJson(toAttrs()));

    /* The tree may already be in the Nix store, or it could be
       substituted (which is often faster than fetching from the
       original source). So check that. */
    if (hasAllInfo()) {
        try {
            auto storePath = computeStorePath(*store);

            store->ensurePath(storePath);

            debug("using substituted/cached input '%s' in '%s'",
                to_string(), store->printStorePath(storePath));

            auto actualPath = store->toRealPath(storePath);

            return {fetchers::Tree(std::move(actualPath), std::move(storePath)), *this};
        } catch (Error & e) {
            debug("substitution of input '%s' failed: %s", to_string(), e.what());
        }
    }

    auto [tree, input] = scheme->fetch(store, *this);

    if (tree.actualPath == "")
        tree.actualPath = store->toRealPath(tree.storePath);

    auto narHash = store->queryPathInfo(tree.storePath)->narHash;
    input.attrs.insert_or_assign("narHash", narHash->to_string(SRI, true));

    if (auto prevNarHash = getNarHash()) {
        if (narHash != *prevNarHash)
            throw Error((unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'",
                to_string(), tree.actualPath, prevNarHash->to_string(SRI, true), narHash->to_string(SRI, true));
    }

    if (auto prevLastModified = getLastModified()) {
        if (input.getLastModified() != prevLastModified)
            throw Error("'lastModified' attribute mismatch in input '%s', expected %d",
                input.to_string(), *prevLastModified);
    }

    if (auto prevRevCount = getRevCount()) {
        if (input.getRevCount() != prevRevCount)
            throw Error("'revCount' attribute mismatch in input '%s', expected %d",
                input.to_string(), *prevRevCount);
    }

    input.immutable = true;

    assert(input.hasAllInfo());

    return {std::move(tree), input};
}

Input Input::applyOverrides(
    std::optional<std::string> ref,
    std::optional<Hash> rev) const
{
    if (!scheme) return *this;
    return scheme->applyOverrides(*this, ref, rev);
}

void Input::clone(const Path & destDir) const
{
    assert(scheme);
    scheme->clone(*this, destDir);
}

std::optional<Path> Input::getSourcePath() const
{
    assert(scheme);
    return scheme->getSourcePath(*this);
}

void Input::markChangedFile(
    std::string_view file,
    std::optional<std::string> commitMsg) const
{
    assert(scheme);
    return scheme->markChangedFile(*this, file, commitMsg);
}

StorePath Input::computeStorePath(Store & store) const
{
    auto narHash = getNarHash();
    if (!narHash)
        throw Error("cannot compute store path for mutable input '%s'", to_string());
    return store.makeFixedOutputPath(FileIngestionMethod::Recursive, *narHash, "source");
}

std::string Input::getType() const
{
    return getStrAttr(attrs, "type");
}

std::optional<Hash> Input::getNarHash() const
{
    if (auto s = maybeGetStrAttr(attrs, "narHash")) {
        auto hash = s->empty() ? Hash(htSHA256) : Hash::parseSRI(*s);
        if (hash.type != htSHA256)
            throw UsageError("narHash must be specified with SRI notation");
        return newHashAllowEmpty(*s, htSHA256);
    }
    return {};
}

std::optional<std::string> Input::getRef() const
{
    if (auto s = maybeGetStrAttr(attrs, "ref"))
        return *s;
    return {};
}

std::optional<Hash> Input::getRev() const
{
    if (auto s = maybeGetStrAttr(attrs, "rev"))
        return Hash::parseAny(*s, htSHA1);
    return {};
}

std::optional<uint64_t> Input::getRevCount() const
{
    if (auto n = maybeGetIntAttr(attrs, "revCount"))
        return *n;
    return {};
}

std::optional<time_t> Input::getLastModified() const
{
    if (auto n = maybeGetIntAttr(attrs, "lastModified"))
        return *n;
    return {};
}

ParsedURL InputScheme::toURL(const Input & input)
{
    throw Error("don't know how to convert input '%s' to a URL", attrsToJson(input.attrs));
}

Input InputScheme::applyOverrides(
    const Input & input,
    std::optional<std::string> ref,
    std::optional<Hash> rev)
{
    if (ref)
        throw Error("don't know how to set branch/tag name of input '%s' to '%s'", input.to_string(), *ref);
    if (rev)
        throw Error("don't know how to set revision of input '%s' to '%s'", input.to_string(), rev->gitRev());
    return input;
}

std::optional<Path> InputScheme::getSourcePath(const Input & input)
{
    return {};
}

void InputScheme::markChangedFile(const Input & input, std::string_view file, std::optional<std::string> commitMsg)
{
    assert(false);
}

void InputScheme::clone(const Input & input, const Path & destDir)
{
    throw Error("do not know how to clone input '%s'", input.to_string());
}

}
<commit_msg>Fix error message and avoid recalculation<commit_after>#include "fetchers.hh"
#include "store-api.hh"

#include <nlohmann/json.hpp>

namespace nix::fetchers {

std::unique_ptr<std::vector<std::shared_ptr<InputScheme>>> inputSchemes = nullptr;

void registerInputScheme(std::shared_ptr<InputScheme> && inputScheme)
{
    if (!inputSchemes) inputSchemes = std::make_unique<std::vector<std::shared_ptr<InputScheme>>>();
    inputSchemes->push_back(std::move(inputScheme));
}

Input Input::fromURL(const std::string & url)
{
    return fromURL(parseURL(url));
}

static void fixupInput(Input & input)
{
    // Check common attributes.
    input.getType();
    input.getRef();
    if (input.getRev())
        input.immutable = true;
    input.getRevCount();
    input.getLastModified();
    if (input.getNarHash())
        input.immutable = true;
}

Input Input::fromURL(const ParsedURL & url)
{
    for (auto & inputScheme : *inputSchemes) {
        auto res = inputScheme->inputFromURL(url);
        if (res) {
            res->scheme = inputScheme;
            fixupInput(*res);
            return std::move(*res);
        }
    }

    throw Error("input '%s' is unsupported", url.url);
}

Input Input::fromAttrs(Attrs && attrs)
{
    for (auto & inputScheme : *inputSchemes) {
        auto res = inputScheme->inputFromAttrs(attrs);
        if (res) {
            res->scheme = inputScheme;
            fixupInput(*res);
            return std::move(*res);
        }
    }

    Input input;
    input.attrs = attrs;
    fixupInput(input);
    return input;
}

ParsedURL Input::toURL() const
{
    if (!scheme)
        throw Error("cannot show unsupported input '%s'", attrsToJson(attrs));
    return scheme->toURL(*this);
}

std::string Input::to_string() const
{
    return toURL().to_string();
}

Attrs Input::toAttrs() const
{
    return attrs;
}

bool Input::hasAllInfo() const
{
    return getNarHash() && scheme && scheme->hasAllInfo(*this);
}

bool Input::operator ==(const Input & other) const
{
    return attrs == other.attrs;
}

bool Input::contains(const Input & other) const
{
    if (*this == other) return true;
    auto other2(other);
    other2.attrs.erase("ref");
    other2.attrs.erase("rev");
    if (*this == other2) return true;
    return false;
}

std::pair<Tree, Input> Input::fetch(ref<Store> store) const
{
    if (!scheme)
        throw Error("cannot fetch unsupported input '%s'", attrsToJson(toAttrs()));

    /* The tree may already be in the Nix store, or it could be
       substituted (which is often faster than fetching from the
       original source). So check that. */
    if (hasAllInfo()) {
        try {
            auto storePath = computeStorePath(*store);

            store->ensurePath(storePath);

            debug("using substituted/cached input '%s' in '%s'",
                to_string(), store->printStorePath(storePath));

            auto actualPath = store->toRealPath(storePath);

            return {fetchers::Tree(std::move(actualPath), std::move(storePath)), *this};
        } catch (Error & e) {
            debug("substitution of input '%s' failed: %s", to_string(), e.what());
        }
    }

    auto [tree, input] = scheme->fetch(store, *this);

    if (tree.actualPath == "")
        tree.actualPath = store->toRealPath(tree.storePath);

    auto narHash = store->queryPathInfo(tree.storePath)->narHash;
    input.attrs.insert_or_assign("narHash", narHash->to_string(SRI, true));

    if (auto prevNarHash = getNarHash()) {
        if (narHash != *prevNarHash)
            throw Error((unsigned int) 102, "NAR hash mismatch in input '%s' (%s), expected '%s', got '%s'",
                to_string(), tree.actualPath, prevNarHash->to_string(SRI, true), narHash->to_string(SRI, true));
    }

    if (auto prevLastModified = getLastModified()) {
        if (input.getLastModified() != prevLastModified)
            throw Error("'lastModified' attribute mismatch in input '%s', expected %d",
                input.to_string(), *prevLastModified);
    }

    if (auto prevRevCount = getRevCount()) {
        if (input.getRevCount() != prevRevCount)
            throw Error("'revCount' attribute mismatch in input '%s', expected %d",
                input.to_string(), *prevRevCount);
    }

    input.immutable = true;

    assert(input.hasAllInfo());

    return {std::move(tree), input};
}

Input Input::applyOverrides(
    std::optional<std::string> ref,
    std::optional<Hash> rev) const
{
    if (!scheme) return *this;
    return scheme->applyOverrides(*this, ref, rev);
}

void Input::clone(const Path & destDir) const
{
    assert(scheme);
    scheme->clone(*this, destDir);
}

std::optional<Path> Input::getSourcePath() const
{
    assert(scheme);
    return scheme->getSourcePath(*this);
}

void Input::markChangedFile(
    std::string_view file,
    std::optional<std::string> commitMsg) const
{
    assert(scheme);
    return scheme->markChangedFile(*this, file, commitMsg);
}

StorePath Input::computeStorePath(Store & store) const
{
    auto narHash = getNarHash();
    if (!narHash)
        throw Error("cannot compute store path for mutable input '%s'", to_string());
    return store.makeFixedOutputPath(FileIngestionMethod::Recursive, *narHash, "source");
}

std::string Input::getType() const
{
    return getStrAttr(attrs, "type");
}

std::optional<Hash> Input::getNarHash() const
{
    if (auto s = maybeGetStrAttr(attrs, "narHash")) {
        auto hash = s->empty() ? Hash(htSHA256) : Hash::parseSRI(*s);
        if (hash.type != htSHA256)
            throw UsageError("narHash must use SHA-256");
        return hash;
    }
    return {};
}

std::optional<std::string> Input::getRef() const
{
    if (auto s = maybeGetStrAttr(attrs, "ref"))
        return *s;
    return {};
}

std::optional<Hash> Input::getRev() const
{
    if (auto s = maybeGetStrAttr(attrs, "rev"))
        return Hash::parseAny(*s, htSHA1);
    return {};
}

std::optional<uint64_t> Input::getRevCount() const
{
    if (auto n = maybeGetIntAttr(attrs, "revCount"))
        return *n;
    return {};
}

std::optional<time_t> Input::getLastModified() const
{
    if (auto n = maybeGetIntAttr(attrs, "lastModified"))
        return *n;
    return {};
}

ParsedURL InputScheme::toURL(const Input & input)
{
    throw Error("don't know how to convert input '%s' to a URL", attrsToJson(input.attrs));
}

Input InputScheme::applyOverrides(
    const Input & input,
    std::optional<std::string> ref,
    std::optional<Hash> rev)
{
    if (ref)
        throw Error("don't know how to set branch/tag name of input '%s' to '%s'", input.to_string(), *ref);
    if (rev)
        throw Error("don't know how to set revision of input '%s' to '%s'", input.to_string(), rev->gitRev());
    return input;
}

std::optional<Path> InputScheme::getSourcePath(const Input & input)
{
    return {};
}

void InputScheme::markChangedFile(const Input & input, std::string_view file, std::optional<std::string> commitMsg)
{
    assert(false);
}

void InputScheme::clone(const Input & input, const Path & destDir)
{
    throw Error("do not know how to clone input '%s'", input.to_string());
}

}
<|endoftext|>