<commit_before>/*
 * Copyright (c) 2014 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.
 *
 */

// CLASS HEADER
#include "frame-time.h"

// INTERNAL INCLUDES
#include <dali/integration-api/debug.h>
#include <dali/integration-api/platform-abstraction.h>

namespace Dali
{

using Integration::PlatformAbstraction;

namespace Internal
{
namespace Adaptor
{

namespace
{
#if defined(DEBUG_ENABLED)
Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME");
#endif

const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u );

const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u );

const float        MICROSECONDS_TO_SECONDS( 0.000001f );

const unsigned int HISTORY_SIZE(3);

// constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
const unsigned int TRUE = 1u;
const unsigned int FALSE = 0u;
} // unnamed namespace

FrameTime::FrameTime( PlatformAbstraction& platform )
: mPlatform( platform ),
  mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
  mLastSyncTime( 0u ),
  mLastSyncTimeAtUpdate( 0u ),
  mLastSyncFrameNumber( 0u ),
  mLastUpdateFrameNumber( 0u ),
  mRunning( TRUE ),
  mFirstFrame( TRUE ),
  writePos( 0u ),
  mExtraUpdatesSinceSync( 0u )
{
  // Clear buffer
  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
  {
    mPreviousUpdateFrames[i] = 0;
  }

  SetLastSyncTime();
  mLastSyncTimeAtUpdate = mLastSyncTime;

  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
}

FrameTime::~FrameTime()
{
}

void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
{
  mMinimumFrameTimeInterval = interval;
}

void FrameTime::SetSyncTime( unsigned int frameNumber )
{
  // Only set the render time if we are running
  if ( mRunning )
  {
    SetLastSyncTime();

    mLastSyncFrameNumber = frameNumber;

    DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, (unsigned int) ( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
  }
}

void FrameTime::Suspend()
{
  mRunning = FALSE;

  // Reset members
  mLastSyncFrameNumber = 0;
  mLastUpdateFrameNumber = 0;
  writePos = 0;
  mExtraUpdatesSinceSync = 0;

  // Clear buffer
  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
  {
    mPreviousUpdateFrames[i] = 0;
  }

  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
}

void FrameTime::Resume()
{
  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );

  SetLastSyncTime();   // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
  mFirstFrame = TRUE;

  mRunning = TRUE;
}

void FrameTime::Sleep()
{
  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );

  // Mimic Suspend behaviour
  Suspend();
}

void FrameTime::WakeUp()
{
  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );

  SetLastSyncTime();
  mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
  mFirstFrame = TRUE;
  mRunning = TRUE;
}

void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
{
  if ( mRunning )
  {
    const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
    const uint64_t lastSyncTime( mLastSyncTime );
    const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );

    float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0.
    unsigned int framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time.

    unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
    lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;

    // We should only evaluate the previous frame values if this is not the first frame.
    if ( !mFirstFrame )
    {
      // Check whether we have had any Syncs since we last did an Update.
      if ( framesInLastUpdate == 0 )
      {
        // We have had another update before a Sync, increment counter.
        ++mExtraUpdatesSinceSync;

        // This update frame will be rendered mUpdatesSinceSync later.
        framesTillNextSync += mExtraUpdatesSinceSync;
        DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
      }
      else
      {
        mExtraUpdatesSinceSync = 0;
      }

      // If more than one frame elapsed since last Update, then check if this is a recurring theme so we can accurately predict when this Update is rendered.
      if ( framesInLastUpdate > 1 )
      {
        DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate);
        unsigned int average(0);
        for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
        {
          average += mPreviousUpdateFrames[i];
        }
        average /= HISTORY_SIZE;

        if ( average > 1 )
        {
          // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
          framesTillNextSync = average;
        }
      }

      // Write the number of frames the last update took to the array.
      mPreviousUpdateFrames[writePos] = framesInLastUpdate;
      writePos = ( writePos + 1 ) % HISTORY_SIZE;
    }

    mLastUpdateFrameNumber = lastSyncFrameNumber;
    mLastSyncTimeAtUpdate = lastSyncTime;
    mFirstFrame = FALSE;

    // Calculate the time till the next render
    unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );

    // Set the input variables
    lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
    lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
    nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;

    DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds );
    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                      FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync );
  }
}

inline void FrameTime::SetLastSyncTime()
{
  unsigned int seconds( 0u );
  unsigned int microseconds( 0u );

  mPlatform.GetTimeMicroseconds( seconds, microseconds );

  mLastSyncTime = ( seconds * MICROSECONDS_PER_SECOND ) + microseconds;
}

} // namespace Adaptor
} // namespace Internal
} // namespace Dali
<commit_msg>Fixed overflow error with time values<commit_after>/*
 * Copyright (c) 2014 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.
 *
 */

// CLASS HEADER
#include "frame-time.h"

// INTERNAL INCLUDES
#include <dali/integration-api/debug.h>
#include <dali/integration-api/platform-abstraction.h>

namespace Dali
{

using Integration::PlatformAbstraction;

namespace Internal
{
namespace Adaptor
{

namespace
{
#if defined(DEBUG_ENABLED)
Integration::Log::Filter* gLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FRAME_TIME");
#endif

const unsigned int DEFAULT_MINIMUM_FRAME_TIME_INTERVAL( 16667u );

const unsigned int MICROSECONDS_PER_SECOND( 1000000u );
const unsigned int MICROSECONDS_PER_MILLISECOND( 1000u );

const float        MICROSECONDS_TO_SECONDS( 0.000001f );

const unsigned int HISTORY_SIZE(3);

// constants to keep code readability with unsigned int has to be used as boolean (due to multithreading)
const unsigned int TRUE = 1u;
const unsigned int FALSE = 0u;
} // unnamed namespace

FrameTime::FrameTime( PlatformAbstraction& platform )
: mPlatform( platform ),
  mMinimumFrameTimeInterval( DEFAULT_MINIMUM_FRAME_TIME_INTERVAL ),
  mLastSyncTime( 0u ),
  mLastSyncTimeAtUpdate( 0u ),
  mLastSyncFrameNumber( 0u ),
  mLastUpdateFrameNumber( 0u ),
  mRunning( TRUE ),
  mFirstFrame( TRUE ),
  writePos( 0u ),
  mExtraUpdatesSinceSync( 0u )
{
  // Clear buffer
  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
  {
    mPreviousUpdateFrames[i] = 0;
  }

  SetLastSyncTime();
  mLastSyncTimeAtUpdate = mLastSyncTime;

  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime Initialized\n" );
}

FrameTime::~FrameTime()
{
}

void FrameTime::SetMinimumFrameTimeInterval( unsigned int interval )
{
  mMinimumFrameTimeInterval = interval;
}

void FrameTime::SetSyncTime( unsigned int frameNumber )
{
  // Only set the render time if we are running
  if ( mRunning )
  {
    SetLastSyncTime();

    mLastSyncFrameNumber = frameNumber;

    DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: SetSyncTime(): Frame: %u: Time: %u\n", mLastSyncFrameNumber, (unsigned int) ( mLastSyncTime / MICROSECONDS_PER_MILLISECOND ) );
  }
}

void FrameTime::Suspend()
{
  mRunning = FALSE;

  // Reset members
  mLastSyncFrameNumber = 0;
  mLastUpdateFrameNumber = 0;
  writePos = 0;
  mExtraUpdatesSinceSync = 0;

  // Clear buffer
  for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
  {
    mPreviousUpdateFrames[i] = 0;
  }

  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Suspended\n" );
}

void FrameTime::Resume()
{
  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Resuming\n" );

  SetLastSyncTime();   // Should only update the last Sync time so the elapsed time during suspension is taken into consideration when we next update.
  mFirstFrame = TRUE;

  mRunning = TRUE;
}

void FrameTime::Sleep()
{
  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Sleeping\n" );

  // Mimic Suspend behaviour
  Suspend();
}

void FrameTime::WakeUp()
{
  DALI_LOG_INFO( gLogFilter, Debug::Concise, "FrameTime: Waking Up\n" );

  SetLastSyncTime();
  mLastSyncTimeAtUpdate = mLastSyncTime; // We do not want any animations to progress as we have just been woken up.
  mFirstFrame = TRUE;
  mRunning = TRUE;
}

void FrameTime::PredictNextSyncTime( float& lastFrameDeltaSeconds, unsigned int& lastSyncTimeMilliseconds, unsigned int& nextSyncTimeMilliseconds )
{
  if ( mRunning )
  {
    const unsigned int minimumFrameTimeInterval( mMinimumFrameTimeInterval );
    const uint64_t lastSyncTime( mLastSyncTime );
    const unsigned int lastSyncFrameNumber( mLastSyncFrameNumber );

    float lastFrameDelta( 0.0f ); // Assume the last update frame delta is 0.
    unsigned int framesTillNextSync( 1 ); // Assume next render will be in one Sync frame time.

    unsigned int framesInLastUpdate( lastSyncFrameNumber - mLastUpdateFrameNumber );
    lastFrameDelta = lastSyncTime - mLastSyncTimeAtUpdate;

    // We should only evaluate the previous frame values if this is not the first frame.
    if ( !mFirstFrame )
    {
      // Check whether we have had any Syncs since we last did an Update.
      if ( framesInLastUpdate == 0 )
      {
        // We have had another update before a Sync, increment counter.
        ++mExtraUpdatesSinceSync;

        // This update frame will be rendered mUpdatesSinceSync later.
        framesTillNextSync += mExtraUpdatesSinceSync;
        DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime UpdateBeforeSync\n");
      }
      else
      {
        mExtraUpdatesSinceSync = 0;
      }

      // If more than one frame elapsed since last Update, then check if this is a recurring theme so we can accurately predict when this Update is rendered.
      if ( framesInLastUpdate > 1 )
      {
        DALI_LOG_INFO(gLogFilter, Debug::Concise, "PredictNextSyncTime framesInLastUpdate:%u\n", framesInLastUpdate);
        unsigned int average(0);
        for ( unsigned int i = 0; i < HISTORY_SIZE; ++i )
        {
          average += mPreviousUpdateFrames[i];
        }
        average /= HISTORY_SIZE;

        if ( average > 1 )
        {
          // Our average shows a recurring theme, we are missing frames when rendering so calculate number of frames this will take.
          framesTillNextSync = average;
        }
      }

      // Write the number of frames the last update took to the array.
      mPreviousUpdateFrames[writePos] = framesInLastUpdate;
      writePos = ( writePos + 1 ) % HISTORY_SIZE;
    }

    mLastUpdateFrameNumber = lastSyncFrameNumber;
    mLastSyncTimeAtUpdate = lastSyncTime;
    mFirstFrame = FALSE;

    // Calculate the time till the next render
    unsigned int timeTillNextRender( minimumFrameTimeInterval * framesTillNextSync );

    // Set the input variables
    lastFrameDeltaSeconds = lastFrameDelta * MICROSECONDS_TO_SECONDS;
    lastSyncTimeMilliseconds = lastSyncTime / MICROSECONDS_PER_MILLISECOND;
    nextSyncTimeMilliseconds = ( lastSyncTime + timeTillNextRender ) / MICROSECONDS_PER_MILLISECOND;

    DALI_LOG_INFO( gLogFilter, Debug::General, "FrameTime: Frame: %u, Time: %u, NextTime: %u, LastDelta: %f\n", mLastUpdateFrameNumber, lastSyncTimeMilliseconds, nextSyncTimeMilliseconds, lastFrameDeltaSeconds );
    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                      FramesInLastUpdate: %u, FramesTillNextSync: %u\n", framesInLastUpdate, framesTillNextSync );
  }
}

inline void FrameTime::SetLastSyncTime()
{
  unsigned int seconds( 0u );
  unsigned int microseconds( 0u );

  mPlatform.GetTimeMicroseconds( seconds, microseconds );

  mLastSyncTime = seconds; // Promote from 32 bit to 64 bit value
  mLastSyncTime = ( mLastSyncTime * MICROSECONDS_PER_SECOND ) + microseconds;
}

} // namespace Adaptor
} // namespace Internal
} // namespace Dali
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX600 グループ・省電力制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "RX600/system.hpp"
#include "RX600/peripheral.hpp"
#include "common/static_holder.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  省電力制御クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class power_cfg {

		struct pad_t {

			uint8_t		cmt_;
			uint8_t		tpu_;

			pad_t() : cmt_(0), tpu_(0) { }
		};

		typedef utils::static_holder<pad_t> STH;

		static void set_(bool f, uint8_t& pad, peripheral org, peripheral tgt)
		{
			if(f) {
				pad |= 1 << (static_cast<uint16_t>(tgt) - static_cast<uint16_t>(org));
			} else {
				pad &= ~(1 << (static_cast<uint16_t>(tgt) - static_cast<uint16_t>(org)));
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  周辺機器に切り替える
			@param[in]	t	周辺機器タイプ
			@param[in]	ena	オフにする場合「false」
		*/
		//-----------------------------------------------------------------//
		static void turn(peripheral t, bool ena = true)
		{
			bool f = !ena;
			switch(t) {
			case peripheral::CMT0:
			case peripheral::CMT1:
				// CMT0, CMT1 のストップ状態設定
				set_(ena, STH::st.cmt_, peripheral::CMT0, t);
				SYSTEM::MSTPCRA.MSTPA15 = ((STH::st.cmt_ & 0b0011) == 0);
				break;
			case peripheral::CMT2:
			case peripheral::CMT3:
				// CMT2, CMT3 のストップ状態設定
				set_(ena, STH::st.cmt_, peripheral::CMT0, t);
				SYSTEM::MSTPCRA.MSTPA14 = ((STH::st.cmt_ & 0b1100) == 0);
				break;

			case peripheral::TPU0:
			case peripheral::TPU1:
			case peripheral::TPU2:
			case peripheral::TPU3:
			case peripheral::TPU4:
			case peripheral::TPU5:
				// TPU0 to TPU5 のストップ状態設定
				set_(ena, STH::st.tpu_, peripheral::TPU0, t);
				SYSTEM::MSTPCRA.MSTPA13 = (STH::st.tpu_ == 0);
				break;

			case peripheral::S12AD:
				SYSTEM::MSTPCRA.MSTPA17 = f;	// S12AD のストップ状態解除
				break;
			case peripheral::S12AD1:
				SYSTEM::MSTPCRA.MSTPA16 = f;	// S12AD1 のストップ状態解除
				break;

			case peripheral::R12DA:
				SYSTEM::MSTPCRA.MSTPA19 = f;	// R12DA のストップ状態解除
				break;

			case peripheral::DTC:
				SYSTEM::MSTPCRA.MSTPA28 = f;	// DMAC/DTC のストップ状態解除
				break;

			case peripheral::SCI0:
				SYSTEM::MSTPCRB.MSTPB31 = f;	// B31 (SCI0)のストップ状態解除
				break;
			case peripheral::SCI1:
				SYSTEM::MSTPCRB.MSTPB30 = f;	// B30 (SCI1)のストップ状態解除
				break;
			case peripheral::SCI2:
				SYSTEM::MSTPCRB.MSTPB29 = f;	// B29 (SCI2)のストップ状態解除
				break;
			case peripheral::SCI3:
				SYSTEM::MSTPCRB.MSTPB28 = f;	// B28 (SCI3)のストップ状態解除
				break;
			case peripheral::SCI4:
				SYSTEM::MSTPCRB.MSTPB27 = f;	// B27 (SCI4)のストップ状態解除
				break;
			case peripheral::SCI5:
				SYSTEM::MSTPCRB.MSTPB26 = f;	// B26 (SCI5)のストップ状態解除
				break;
			case peripheral::SCI6:
				SYSTEM::MSTPCRB.MSTPB25 = f;	// B25 (SCI6)のストップ状態解除
				break;
			case peripheral::SCI7:
				SYSTEM::MSTPCRB.MSTPB24 = f;	// B24 (SCI7)のストップ状態解除
				break;

			case peripheral::SCI12:
				SYSTEM::MSTPCRB.MSTPB4 = f;		// B-B4 (SCI12)のストップ状態解除
				break;
#if defined(SIG_RX64M) || defined(SIG_RX71M)
			case peripheral::SCIF8:
				SYSTEM::MSTPCRC.MSTPC27 = f;	// C-B27 (SCIF8)のストップ状態解除
				break;
			case peripheral::SCIF9:
				SYSTEM::MSTPCRC.MSTPC26 = f;	// C-B26 (SCIF9)のストップ状態解除
				break;
			case peripheral::SCIF10:
				SYSTEM::MSTPCRC.MSTPC25 = f;	// C-B25 (SCIF10のストップ状態解除
				break;
			case peripheral::SCIF11:
				SYSTEM::MSTPCRC.MSTPC24 = f;	// C-B24 (SCIF11のストップ状態解除
				break;
#elif defined(SIG_RX65N)
			case peripheral::SCI8:
				SYSTEM::MSTPCRC.MSTPC27 = f;	// C-B27 (SCI8)のストップ状態解除
				break;
			case peripheral::SCI9:
				SYSTEM::MSTPCRC.MSTPC26 = f;	// C-B26 (SCI9)のストップ状態解除
				break;
			case peripheral::SCI10:
				SYSTEM::MSTPCRC.MSTPC25 = f;	// C-B25 (SCI10のストップ状態解除
				break;
			case peripheral::SCI11:
				SYSTEM::MSTPCRC.MSTPC24 = f;	// C-B24 (SCI11のストップ状態解除
				break;
#endif
#if defined(SIG_RX64M) || defined(SIG_RX71M)
			case peripheral::RSPI:
#elif defined(SIG_RX65N)
			case peripheral::RSPI0:
				SYSTEM::MSTPCRB.MSTPB17 = f;	// RSPI のストップ状態解除
				break;
			case peripheral::RSPI1:
				SYSTEM::MSTPCRB.MSTPB16 = f;	// RSPI のストップ状態解除
				break;
#endif

			case peripheral::SDHI:
				SYSTEM::MSTPCRD.MSTPD19 = f;	// SDHI のストップ状態解除
				break;

			case peripheral::ETHERC0:
			case peripheral::ETHERCA:
			case peripheral::EDMAC0:
				SYSTEM::MSTPCRB.MSTPB15 = f;	// ETHER0, EDMAC0 のストップ状態解除
				BUS::BEREN.TOEN = 1;
				break;
			case peripheral::ETHERC1:
			case peripheral::EDMAC1:
				SYSTEM::MSTPCRB.MSTPB14 = f;	// ETHER1, EDMAC1 のストップ状態解除
				BUS::BEREN.TOEN = 1;
				break;

			case peripheral::ECCRAM:
				SYSTEM::MSTPCRC.MSTPC6 = f;		// ECC RAM のストップ状態解除
				break;

			case peripheral::STBRAM:
				SYSTEM::MSTPCRC.MSTPC7 = f;		// STANDBY RAM のストップ状態解除
				break;
			default:
				break;
			}
		}
	};
}
<commit_msg>fix: RX64M/RX71M RSPI power config manage<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX600 グループ・省電力制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2016, 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "RX600/system.hpp"
#include "RX600/peripheral.hpp"
#include "common/static_holder.hpp"

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  省電力制御クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class power_cfg {

		struct pad_t {

			uint8_t		cmt_;
			uint8_t		tpu_;

			pad_t() : cmt_(0), tpu_(0) { }
		};

		typedef utils::static_holder<pad_t> STH;

		static void set_(bool f, uint8_t& pad, peripheral org, peripheral tgt)
		{
			if(f) {
				pad |= 1 << (static_cast<uint16_t>(tgt) - static_cast<uint16_t>(org));
			} else {
				pad &= ~(1 << (static_cast<uint16_t>(tgt) - static_cast<uint16_t>(org)));
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  周辺機器に切り替える
			@param[in]	t	周辺機器タイプ
			@param[in]	ena	オフにする場合「false」
		*/
		//-----------------------------------------------------------------//
		static void turn(peripheral t, bool ena = true)
		{
			bool f = !ena;
			switch(t) {
			case peripheral::CMT0:
			case peripheral::CMT1:
				// CMT0, CMT1 のストップ状態設定
				set_(ena, STH::st.cmt_, peripheral::CMT0, t);
				SYSTEM::MSTPCRA.MSTPA15 = ((STH::st.cmt_ & 0b0011) == 0);
				break;
			case peripheral::CMT2:
			case peripheral::CMT3:
				// CMT2, CMT3 のストップ状態設定
				set_(ena, STH::st.cmt_, peripheral::CMT0, t);
				SYSTEM::MSTPCRA.MSTPA14 = ((STH::st.cmt_ & 0b1100) == 0);
				break;

			case peripheral::TPU0:
			case peripheral::TPU1:
			case peripheral::TPU2:
			case peripheral::TPU3:
			case peripheral::TPU4:
			case peripheral::TPU5:
				// TPU0 to TPU5 のストップ状態設定
				set_(ena, STH::st.tpu_, peripheral::TPU0, t);
				SYSTEM::MSTPCRA.MSTPA13 = (STH::st.tpu_ == 0);
				break;

			case peripheral::S12AD:
				SYSTEM::MSTPCRA.MSTPA17 = f;	// S12AD のストップ状態解除
				break;
			case peripheral::S12AD1:
				SYSTEM::MSTPCRA.MSTPA16 = f;	// S12AD1 のストップ状態解除
				break;

			case peripheral::R12DA:
				SYSTEM::MSTPCRA.MSTPA19 = f;	// R12DA のストップ状態解除
				break;

			case peripheral::DTC:
				SYSTEM::MSTPCRA.MSTPA28 = f;	// DMAC/DTC のストップ状態解除
				break;

			case peripheral::SCI0:
				SYSTEM::MSTPCRB.MSTPB31 = f;	// B31 (SCI0)のストップ状態解除
				break;
			case peripheral::SCI1:
				SYSTEM::MSTPCRB.MSTPB30 = f;	// B30 (SCI1)のストップ状態解除
				break;
			case peripheral::SCI2:
				SYSTEM::MSTPCRB.MSTPB29 = f;	// B29 (SCI2)のストップ状態解除
				break;
			case peripheral::SCI3:
				SYSTEM::MSTPCRB.MSTPB28 = f;	// B28 (SCI3)のストップ状態解除
				break;
			case peripheral::SCI4:
				SYSTEM::MSTPCRB.MSTPB27 = f;	// B27 (SCI4)のストップ状態解除
				break;
			case peripheral::SCI5:
				SYSTEM::MSTPCRB.MSTPB26 = f;	// B26 (SCI5)のストップ状態解除
				break;
			case peripheral::SCI6:
				SYSTEM::MSTPCRB.MSTPB25 = f;	// B25 (SCI6)のストップ状態解除
				break;
			case peripheral::SCI7:
				SYSTEM::MSTPCRB.MSTPB24 = f;	// B24 (SCI7)のストップ状態解除
				break;

			case peripheral::SCI12:
				SYSTEM::MSTPCRB.MSTPB4 = f;		// B-B4 (SCI12)のストップ状態解除
				break;
#if defined(SIG_RX64M) || defined(SIG_RX71M)
			case peripheral::SCIF8:
				SYSTEM::MSTPCRC.MSTPC27 = f;	// C-B27 (SCIF8)のストップ状態解除
				break;
			case peripheral::SCIF9:
				SYSTEM::MSTPCRC.MSTPC26 = f;	// C-B26 (SCIF9)のストップ状態解除
				break;
			case peripheral::SCIF10:
				SYSTEM::MSTPCRC.MSTPC25 = f;	// C-B25 (SCIF10のストップ状態解除
				break;
			case peripheral::SCIF11:
				SYSTEM::MSTPCRC.MSTPC24 = f;	// C-B24 (SCIF11のストップ状態解除
				break;
#elif defined(SIG_RX65N)
			case peripheral::SCI8:
				SYSTEM::MSTPCRC.MSTPC27 = f;	// C-B27 (SCI8)のストップ状態解除
				break;
			case peripheral::SCI9:
				SYSTEM::MSTPCRC.MSTPC26 = f;	// C-B26 (SCI9)のストップ状態解除
				break;
			case peripheral::SCI10:
				SYSTEM::MSTPCRC.MSTPC25 = f;	// C-B25 (SCI10のストップ状態解除
				break;
			case peripheral::SCI11:
				SYSTEM::MSTPCRC.MSTPC24 = f;	// C-B24 (SCI11のストップ状態解除
				break;
#endif
#if defined(SIG_RX64M) || defined(SIG_RX71M)
			case peripheral::RSPI:
				SYSTEM::MSTPCRB.MSTPB17 = f;	// RSPI のストップ状態解除
				break;
#elif defined(SIG_RX65N)
			case peripheral::RSPI0:
				SYSTEM::MSTPCRB.MSTPB17 = f;	// RSPI のストップ状態解除
				break;
			case peripheral::RSPI1:
				SYSTEM::MSTPCRB.MSTPB16 = f;	// RSPI のストップ状態解除
				break;
#endif

			case peripheral::SDHI:
				SYSTEM::MSTPCRD.MSTPD19 = f;	// SDHI のストップ状態解除
				break;

			case peripheral::ETHERC0:
			case peripheral::ETHERCA:
			case peripheral::EDMAC0:
				SYSTEM::MSTPCRB.MSTPB15 = f;	// ETHER0, EDMAC0 のストップ状態解除
				BUS::BEREN.TOEN = 1;
				break;
			case peripheral::ETHERC1:
			case peripheral::EDMAC1:
				SYSTEM::MSTPCRB.MSTPB14 = f;	// ETHER1, EDMAC1 のストップ状態解除
				BUS::BEREN.TOEN = 1;
				break;

			case peripheral::ECCRAM:
				SYSTEM::MSTPCRC.MSTPC6 = f;		// ECC RAM のストップ状態解除
				break;

			case peripheral::STBRAM:
				SYSTEM::MSTPCRC.MSTPC7 = f;		// STANDBY RAM のストップ状態解除
				break;
			default:
				break;
			}
		}
	};
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include "fnord-base/bufferutil.h"
#include "fnord-base/exception.h"
#include "fnord-base/inspect.h"
#include "fnord-http/httpparser.h"

namespace fnord {
namespace http {

const char HTTPParser::kContentLengthHeader[] = "Content-Length";
const char HTTPParser::kConnectionHeader[] = "Connection";

HTTPParser::HTTPParser(
    kParserMode mode,
    size_t buffer_size /* = kDefaultBufferSize */) :
    mode_(mode),
    on_method_cb_(nullptr),
    on_uri_cb_(nullptr),
    on_version_cb_(nullptr),
    on_status_code_cb_(nullptr),
    on_status_name_cb_(nullptr),
    on_header_cb_(nullptr),
    on_headers_complete_cb_(nullptr),
    on_body_chunk_cb_(nullptr),
    expect_body_(true),
    body_bytes_read_(0),
    body_bytes_expected_(0) {
  switch (mode) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.reserve(buffer_size);
}

HTTPParser::kParserState HTTPParser::state() const {
  return state_;
}

void HTTPParser::onMethod(
    std::function<void(HTTPMessage::kHTTPMethod)> callback) {
  on_method_cb_ = callback;
}

void HTTPParser::onURI(
    std::function<void(const char* data, size_t size)> callback) {
  on_uri_cb_ = callback;
}

void HTTPParser::onVersion(
    std::function<void(const char* data, size_t size)> callback) {
  on_version_cb_ = callback;
}

void HTTPParser::onStatusCode(std::function<void(int)> callback) {
  on_status_code_cb_ = callback;
}

void HTTPParser::onStatusName(
    std::function<void(const char* data, size_t size)> callback) {
  on_status_name_cb_ = callback;
}

void HTTPParser::onHeader(std::function<void(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len)> callback) {
  on_header_cb_ = callback;
}

void HTTPParser::onHeadersComplete(std::function<void()> callback) {
  on_headers_complete_cb_ = callback;
}

void HTTPParser::onBodyChunk(
    std::function<void(const char* data, size_t size)> callback) {
  on_body_chunk_cb_ = callback;
}

void HTTPParser::parse(const char* data, size_t size) {
  const char* begin = data;
  const char* end = data + size;

  while (begin < end) {
    switch (state_) {
      case S_REQ_METHOD:
        parseMethod(&begin, end);
        break;
      case S_REQ_URI:
        parseURI(&begin, end);
        break;
      case S_REQ_VERSION:
        parseRequestVersion(&begin, end);
        break;
      case S_RES_VERSION:
        parseResponseVersion(&begin, end);
        break;
      case S_RES_STATUS_CODE:
        parseResponseStatusCode(&begin, end);
        break;
      case S_RES_STATUS_NAME:
        parseResponseStatusName(&begin, end);
        break;
      case S_HEADER:
        parseHeader(&begin, end);
        break;
      case S_DONE:
        if (mode_ == PARSE_HTTP_REQUEST) {
          RAISE(kParseError, "invalid trailing bytes");
        }
        /* fallthrough */
      case S_BODY:
        readBody(&begin, end);
        break;

    }
  }
}

void HTTPParser::eof() {
  switch (state_) {
    case S_REQ_METHOD:
    case S_REQ_URI:
    case S_REQ_VERSION:
    case S_RES_VERSION:
    case S_RES_STATUS_CODE:
    case S_RES_STATUS_NAME:
    case S_HEADER:
    case S_BODY:
      if (body_bytes_expected_ != -1 &&
          body_bytes_read_ < body_bytes_expected_) {
        RAISE(kParseError, "unexpected end of file");
      } else {
        state_ = S_DONE;
      }
      return;
    case S_DONE:
      return;
  }
}

void HTTPParser::parseMethod(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    state_ = S_REQ_URI;
    (*begin)++;

    if (on_method_cb_) {
      if (buf_ == "CONNECT") {
        on_method_cb_(HTTPMessage::M_CONNECT);
        buf_.clear();
        return;
      }

      if (buf_ == "DELETE") {
        on_method_cb_(HTTPMessage::M_DELETE);
        buf_.clear();
        return;
      }

      if (buf_ == "GET") {
        on_method_cb_(HTTPMessage::M_GET);
        buf_.clear();
        return;
      }

      if (buf_ == "HEAD") {
        on_method_cb_(HTTPMessage::M_HEAD);
        buf_.clear();
        return;
      }

      if (buf_ == "OPTIONS") {
        on_method_cb_(HTTPMessage::M_OPTIONS);
        buf_.clear();
        return;
      }

      if (buf_ == "POST") {
        on_method_cb_(HTTPMessage::M_POST);
        buf_.clear();
        return;
      }

      if (buf_ == "PUT") {
        on_method_cb_(HTTPMessage::M_PUT);
        buf_.clear();
        return;
      }

      if (buf_ == "TRACE"){
        on_method_cb_(HTTPMessage::M_TRACE);
        buf_.clear();
        return;
      }

      RAISEF(kParseError, "Invalid HTTP method: $0", buf_.toString());
    }
  }

  if (buf_.size() > kMaxMethodSize) {
    RAISEF(kParseError, "HTTP method too large, max is $0", kMaxMethodSize);
  }
}

void HTTPParser::parseURI(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (on_uri_cb_) {
      on_uri_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_REQ_VERSION;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseRequestVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (strncasecmp((char *) buf_.data(), "HTTP/1.0", buf_.size()) == 0) {
      body_bytes_expected_ = -1;
    }

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_RES_STATUS_CODE;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseStatusCode(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    std::string status_code_str((char *) buf_.data(), buf_.size());
    int status_code = 1;

    try {
      status_code = std::stoi(status_code_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid http status code: $0", status_code_str);
    }

    if (on_status_code_cb_) {
      on_status_code_cb_(status_code);
    }

    buf_.clear();
    state_ = S_RES_STATUS_NAME;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseResponseStatusName(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_status_name_cb_) {
      on_status_name_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseHeader(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (buf_.size() > 0) {
      auto hkey = (char*) buf_.data();
      auto hkey_len = buf_.find(':');
      if (hkey_len == Buffer::npos) {
        RAISEF(kParseError, "invalid HTTP header line: $0", buf_.toString());
      }

      auto hval = hkey + hkey_len + 1;
      auto hval_len = buf_.size() - hkey_len - 1;
      while (hval_len > 0 && *hval == ' ') {
        hval++;
        hval_len--;
      }

      processHeader(hkey, hkey_len, hval, hval_len);
      buf_.clear();
      state_ = S_HEADER;
    } else {
      if (body_bytes_expected_ == 0) {
        state_ = S_DONE;
      } else {
        state_ = S_BODY;
      }

      if (on_headers_complete_cb_) {
        on_headers_complete_cb_();
      }
    }

    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxHeaderSize) {
    RAISEF(kParseError, "HTTP header too large, max is $0", kMaxHeaderSize);
  }
}

void HTTPParser::processHeader(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len) {
  if (expect_body_ &&
      key_len == strlen(kContentLengthHeader) &&
      strncasecmp(key, kContentLengthHeader, key_len) == 0) {
    std::string content_length_str(val, val_len);
    try {
      body_bytes_expected_ = std::stoul(content_length_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid content length: $0", content_length_str);
    }
  }

  if (expect_body_ &&
      key_len == strlen(kConnectionHeader) &&
      strncasecmp(key, kConnectionHeader, key_len) == 0 &&
      val_len == strlen("Close") &&
      strncasecmp(val, "Close", key_len) == 0) {
    body_bytes_expected_ = -1;
  }

  if (on_header_cb_) {
    on_header_cb_(key, key_len, val, val_len);
  }
}

void HTTPParser::readBody(const char** begin, const char* end) {
  body_bytes_read_ += end - *begin;

  if (body_bytes_read_ == body_bytes_expected_) {
    state_ = HTTPParser::S_DONE;
  }

  //if ((body_bytes_read_ > body_bytes_expected_) &&
  //    !(body_bytes_expected_ == 0 && mode_ == PARSE_HTTP_RESPONSE)) {
  //  RAISE(kParseError, "invalid trailing body bytes");
  //}

  if (on_body_chunk_cb_) {
    on_body_chunk_cb_(*begin, end - *begin);
  }

  *begin = end;
}

bool HTTPParser::readUntil(const char** begin, const char* end, char search) {
  auto cur = *begin;
  for (; cur < end && *cur != search; ++cur);
  buf_.append(*begin, (cur - *begin));
  *begin = cur;
  return cur != end && *cur == search;
}

void HTTPParser::reset() {
  switch (mode_) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.clear();
  body_bytes_read_ = 0;
  body_bytes_expected_ = 0;
  expect_body_ = true;
}

void HTTPParser::ignoreBody() {
  expect_body_ = false;
}

}
}
<commit_msg>fixes<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <string.h>
#include "fnord-base/bufferutil.h"
#include "fnord-base/exception.h"
#include "fnord-base/inspect.h"
#include "fnord-http/httpparser.h"

namespace fnord {
namespace http {

const char HTTPParser::kContentLengthHeader[] = "Content-Length";
const char HTTPParser::kConnectionHeader[] = "Connection";

HTTPParser::HTTPParser(
    kParserMode mode,
    size_t buffer_size /* = kDefaultBufferSize */) :
    mode_(mode),
    on_method_cb_(nullptr),
    on_uri_cb_(nullptr),
    on_version_cb_(nullptr),
    on_status_code_cb_(nullptr),
    on_status_name_cb_(nullptr),
    on_header_cb_(nullptr),
    on_headers_complete_cb_(nullptr),
    on_body_chunk_cb_(nullptr),
    expect_body_(true),
    body_bytes_read_(0),
    body_bytes_expected_(0) {
  switch (mode) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.reserve(buffer_size);
}

HTTPParser::kParserState HTTPParser::state() const {
  return state_;
}

void HTTPParser::onMethod(
    std::function<void(HTTPMessage::kHTTPMethod)> callback) {
  on_method_cb_ = callback;
}

void HTTPParser::onURI(
    std::function<void(const char* data, size_t size)> callback) {
  on_uri_cb_ = callback;
}

void HTTPParser::onVersion(
    std::function<void(const char* data, size_t size)> callback) {
  on_version_cb_ = callback;
}

void HTTPParser::onStatusCode(std::function<void(int)> callback) {
  on_status_code_cb_ = callback;
}

void HTTPParser::onStatusName(
    std::function<void(const char* data, size_t size)> callback) {
  on_status_name_cb_ = callback;
}

void HTTPParser::onHeader(std::function<void(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len)> callback) {
  on_header_cb_ = callback;
}

void HTTPParser::onHeadersComplete(std::function<void()> callback) {
  on_headers_complete_cb_ = callback;
}

void HTTPParser::onBodyChunk(
    std::function<void(const char* data, size_t size)> callback) {
  on_body_chunk_cb_ = callback;
}

void HTTPParser::parse(const char* data, size_t size) {
  const char* begin = data;
  const char* end = data + size;

  while (begin < end) {
    switch (state_) {
      case S_REQ_METHOD:
        parseMethod(&begin, end);
        break;
      case S_REQ_URI:
        parseURI(&begin, end);
        break;
      case S_REQ_VERSION:
        parseRequestVersion(&begin, end);
        break;
      case S_RES_VERSION:
        parseResponseVersion(&begin, end);
        break;
      case S_RES_STATUS_CODE:
        parseResponseStatusCode(&begin, end);
        break;
      case S_RES_STATUS_NAME:
        parseResponseStatusName(&begin, end);
        break;
      case S_HEADER:
        parseHeader(&begin, end);
        break;
      case S_DONE:
        if (mode_ == PARSE_HTTP_REQUEST) {
          RAISE(kParseError, "invalid trailing bytes");
        }
        /* fallthrough */
      case S_BODY:
        readBody(&begin, end);
        break;

    }
  }
}

void HTTPParser::eof() {
  switch (state_) {
    case S_REQ_METHOD:
    case S_REQ_URI:
    case S_REQ_VERSION:
    case S_RES_VERSION:
    case S_RES_STATUS_CODE:
    case S_RES_STATUS_NAME:
    case S_HEADER:
    case S_BODY:
      if (body_bytes_expected_ != -1 &&
          body_bytes_read_ < body_bytes_expected_) {
        RAISE(kParseError, "unexpected end of file");
      } else {
        state_ = S_DONE;
      }
      return;
    case S_DONE:
      return;
  }
}

void HTTPParser::parseMethod(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    state_ = S_REQ_URI;
    (*begin)++;

    if (on_method_cb_) {
      if (buf_ == "CONNECT") {
        on_method_cb_(HTTPMessage::M_CONNECT);
        buf_.clear();
        return;
      }

      if (buf_ == "DELETE") {
        on_method_cb_(HTTPMessage::M_DELETE);
        buf_.clear();
        return;
      }

      if (buf_ == "GET") {
        on_method_cb_(HTTPMessage::M_GET);
        buf_.clear();
        return;
      }

      if (buf_ == "HEAD") {
        on_method_cb_(HTTPMessage::M_HEAD);
        buf_.clear();
        return;
      }

      if (buf_ == "OPTIONS") {
        on_method_cb_(HTTPMessage::M_OPTIONS);
        buf_.clear();
        return;
      }

      if (buf_ == "POST") {
        on_method_cb_(HTTPMessage::M_POST);
        buf_.clear();
        return;
      }

      if (buf_ == "PUT") {
        on_method_cb_(HTTPMessage::M_PUT);
        buf_.clear();
        return;
      }

      if (buf_ == "TRACE"){
        on_method_cb_(HTTPMessage::M_TRACE);
        buf_.clear();
        return;
      }

      RAISEF(kParseError, "Invalid HTTP method: $0", buf_.toString());
    }
  }

  if (buf_.size() > kMaxMethodSize) {
    RAISEF(kParseError, "HTTP method too large, max is $0", kMaxMethodSize);
  }
}

void HTTPParser::parseURI(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (on_uri_cb_) {
      on_uri_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_REQ_VERSION;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseRequestVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseVersion(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    if (strncasecmp((char *) buf_.data(), "HTTP/1.0", buf_.size()) == 0) {
      body_bytes_expected_ = -1;
    }

    if (on_version_cb_) {
      on_version_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_RES_STATUS_CODE;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseResponseStatusCode(const char** begin, const char* end) {
  if (readUntil(begin, end, ' ')) {
    std::string status_code_str((char *) buf_.data(), buf_.size());
    int status_code = 1;

    try {
      status_code = std::stoi(status_code_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid http status code: $0", status_code_str);
    }

    if (on_status_code_cb_) {
      on_status_code_cb_(status_code);
    }

    buf_.clear();
    state_ = S_RES_STATUS_NAME;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxURISize) {
    RAISEF(kParseError, "HTTP URI too large, max is $0", kMaxURISize);
  }
}

void HTTPParser::parseResponseStatusName(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (on_status_name_cb_) {
      on_status_name_cb_((char *) buf_.data(), buf_.size());
    }

    buf_.clear();
    state_ = S_HEADER;
    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxVersionSize) {
    RAISEF(kParseError, "HTTP version too large, max is $0", kMaxVersionSize);
  }
}

void HTTPParser::parseHeader(const char** begin, const char* end) {
  if (readUntil(begin, end, '\n')) {
    BufferUtil::stripTrailingBytes(&buf_, '\r');

    if (buf_.size() > 0) {
      auto hkey = (char*) buf_.data();
      auto hkey_len = buf_.find(':');
      if (hkey_len == Buffer::npos) {
        RAISEF(kParseError, "invalid HTTP header line: $0", buf_.toString());
      }

      auto hval = hkey + hkey_len + 1;
      auto hval_len = buf_.size() - hkey_len - 1;
      while (hval_len > 0 && *hval == ' ') {
        hval++;
        hval_len--;
      }

      processHeader(hkey, hkey_len, hval, hval_len);
      buf_.clear();
      state_ = S_HEADER;
    } else {
      if (body_bytes_expected_ == 0) {
        state_ = S_DONE;
      } else {
        state_ = S_BODY;
      }

      if (on_headers_complete_cb_) {
        on_headers_complete_cb_();
      }
    }

    (*begin)++;
    return;
  }

  if (buf_.size() > kMaxHeaderSize) {
    RAISEF(kParseError, "HTTP header too large, max is $0", kMaxHeaderSize);
  }
}

void HTTPParser::processHeader(
    const char* key,
    size_t key_len,
    const char* val,
    size_t val_len) {
  if (expect_body_ &&
      key_len == strlen(kContentLengthHeader) &&
      strncasecmp(key, kContentLengthHeader, key_len) == 0) {
    std::string content_length_str(val, val_len);
    try {
      body_bytes_expected_ = std::stoul(content_length_str);
    } catch (const std::exception& e) {
      RAISEF(kParseError, "invalid content length: $0", content_length_str);
    }
  }

  if (expect_body_ &&
      key_len == strlen(kConnectionHeader) &&
      strncasecmp(key, kConnectionHeader, key_len) == 0 &&
      val_len == strlen("Close") &&
      strncasecmp(val, "Close", val_len) == 0) {
    body_bytes_expected_ = -1;
  }

  if (on_header_cb_) {
    on_header_cb_(key, key_len, val, val_len);
  }
}

void HTTPParser::readBody(const char** begin, const char* end) {
  body_bytes_read_ += end - *begin;

  if (body_bytes_read_ == body_bytes_expected_) {
    state_ = HTTPParser::S_DONE;
  }

  //if ((body_bytes_read_ > body_bytes_expected_) &&
  //    !(body_bytes_expected_ == 0 && mode_ == PARSE_HTTP_RESPONSE)) {
  //  RAISE(kParseError, "invalid trailing body bytes");
  //}

  if (on_body_chunk_cb_) {
    on_body_chunk_cb_(*begin, end - *begin);
  }

  *begin = end;
}

bool HTTPParser::readUntil(const char** begin, const char* end, char search) {
  auto cur = *begin;
  for (; cur < end && *cur != search; ++cur);
  buf_.append(*begin, (cur - *begin));
  *begin = cur;
  return cur != end && *cur == search;
}

void HTTPParser::reset() {
  switch (mode_) {
    case PARSE_HTTP_REQUEST:
      state_ = S_REQ_METHOD;
      break;

    case PARSE_HTTP_RESPONSE:
      state_ = S_RES_VERSION;
      break;
  }

  buf_.clear();
  body_bytes_read_ = 0;
  body_bytes_expected_ = 0;
  expect_body_ = true;
}

void HTTPParser::ignoreBody() {
  expect_body_ = false;
}

}
}
<|endoftext|>


<commit_before>/*

openfx-arena - https://github.com/olear/openfx-arena

Copyright (c) 2015, Ole-André Rodlie <olear@fxarena.net>
Copyright (c) 2015, FxArena DA <mail@fxarena.net>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Neither the name of FxArena DA nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

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

*/

#include "ReadSVG.h"
#include <iostream>
#include <stdint.h>
#include <Magick++.h>
#include "GenericReader.h"
#include "GenericOCIO.h"
#include "ofxsMacros.h"
#ifdef OFX_IO_USING_OCIO
#include <OpenColorIO/OpenColorIO.h>
#endif

#define kPluginName "ReadSVGOFX"
#define kPluginGrouping "Image/Readers"
#define kPluginIdentifier "net.fxarena.openfx.ReadSVG"
#define kPluginVersionMajor 1
#define kPluginVersionMinor 4

#define kParamDpi "dpi"
#define kParamDpiLabel "DPI"
#define kParamDpiHint "Dots-per-inch (0 is default)"
#define kParamDpiDefault 0

#define kSupportsRGBA true
#define kSupportsRGB false
#define kSupportsAlpha false
#define kSupportsTiles false

class ReadSVGPlugin : public GenericReaderPlugin
{
public:
    ReadSVGPlugin(OfxImageEffectHandle handle);
    virtual ~ReadSVGPlugin();
private:
    virtual bool isVideoStream(const std::string& /*filename*/) OVERRIDE FINAL { return false; }
    virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string &paramName) OVERRIDE FINAL;
    virtual void decode(const std::string& filename, OfxTime time, const OfxRectI& renderWindow, float *pixelData, const OfxRectI& bounds, OFX::PixelComponentEnum pixelComponents, int pixelComponentCount, int rowBytes) OVERRIDE FINAL;
    virtual bool getFrameBounds(const std::string& filename, OfxTime time, OfxRectI *bounds, double *par, std::string *error) OVERRIDE FINAL;
    virtual void restoreState(const std::string& filename) OVERRIDE FINAL;
    virtual void onInputFileChanged(const std::string& newFile, OFX::PreMultiplicationEnum *premult, OFX::PixelComponentEnum *components, int *componentCount) OVERRIDE FINAL;
    OFX::IntParam *dpi_;
    bool hasRSVG_;
    int width_;
    int height_;
};

ReadSVGPlugin::ReadSVGPlugin(OfxImageEffectHandle handle)
: GenericReaderPlugin(handle, kSupportsRGBA, kSupportsRGB, kSupportsAlpha, kSupportsTiles, false)
,dpi_(0)
,hasRSVG_(false)
,width_(0)
,height_(0)
{
    Magick::InitializeMagick(NULL);
    std::string delegates = MagickCore::GetMagickDelegates();
    if (delegates.find("rsvg") != std::string::npos)
        hasRSVG_ = true;

    dpi_ = fetchIntParam(kParamDpi);
    assert(dpi_);
}

ReadSVGPlugin::~ReadSVGPlugin()
{
}

void
ReadSVGPlugin::decode(const std::string& filename,
                      OfxTime time,
                      const OfxRectI& /*renderWindow*/,
                      float *pixelData,
                      const OfxRectI& bounds,
                      OFX::PixelComponentEnum /*pixelComponents*/,
                      int /*pixelComponentCount*/,
                      int /*rowBytes*/)
{
    #ifdef DEBUG
    std::cout << "decode ..." << std::endl;
    #endif
    if (!hasRSVG_)
        setPersistentMessage(OFX::Message::eMessageError, "", "librsvg missing, some features may not work as expected");
    int dpi = 0;
    dpi_->getValueAtTime(time, dpi);
    Magick::Image image;
    image.resolutionUnits(Magick::PixelsPerInchResolution);
    image.density(Magick::Geometry(dpi,dpi));
    try {
        image.backgroundColor("none"); // must be set to avoid bg
        image.read(filename);
    }
    catch(Magick::Warning &warning) { // ignore since warns interupt render
        #ifdef DEBUG
        std::cout << warning.what() << std::endl;
        #endif
    }
    if (image.columns()>0 && image.rows()>0) {
        Magick::Image container(Magick::Geometry(bounds.x2,bounds.y2),Magick::Color("rgba(0,0,0,0)"));
        container.composite(image,0,0,Magick::OverCompositeOp);
        container.flip();
        container.write(0,0,bounds.x2,bounds.y2,"RGBA",Magick::FloatPixel,pixelData);
    }
    else {
        setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
    }
}

bool ReadSVGPlugin::getFrameBounds(const std::string& /*filename*/,
                              OfxTime /*time*/,
                              OfxRectI *bounds,
                              double *par,
                              std::string* /*error*/)
{
    #ifdef DEBUG
    std::cout << "getFrameBounds ..." << std::endl;
    #endif
    if (width_>0 && height_>0) {
        bounds->x1 = 0;
        bounds->x2 = width_;
        bounds->y1 = 0;
        bounds->y2 = height_;
        *par = 1.0;
    }
    return true;
}

void ReadSVGPlugin::restoreState(const std::string& filename)
{
    #ifdef DEBUG
    std::cout << "restoreState ..." << std::endl;
    #endif
    Magick::Image image;
    int dpi;
    dpi_->getValue(dpi);
    image.resolutionUnits(Magick::PixelsPerInchResolution);
    image.density(Magick::Geometry(dpi,dpi));
    try {
        image.read(filename);
    }
    catch(Magick::Warning &warning) { // ignore since warns interupt render
        #ifdef DEBUG
        std::cout << warning.what() << std::endl;
        #endif
    }
    if (image.columns()>0 && image.rows()>0) {
        width_ = image.columns();
        height_ = image.rows();
    }
    else {
        setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
    }
}

void ReadSVGPlugin::changedParam(const OFX::InstanceChangedArgs &args, const std::string &paramName)
{
    #ifdef DEBUG
    std::cout << "changedParam ..." << std::endl;
    #endif
    if (paramName == kParamDpi) {
        int dpi;
        std::string imageFile;
        _fileParam->getValue(imageFile);
        dpi_->getValue(dpi);
        Magick::Image image;
        image.resolutionUnits(Magick::PixelsPerInchResolution);
        image.density(Magick::Geometry(dpi,dpi));
        try {
            image.read(imageFile);
        }
        catch(Magick::Warning &warning) { // ignore since warns interupt render
            #ifdef DEBUG
            std::cout << warning.what() << std::endl;
            #endif
        }
        if (image.columns()>0 && image.rows()>0) {
            width_ = image.columns();
            height_ = image.rows();
        }
    }
    else {
        GenericReaderPlugin::changedParam(args,paramName);
    }
}

void ReadSVGPlugin::onInputFileChanged(const std::string& newFile,
                                  OFX::PreMultiplicationEnum *premult,
                                  OFX::PixelComponentEnum *components,int */*componentCount*/)
{
    #ifdef DEBUG
    std::cout << "onInputFileChanged ..." << std::endl;
    #endif
    assert(premult && components);
    int dpi;
    dpi_->getValue(dpi);
    Magick::Image image;
    #ifdef DEBUG
    image.debug(true);
    #endif
    image.resolutionUnits(Magick::PixelsPerInchResolution);
    image.density(Magick::Geometry(dpi,dpi));
    try {
        image.read(newFile);
    }
    catch(Magick::Warning &warning) { // ignore since warns interupt render
        #ifdef DEBUG
        std::cout << warning.what() << std::endl;
        #endif
    }
    if (image.columns()>0 && image.rows()>0) {
        width_ = image.columns();
        height_ = image.rows();
        # ifdef OFX_IO_USING_OCIO
        switch(image.colorSpace()) {
        case Magick::RGBColorspace:
            _ocio->setInputColorspace("sRGB");
            break;
        case Magick::sRGBColorspace:
            _ocio->setInputColorspace("sRGB");
            break;
        case Magick::scRGBColorspace:
            _ocio->setInputColorspace("sRGB");
            break;
        default:
            _ocio->setInputColorspace("Linear");
            break;
        }
        # endif // OFX_IO_USING_OCIO
    }
    else {
        setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
    }
    *components = OFX::ePixelComponentRGBA;
    *premult = OFX::eImageOpaque;
}

using namespace OFX;

mDeclareReaderPluginFactory(ReadSVGPluginFactory, {}, {}, false);

/** @brief The basic describe function, passed a plugin descriptor */
void ReadSVGPluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
    GenericReaderDescribe(desc, kSupportsTiles, false);
    desc.setLabel(kPluginName);

    #ifdef OFX_EXTENSIONS_TUTTLE
    const char* extensions[] = {"svg","svgz", NULL};
    desc.addSupportedExtensions(extensions);
    desc.setPluginEvaluation(50);
    #endif

    std::string magickV = MagickCore::GetMagickVersion(NULL);
    std::string delegates = MagickCore::GetMagickDelegates();
    desc.setPluginDescription("Read SVG image format.\n\nWritten by Ole-André Rodlie <olear@fxarena.net>\n\nPowered by "+magickV+"\n\nFeatures: "+delegates);
}

/** @brief The describe in context function, passed a plugin descriptor and a context */
void ReadSVGPluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum context)
{
    PageParamDescriptor *page = GenericReaderDescribeInContextBegin(desc, context, isVideoStreamPlugin(), kSupportsRGBA, kSupportsRGB, kSupportsAlpha, kSupportsTiles);
    {
        IntParamDescriptor* param = desc.defineIntParam(kParamDpi);
        param->setLabel(kParamDpiLabel);
        param->setHint(kParamDpiHint);
        param->setRange(0, 10000);
        param->setDisplayRange(0, 500);
        param->setDefault(kParamDpiDefault);
        page->addChild(*param);
    }
    GenericReaderDescribeInContextEnd(desc, context, page, "reference", "reference");
}

/** @brief The create instance function, the plugin must return an object derived from the \ref OFX::ImageEffect class */
ImageEffect* ReadSVGPluginFactory::createInstance(OfxImageEffectHandle handle,
                                     ContextEnum /*context*/)
{
    ReadSVGPlugin* ret =  new ReadSVGPlugin(handle);
    ret->restoreStateFromParameters();
    return ret;
}

void getReadSVGPluginID(OFX::PluginFactoryArray &ids)
{
    static ReadSVGPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
    ids.push_back(&p);
}
<commit_msg>ReadSVG: minor<commit_after>/*

openfx-arena - https://github.com/olear/openfx-arena

Copyright (c) 2015, Ole-André Rodlie <olear@fxarena.net>
Copyright (c) 2015, FxArena DA <mail@fxarena.net>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this
  list of conditions and the following disclaimer.

* Neither the name of FxArena DA nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.

* Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

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

*/

#include "ReadSVG.h"
#include <iostream>
#include <stdint.h>
#include <Magick++.h>
#include "GenericReader.h"
#include "GenericOCIO.h"
#include "ofxsMacros.h"
#ifdef OFX_IO_USING_OCIO
#include <OpenColorIO/OpenColorIO.h>
#endif

#define kPluginName "ReadSVGOFX"
#define kPluginGrouping "Image/Readers"
#define kPluginIdentifier "net.fxarena.openfx.ReadSVG"
#define kPluginVersionMajor 1
#define kPluginVersionMinor 4

#define kParamDpi "dpi"
#define kParamDpiLabel "DPI"
#define kParamDpiHint "Dots-per-inch (0 is default)"
#define kParamDpiDefault 0

#define kSupportsRGBA true
#define kSupportsRGB false
#define kSupportsAlpha false
#define kSupportsTiles false

class ReadSVGPlugin : public GenericReaderPlugin
{
public:
    ReadSVGPlugin(OfxImageEffectHandle handle);
    virtual ~ReadSVGPlugin();
private:
    virtual bool isVideoStream(const std::string& /*filename*/) OVERRIDE FINAL { return false; }
    virtual void changedParam(const OFX::InstanceChangedArgs &args, const std::string &paramName) OVERRIDE FINAL;
    virtual void decode(const std::string& filename, OfxTime time, const OfxRectI& renderWindow, float *pixelData, const OfxRectI& bounds, OFX::PixelComponentEnum pixelComponents, int pixelComponentCount, int rowBytes) OVERRIDE FINAL;
    virtual bool getFrameBounds(const std::string& filename, OfxTime time, OfxRectI *bounds, double *par, std::string *error) OVERRIDE FINAL;
    virtual void restoreState(const std::string& filename) OVERRIDE FINAL;
    virtual void onInputFileChanged(const std::string& newFile, OFX::PreMultiplicationEnum *premult, OFX::PixelComponentEnum *components, int *componentCount) OVERRIDE FINAL;
    OFX::IntParam *dpi_;
    bool hasRSVG_;
    int width_;
    int height_;
};

ReadSVGPlugin::ReadSVGPlugin(OfxImageEffectHandle handle)
: GenericReaderPlugin(handle, kSupportsRGBA, kSupportsRGB, kSupportsAlpha, kSupportsTiles, false)
,dpi_(0)
,hasRSVG_(false)
,width_(0)
,height_(0)
{
    Magick::InitializeMagick(NULL);
    std::string delegates = MagickCore::GetMagickDelegates();
    if (delegates.find("rsvg") != std::string::npos)
        hasRSVG_ = true;

    dpi_ = fetchIntParam(kParamDpi);
    assert(dpi_);
}

ReadSVGPlugin::~ReadSVGPlugin()
{
}

void
ReadSVGPlugin::decode(const std::string& filename,
                      OfxTime time,
                      const OfxRectI& /*renderWindow*/,
                      float *pixelData,
                      const OfxRectI& bounds,
                      OFX::PixelComponentEnum /*pixelComponents*/,
                      int /*pixelComponentCount*/,
                      int /*rowBytes*/)
{
    #ifdef DEBUG
    std::cout << "decode ..." << std::endl;
    #endif
    if (!hasRSVG_)
        setPersistentMessage(OFX::Message::eMessageError, "", "librsvg missing, some features may not work as expected");
    int dpi = 0;
    dpi_->getValueAtTime(time, dpi);
    Magick::Image image;
    image.resolutionUnits(Magick::PixelsPerInchResolution);
    image.density(Magick::Geometry(dpi,dpi));
    try {
        image.backgroundColor("none"); // must be set to avoid bg
        image.read(filename);
    }
    catch(Magick::Warning &warning) { // ignore since warns interupt render
        #ifdef DEBUG
        std::cout << warning.what() << std::endl;
        #endif
    }
    if (image.columns()>0 && image.rows()>0) {
        Magick::Image container(Magick::Geometry(bounds.x2,bounds.y2),Magick::Color("rgba(0,0,0,0)"));
        container.composite(image,0,0,Magick::OverCompositeOp);
        container.flip();
        container.write(0,0,bounds.x2,bounds.y2,"RGBA",Magick::FloatPixel,pixelData);
    }
    else {
        setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
    }
}

bool ReadSVGPlugin::getFrameBounds(const std::string& /*filename*/,
                              OfxTime /*time*/,
                              OfxRectI *bounds,
                              double *par,
                              std::string* /*error*/)
{
    #ifdef DEBUG
    std::cout << "getFrameBounds ..." << std::endl;
    #endif
    if (width_>0 && height_>0) {
        bounds->x1 = 0;
        bounds->x2 = width_;
        bounds->y1 = 0;
        bounds->y2 = height_;
        *par = 1.0;
    }
    return true;
}

void ReadSVGPlugin::restoreState(const std::string& filename)
{
    #ifdef DEBUG
    std::cout << "restoreState ..." << std::endl;
    #endif
    Magick::Image image;
    int dpi;
    dpi_->getValue(dpi);
    image.resolutionUnits(Magick::PixelsPerInchResolution);
    image.density(Magick::Geometry(dpi,dpi));
    try {
        image.read(filename);
    }
    catch(Magick::Warning &warning) { // ignore since warns interupt render
        #ifdef DEBUG
        std::cout << warning.what() << std::endl;
        #endif
    }
    if (image.columns()>0 && image.rows()>0) {
        width_ = image.columns();
        height_ = image.rows();
    }
    /*else {
        setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
    }*/
}

void ReadSVGPlugin::changedParam(const OFX::InstanceChangedArgs &args, const std::string &paramName)
{
    #ifdef DEBUG
    std::cout << "changedParam ..." << std::endl;
    #endif
    if (paramName == kParamDpi) {
        int dpi;
        std::string imageFile;
        _fileParam->getValue(imageFile);
        dpi_->getValue(dpi);
        Magick::Image image;
        image.resolutionUnits(Magick::PixelsPerInchResolution);
        image.density(Magick::Geometry(dpi,dpi));
        try {
            image.read(imageFile);
        }
        catch(Magick::Warning &warning) { // ignore since warns interupt render
            #ifdef DEBUG
            std::cout << warning.what() << std::endl;
            #endif
        }
        if (image.columns()>0 && image.rows()>0) {
            width_ = image.columns();
            height_ = image.rows();
        }
    }
    else {
        GenericReaderPlugin::changedParam(args,paramName);
    }
}

void ReadSVGPlugin::onInputFileChanged(const std::string& newFile,
                                  OFX::PreMultiplicationEnum *premult,
                                  OFX::PixelComponentEnum *components,int */*componentCount*/)
{
    #ifdef DEBUG
    std::cout << "onInputFileChanged ..." << std::endl;
    #endif
    assert(premult && components);
    int dpi;
    dpi_->getValue(dpi);
    Magick::Image image;
    #ifdef DEBUG
    image.debug(true);
    #endif
    image.resolutionUnits(Magick::PixelsPerInchResolution);
    image.density(Magick::Geometry(dpi,dpi));
    try {
        image.read(newFile);
    }
    catch(Magick::Warning &warning) { // ignore since warns interupt render
        #ifdef DEBUG
        std::cout << warning.what() << std::endl;
        #endif
    }
    if (image.columns()>0 && image.rows()>0) {
        width_ = image.columns();
        height_ = image.rows();
        # ifdef OFX_IO_USING_OCIO
        switch(image.colorSpace()) {
        case Magick::RGBColorspace:
            _ocio->setInputColorspace("sRGB");
            break;
        case Magick::sRGBColorspace:
            _ocio->setInputColorspace("sRGB");
            break;
        case Magick::scRGBColorspace:
            _ocio->setInputColorspace("sRGB");
            break;
        default:
            _ocio->setInputColorspace("Linear");
            break;
        }
        # endif // OFX_IO_USING_OCIO
    }
    else {
        setPersistentMessage(OFX::Message::eMessageError, "", "Unable to read image");
        OFX::throwSuiteStatusException(kOfxStatErrFormat);
    }
    *components = OFX::ePixelComponentRGBA;
    *premult = OFX::eImageOpaque;
}

using namespace OFX;

mDeclareReaderPluginFactory(ReadSVGPluginFactory, {}, {}, false);

/** @brief The basic describe function, passed a plugin descriptor */
void ReadSVGPluginFactory::describe(OFX::ImageEffectDescriptor &desc)
{
    GenericReaderDescribe(desc, kSupportsTiles, false);
    desc.setLabel(kPluginName);

    #ifdef OFX_EXTENSIONS_TUTTLE
    const char* extensions[] = {"svg","svgz", NULL};
    desc.addSupportedExtensions(extensions);
    desc.setPluginEvaluation(50);
    #endif

    std::string magickV = MagickCore::GetMagickVersion(NULL);
    std::string delegates = MagickCore::GetMagickDelegates();
    desc.setPluginDescription("Read SVG image format.\n\nWritten by Ole-André Rodlie <olear@fxarena.net>\n\nPowered by "+magickV+"\n\nFeatures: "+delegates);
}

/** @brief The describe in context function, passed a plugin descriptor and a context */
void ReadSVGPluginFactory::describeInContext(OFX::ImageEffectDescriptor &desc, ContextEnum context)
{
    PageParamDescriptor *page = GenericReaderDescribeInContextBegin(desc, context, isVideoStreamPlugin(), kSupportsRGBA, kSupportsRGB, kSupportsAlpha, kSupportsTiles);
    {
        IntParamDescriptor* param = desc.defineIntParam(kParamDpi);
        param->setLabel(kParamDpiLabel);
        param->setHint(kParamDpiHint);
        param->setRange(0, 10000);
        param->setDisplayRange(0, 500);
        param->setDefault(kParamDpiDefault);
        page->addChild(*param);
    }
    GenericReaderDescribeInContextEnd(desc, context, page, "reference", "reference");
}

/** @brief The create instance function, the plugin must return an object derived from the \ref OFX::ImageEffect class */
ImageEffect* ReadSVGPluginFactory::createInstance(OfxImageEffectHandle handle,
                                     ContextEnum /*context*/)
{
    ReadSVGPlugin* ret =  new ReadSVGPlugin(handle);
    ret->restoreStateFromParameters();
    return ret;
}

void getReadSVGPluginID(OFX::PluginFactoryArray &ids)
{
    static ReadSVGPluginFactory p(kPluginIdentifier, kPluginVersionMajor, kPluginVersionMinor);
    ids.push_back(&p);
}
<|endoftext|>


<commit_before>// Copyright 2019 Google Inc. All rights reserved.
//
// 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.

#include <inttypes.h>

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#include "app_framework.h"  // NOLINT
#include "firebase/app.h"
#include "firebase/log.h"
#include "firebase/remote_config.h"
#include "firebase/util.h"
#include "firebase_test_framework.h"  // NOLINT

// The TO_STRING macro is useful for command line defined strings as the quotes
// get stripped.
#define TO_STRING_EXPAND(X) #X
#define TO_STRING(X) TO_STRING_EXPAND(X)

// Path to the Firebase config file to load.
#ifdef FIREBASE_CONFIG
#define FIREBASE_CONFIG_STRING TO_STRING(FIREBASE_CONFIG)
#else
#define FIREBASE_CONFIG_STRING ""
#endif  // FIREBASE_CONFIG

namespace firebase_testapp_automated {

using app_framework::LogDebug;
using app_framework::LogWarning;
using app_framework::ProcessEvents;
using firebase::Future;
using firebase::remote_config::RemoteConfig;
using firebase_test_framework::FirebaseTest;

using testing::UnorderedElementsAre;

class FirebaseRemoteConfigTest : public FirebaseTest {
 public:
  FirebaseRemoteConfigTest();
  ~FirebaseRemoteConfigTest() override;

  void SetUp() override;
  void TearDown() override;

 protected:
  // Initialize Firebase App and Firebase Remote Config.
  void Initialize();
  // Shut down Firebase Remote Config and Firebase App.
  void Terminate();

  bool initialized_ = false;
  RemoteConfig* rc_ = nullptr;
};

FirebaseRemoteConfigTest::FirebaseRemoteConfigTest() : initialized_(false) {
  FindFirebaseConfig(FIREBASE_CONFIG_STRING);
}

FirebaseRemoteConfigTest::~FirebaseRemoteConfigTest() {
  // Must be cleaned up on exit.
  assert(app_ == nullptr);
  assert(rc_ == nullptr);
}

void FirebaseRemoteConfigTest::SetUp() {
  FirebaseTest::SetUp();
  Initialize();
}

void FirebaseRemoteConfigTest::TearDown() {
  // Delete the shared path, if there is one.
  Terminate();
  FirebaseTest::TearDown();
}

void FirebaseRemoteConfigTest::Initialize() {
  if (initialized_) return;
  SetLogLevel(app_framework::kDebug);

  InitializeApp();

  LogDebug("Initializing Firebase Remote Config.");

  ::firebase::ModuleInitializer initializer;

  void* ptr = nullptr;
  ptr = &rc_;
  initializer.Initialize(app_, ptr, [](::firebase::App* app, void* target) {
    LogDebug("Try to initialize Firebase RemoteConfig");
    RemoteConfig** rc_ptr = reinterpret_cast<RemoteConfig**>(target);
    *rc_ptr = RemoteConfig::GetInstance(app);
    return firebase::kInitResultSuccess;
  });

  WaitForCompletion(initializer.InitializeLastResult(), "Initialize");

  ASSERT_EQ(initializer.InitializeLastResult().error(), 0)
      << initializer.InitializeLastResult().error_message();

  LogDebug("Successfully initialized Firebase RemoteConfig.");

  initialized_ = true;
}

void FirebaseRemoteConfigTest::Terminate() {
  if (!initialized_) return;

  LogDebug("Shutdown the Remote Config library.");
  if (rc_) {
    delete rc_;
    rc_ = nullptr;
  }
  LogDebug("Terminating.");
  TerminateApp();

  initialized_ = false;

  ProcessEvents(100);
}

static const char* ValueSourceToString(
    firebase::remote_config::ValueSource source) {
  static const char* kSourceToString[] = {
      "Static",   // kValueSourceStaticValue
      "Remote",   // kValueSourceRemoteValue
      "Default",  // kValueSourceDefaultValue
  };
  return kSourceToString[source];
}

static const unsigned char kBinaryDefaults[] = {6, 0, 0, 6, 7, 3};
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant defaults[] = {
    {"TestBoolean", false},
    {"TestLong", 42},
    {"TestDouble", 3.14},
    {"TestString", "Hello World"},
    {"TestData", firebase::Variant::FromStaticBlob(kBinaryDefaults,
                                                   sizeof(kBinaryDefaults))},
    {"TestDefaultOnly", "Default value that won't be overridden"}};

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant kServerValue[] = {
    {"TestBoolean", true},
    {"TestLong", 119},
    {"TestDouble", 625.63},
    {"TestString", firebase::Variant::FromMutableString("This is a string")},
    {"TestData", 4321},
    {"TestDefaultOnly", firebase::Variant::FromMutableString(
                            "Default value that won't be overridden")}};

static Future<void> SetDefaults(RemoteConfig* rc) {
  size_t default_count = FIREBASE_ARRAYSIZE(defaults);
  return rc->SetDefaults(defaults, default_count);
}

static Future<void> SetDefaultConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings defaultConfigSettings;
  return rc->SetConfigSettings(defaultConfigSettings);
}

static Future<void> SetZeroIntervalConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings zeroIntervalConfigSettings;
  zeroIntervalConfigSettings.minimum_fetch_interval_in_milliseconds = 0;
  return rc->SetConfigSettings(zeroIntervalConfigSettings);
}

// Test cases below.

TEST_F(FirebaseRemoteConfigTest, TestInitializeAndTerminate) {
  // Already tested via SetUp() and TearDown().
}

TEST_F(FirebaseRemoteConfigTest, TestSetDefault) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  bool validated_defaults = true;
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_FALSE(bool_value);
  } else {
    validated_defaults = false;
  }
  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(int64_value, 42);
  } else {
    validated_defaults = false;
  }
  double double_value = rc_->GetDouble("TestDouble", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_NEAR(double_value, 3.14, 0.0001);
  } else {
    validated_defaults = false;
  }
  std::string string_value = rc_->GetString("TestString", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(string_value, "Hello World");
  } else {
    validated_defaults = false;
  }
  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_THAT(blob_value, testing::ElementsAreArray(kBinaryDefaults,
                                                      sizeof(kBinaryDefaults)));
  } else {
    validated_defaults = false;
  }

  if (!validated_defaults) {
    LogWarning(
        "Can't validate defaults, they've been overridden by server values.\n"
#if defined(__ANDROID__)
        "Delete the app's data and run this test again to test SetDefaults:\n"
        " adb shell pm clear [bundle ID]"
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
        "Uninstall and re-install the app and run this again to test "
        "SetDefaults."
#else  // Desktop
        "Delete the Remote Config cache and run this test again to test "
        "SetDefaults:\n"
#if defined(_WIN32)
        " del remote_config_data"
#else
        " rm remote_config_data"
#endif  // defined(_WIN32)
#endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
    );
  }
}

TEST_F(FirebaseRemoteConfigTest, TestGetKeys) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  std::vector<std::string> keys = rc_->GetKeys();
  EXPECT_THAT(
      keys, UnorderedElementsAre("TestBoolean", "TestLong", "TestDouble",
                                 "TestString", "TestData", "TestDefaultOnly"));
  std::vector<std::string> keys_subset = rc_->GetKeysByPrefix("TestD");
  EXPECT_THAT(keys_subset, UnorderedElementsAre("TestDouble", "TestData",
                                                "TestDefaultOnly"));
}

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
TEST_F(FirebaseRemoteConfigTest, TestGetAll) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  std::map<std::string, firebase::Variant> key_values = rc_->GetAll();
  EXPECT_EQ(key_values.size(), 6);

  for (auto key_valur_pair : kServerValue) {
    firebase::Variant k_value = key_valur_pair.value;
    firebase::Variant fetched_value = key_values[key_valur_pair.key];
    EXPECT_EQ(k_value.type(), fetched_value.type());
    EXPECT_EQ(k_value, fetched_value);
  }
}

/* The following test expects that you have your server values set to:
   TestData     4321
   TestDouble   625.63
   TestLong     119
   TestBoolean  true
   TestString   This is a string
 */
TEST_F(FirebaseRemoteConfigTest, TestFetch) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  LogDebug("Fetch time: %lld", rc_->GetInfo().fetch_time);
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestBoolean source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_TRUE(bool_value);

  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestLong source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(int64_value, 119);

  double double_value = rc_->GetDouble("TestDouble", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestDouble source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_NEAR(double_value, 625.63, 0.0001);

  std::string string_value = rc_->GetString("TestString", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestString source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(string_value, "This is a string");

  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestData source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";

  const unsigned char kExpectedBlobServerValue[] = {'4', '3', '2', '1'};
  EXPECT_THAT(blob_value,
              testing::ElementsAreArray(kExpectedBlobServerValue,
                                        sizeof(kExpectedBlobServerValue)));
}

TEST_F(FirebaseRemoteConfigTest, TestFetchInterval) {
  ASSERT_NE(rc_, nullptr);
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->FetchAndActivate(); },
                   rc_),
      "FetchAndActivate"));
  uint64_t current_fetch_time = rc_->GetInfo().fetch_time;
  // Making sure the config settings's fetch interval is 12 hours
  EXPECT_TRUE(WaitForCompletion(SetDefaultConfigSettings(rc_),
                                "SetDefaultConfigSettings"));
  // Second fetch, should respect fetch interval and don't change data.
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_EQ(current_fetch_time, rc_->GetInfo().fetch_time);
  // Update fetch interval to 0
  EXPECT_TRUE(WaitForCompletion(SetZeroIntervalConfigSettings(rc_),
                                "SetZeroIntervalConfigSettings"));
  EXPECT_EQ(0, rc_->GetConfigSettings().minimum_fetch_interval_in_milliseconds);
  // Third fetch, this should operate the real fetch and update the fetch time.
  EXPECT_TRUE(WaitForCompletion(
      RunWithRetry([](RemoteConfig* rc) { return rc->Fetch(); }, rc_),
      "Fetch"));
  EXPECT_NE(current_fetch_time, rc_->GetInfo().fetch_time);
}

}  // namespace firebase_testapp_automated
<commit_msg>Refactor Remote Config deflake to use cleaner std::function version. (#545)<commit_after>// Copyright 2019 Google Inc. All rights reserved.
//
// 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.

#include <inttypes.h>

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>

#include "app_framework.h"  // NOLINT
#include "firebase/app.h"
#include "firebase/log.h"
#include "firebase/remote_config.h"
#include "firebase/util.h"
#include "firebase_test_framework.h"  // NOLINT

// The TO_STRING macro is useful for command line defined strings as the quotes
// get stripped.
#define TO_STRING_EXPAND(X) #X
#define TO_STRING(X) TO_STRING_EXPAND(X)

// Path to the Firebase config file to load.
#ifdef FIREBASE_CONFIG
#define FIREBASE_CONFIG_STRING TO_STRING(FIREBASE_CONFIG)
#else
#define FIREBASE_CONFIG_STRING ""
#endif  // FIREBASE_CONFIG

namespace firebase_testapp_automated {

using app_framework::LogDebug;
using app_framework::LogWarning;
using app_framework::ProcessEvents;
using firebase::Future;
using firebase::remote_config::RemoteConfig;
using firebase_test_framework::FirebaseTest;

using testing::UnorderedElementsAre;

class FirebaseRemoteConfigTest : public FirebaseTest {
 public:
  FirebaseRemoteConfigTest();
  ~FirebaseRemoteConfigTest() override;

  void SetUp() override;
  void TearDown() override;

 protected:
  // Initialize Firebase App and Firebase Remote Config.
  void Initialize();
  // Shut down Firebase Remote Config and Firebase App.
  void Terminate();

  bool initialized_ = false;
  RemoteConfig* rc_ = nullptr;
};

FirebaseRemoteConfigTest::FirebaseRemoteConfigTest() : initialized_(false) {
  FindFirebaseConfig(FIREBASE_CONFIG_STRING);
}

FirebaseRemoteConfigTest::~FirebaseRemoteConfigTest() {
  // Must be cleaned up on exit.
  assert(app_ == nullptr);
  assert(rc_ == nullptr);
}

void FirebaseRemoteConfigTest::SetUp() {
  FirebaseTest::SetUp();
  Initialize();
}

void FirebaseRemoteConfigTest::TearDown() {
  // Delete the shared path, if there is one.
  Terminate();
  FirebaseTest::TearDown();
}

void FirebaseRemoteConfigTest::Initialize() {
  if (initialized_) return;
  SetLogLevel(app_framework::kDebug);

  InitializeApp();

  LogDebug("Initializing Firebase Remote Config.");

  ::firebase::ModuleInitializer initializer;

  void* ptr = nullptr;
  ptr = &rc_;
  initializer.Initialize(app_, ptr, [](::firebase::App* app, void* target) {
    LogDebug("Try to initialize Firebase RemoteConfig");
    RemoteConfig** rc_ptr = reinterpret_cast<RemoteConfig**>(target);
    *rc_ptr = RemoteConfig::GetInstance(app);
    return firebase::kInitResultSuccess;
  });

  WaitForCompletion(initializer.InitializeLastResult(), "Initialize");

  ASSERT_EQ(initializer.InitializeLastResult().error(), 0)
      << initializer.InitializeLastResult().error_message();

  LogDebug("Successfully initialized Firebase RemoteConfig.");

  initialized_ = true;
}

void FirebaseRemoteConfigTest::Terminate() {
  if (!initialized_) return;

  LogDebug("Shutdown the Remote Config library.");
  if (rc_) {
    delete rc_;
    rc_ = nullptr;
  }
  LogDebug("Terminating.");
  TerminateApp();

  initialized_ = false;

  ProcessEvents(100);
}

static const char* ValueSourceToString(
    firebase::remote_config::ValueSource source) {
  static const char* kSourceToString[] = {
      "Static",   // kValueSourceStaticValue
      "Remote",   // kValueSourceRemoteValue
      "Default",  // kValueSourceDefaultValue
  };
  return kSourceToString[source];
}

static const unsigned char kBinaryDefaults[] = {6, 0, 0, 6, 7, 3};
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant defaults[] = {
    {"TestBoolean", false},
    {"TestLong", 42},
    {"TestDouble", 3.14},
    {"TestString", "Hello World"},
    {"TestData", firebase::Variant::FromStaticBlob(kBinaryDefaults,
                                                   sizeof(kBinaryDefaults))},
    {"TestDefaultOnly", "Default value that won't be overridden"}};

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
// NOLINTNEXTLINE
static const firebase::remote_config::ConfigKeyValueVariant kServerValue[] = {
    {"TestBoolean", true},
    {"TestLong", 119},
    {"TestDouble", 625.63},
    {"TestString", firebase::Variant::FromMutableString("This is a string")},
    {"TestData", 4321},
    {"TestDefaultOnly", firebase::Variant::FromMutableString(
                            "Default value that won't be overridden")}};

static Future<void> SetDefaults(RemoteConfig* rc) {
  size_t default_count = FIREBASE_ARRAYSIZE(defaults);
  return rc->SetDefaults(defaults, default_count);
}

static Future<void> SetDefaultConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings defaultConfigSettings;
  return rc->SetConfigSettings(defaultConfigSettings);
}

static Future<void> SetZeroIntervalConfigSettings(RemoteConfig* rc) {
  firebase::remote_config::ConfigSettings zeroIntervalConfigSettings;
  zeroIntervalConfigSettings.minimum_fetch_interval_in_milliseconds = 0;
  return rc->SetConfigSettings(zeroIntervalConfigSettings);
}

// Test cases below.

TEST_F(FirebaseRemoteConfigTest, TestInitializeAndTerminate) {
  // Already tested via SetUp() and TearDown().
}

TEST_F(FirebaseRemoteConfigTest, TestSetDefault) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  bool validated_defaults = true;
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_FALSE(bool_value);
  } else {
    validated_defaults = false;
  }
  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(int64_value, 42);
  } else {
    validated_defaults = false;
  }
  double double_value = rc_->GetDouble("TestDouble", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_NEAR(double_value, 3.14, 0.0001);
  } else {
    validated_defaults = false;
  }
  std::string string_value = rc_->GetString("TestString", &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_EQ(string_value, "Hello World");
  } else {
    validated_defaults = false;
  }
  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  if (value_info.source == firebase::remote_config::kValueSourceDefaultValue) {
    EXPECT_THAT(blob_value, testing::ElementsAreArray(kBinaryDefaults,
                                                      sizeof(kBinaryDefaults)));
  } else {
    validated_defaults = false;
  }

  if (!validated_defaults) {
    LogWarning(
        "Can't validate defaults, they've been overridden by server values.\n"
#if defined(__ANDROID__)
        "Delete the app's data and run this test again to test SetDefaults:\n"
        " adb shell pm clear [bundle ID]"
#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
        "Uninstall and re-install the app and run this again to test "
        "SetDefaults."
#else  // Desktop
        "Delete the Remote Config cache and run this test again to test "
        "SetDefaults:\n"
#if defined(_WIN32)
        " del remote_config_data"
#else
        " rm remote_config_data"
#endif  // defined(_WIN32)
#endif  // defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
    );
  }
}

TEST_F(FirebaseRemoteConfigTest, TestGetKeys) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));

  std::vector<std::string> keys = rc_->GetKeys();
  EXPECT_THAT(
      keys, UnorderedElementsAre("TestBoolean", "TestLong", "TestDouble",
                                 "TestString", "TestData", "TestDefaultOnly"));
  std::vector<std::string> keys_subset = rc_->GetKeysByPrefix("TestD");
  EXPECT_THAT(keys_subset, UnorderedElementsAre("TestDouble", "TestData",
                                                "TestDefaultOnly"));
}

//   TestData     4321
//   TestDouble   625.63
//   TestLong     119
//   TestBoolean  true
//   TestString   This is a string
TEST_F(FirebaseRemoteConfigTest, TestGetAll) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(
      WaitForCompletion(RunWithRetry([&]() { return rc_->Fetch(); }), "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  std::map<std::string, firebase::Variant> key_values = rc_->GetAll();
  EXPECT_EQ(key_values.size(), 6);

  for (auto key_valur_pair : kServerValue) {
    firebase::Variant k_value = key_valur_pair.value;
    firebase::Variant fetched_value = key_values[key_valur_pair.key];
    EXPECT_EQ(k_value.type(), fetched_value.type());
    EXPECT_EQ(k_value, fetched_value);
  }
}

/* The following test expects that you have your server values set to:
   TestData     4321
   TestDouble   625.63
   TestLong     119
   TestBoolean  true
   TestString   This is a string
 */
TEST_F(FirebaseRemoteConfigTest, TestFetch) {
  ASSERT_NE(rc_, nullptr);

  EXPECT_TRUE(WaitForCompletion(SetDefaults(rc_), "SetDefaults"));
  EXPECT_TRUE(
      WaitForCompletion(RunWithRetry([&]() { return rc_->Fetch(); }), "Fetch"));
  EXPECT_TRUE(WaitForCompletion(rc_->Activate(), "Activate"));
  LogDebug("Fetch time: %lld", rc_->GetInfo().fetch_time);
  firebase::remote_config::ValueInfo value_info;
  bool bool_value = rc_->GetBoolean("TestBoolean", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestBoolean source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_TRUE(bool_value);

  int64_t int64_value = rc_->GetLong("TestLong", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestLong source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(int64_value, 119);

  double double_value = rc_->GetDouble("TestDouble", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestDouble source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_NEAR(double_value, 625.63, 0.0001);

  std::string string_value = rc_->GetString("TestString", &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestString source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";
  EXPECT_EQ(string_value, "This is a string");

  std::vector<unsigned char> blob_value =
      rc_->GetData("TestData");  //, &value_info);
  EXPECT_EQ(value_info.source, firebase::remote_config::kValueSourceRemoteValue)
      << "TestData source is " << ValueSourceToString(value_info.source)
      << ", expected Remote";

  const unsigned char kExpectedBlobServerValue[] = {'4', '3', '2', '1'};
  EXPECT_THAT(blob_value,
              testing::ElementsAreArray(kExpectedBlobServerValue,
                                        sizeof(kExpectedBlobServerValue)));
}

TEST_F(FirebaseRemoteConfigTest, TestFetchInterval) {
  ASSERT_NE(rc_, nullptr);
  EXPECT_TRUE(
      WaitForCompletion(RunWithRetry([&]() { return rc_->FetchAndActivate(); }),
                        "FetchAndActivate"));
  uint64_t current_fetch_time = rc_->GetInfo().fetch_time;
  // Making sure the config settings's fetch interval is 12 hours
  EXPECT_TRUE(WaitForCompletion(SetDefaultConfigSettings(rc_),
                                "SetDefaultConfigSettings"));
  // Second fetch, should respect fetch interval and don't change data.
  EXPECT_TRUE(
      WaitForCompletion(RunWithRetry([&]() { return rc_->Fetch(); }), "Fetch"));
  EXPECT_EQ(current_fetch_time, rc_->GetInfo().fetch_time);
  // Update fetch interval to 0
  EXPECT_TRUE(WaitForCompletion(SetZeroIntervalConfigSettings(rc_),
                                "SetZeroIntervalConfigSettings"));
  EXPECT_EQ(0, rc_->GetConfigSettings().minimum_fetch_interval_in_milliseconds);
  // Third fetch, this should operate the real fetch and update the fetch time.
  EXPECT_TRUE(
      WaitForCompletion(RunWithRetry([&]() { return rc_->Fetch(); }), "Fetch"));
  EXPECT_NE(current_fetch_time, rc_->GetInfo().fetch_time);
}

}  // namespace firebase_testapp_automated
<|endoftext|>