<commit_before>/*
 * Copyright 2010 MQWeb - Franky Braem
 *
 * Licensed under the EUPL, Version 1.1 or – as soon they
 * will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the
 * Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 */
#include <MQ/Web/RequestHandlerFactory.h>
#include <MQ/Web/StaticRequestHandler.h>
#include <MQ/Web/DenyRequestHandler.h>
#include <MQ/Web/ControllerRequestHandler.h>

#include <Poco/Logger.h>
#include <Poco/RegularExpression.h>
#include <Poco/Util/Application.h>
#include <Poco/Util/AbstractConfiguration.h>

namespace MQ
{
namespace Web
{

RequestHandlerFactory::RequestHandlerFactory() : Poco::Net::HTTPRequestHandlerFactory()
{
}

Poco::Net::HTTPRequestHandler* RequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request)
{
	static std::string staticURI = "/static";
	std::string uri = request.getURI();

	Poco::Logger& logger = Poco::Logger::get("mq.web.access");
	logger.information(Poco::Logger::format("IP: $0 URI: $1 ($2)", request.clientAddress().toString(), uri, request.getMethod()));

	if ( ! filter(request) )
	{
		return new DenyRequestHandler();
	}

	if ( ! uri.compare(0, staticURI.size(), staticURI)
		|| ! uri.compare("/favicon.ico") )
	{
		return new StaticRequestHandler();
	}

	return new ControllerRequestHandler();
}

bool RequestHandlerFactory::filter(const Poco::Net::HTTPServerRequest& request)
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");

	bool allowed = true;

	std::string ip = request.clientAddress().host().toString();

	//TODO: move this to Application and exit MQWeb when an invalid regex is found
	static Poco::Util::AbstractConfiguration* allowIPs = Poco::Util::Application::instance().config().createView("mq.web.allow");
	static Poco::Util::AbstractConfiguration* denyIPs = Poco::Util::Application::instance().config().createView("mq.web.deny");

	Poco::Util::AbstractConfiguration::Keys keys;

	allowIPs->keys(keys);
	if ( keys.size() > 0 ) // Check if IP is allowed
	{
		allowed = false;
		for(Poco::Util::AbstractConfiguration::Keys::iterator it = keys.begin(); it != keys.end(); ++it)
		{
			std::string regexValue = allowIPs->getString(*it);
			poco_trace_f3(logger, "IP Allow Check %s : %s (%s)", ip, regexValue, *it);
			Poco::RegularExpression regex(allowIPs->getString(*it));
			if ( regex.match(ip) )
			{
				poco_debug_f2(logger, "IP %s allowed (mq.web.allow.%s matched)", ip, *it);
				allowed = true;
				break;
			}
		}
	}

	denyIPs->keys(keys);
	if ( keys.size() > 0 ) // Check if IP is denied
	{
		for(Poco::Util::AbstractConfiguration::Keys::iterator it = keys.begin(); it != keys.end(); ++it)
		{
			std::string regexValue = denyIPs->getString(*it);

			poco_trace_f3(logger, "IP Deny Check %s : %s (%s)", ip, regexValue, *it);
			Poco::RegularExpression regex(denyIPs->getString(*it));
			if ( regex.match(ip) )
			{
				poco_warning_f2(logger, "IP %s denied (mq.web.deny.%s matched)", ip, *it);
				allowed = false;
				break;
			}
		}
	}

	return allowed;
}

} } // Namespace MQ::Web
<commit_msg>Call registerControllers in constructor<commit_after>/*
 * Copyright 2010 MQWeb - Franky Braem
 *
 * Licensed under the EUPL, Version 1.1 or – as soon they
 * will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 * You may not use this work except in compliance with the
 * Licence.
 * You may obtain a copy of the Licence at:
 *
 * http://joinup.ec.europa.eu/software/page/eupl
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 */
#include <MQ/Web/RequestHandlerFactory.h>
#include <MQ/Web/StaticRequestHandler.h>
#include <MQ/Web/DenyRequestHandler.h>
#include <MQ/Web/ControllerRequestHandler.h>

#include <Poco/Logger.h>
#include <Poco/RegularExpression.h>
#include <Poco/Util/Application.h>
#include <Poco/Util/AbstractConfiguration.h>

namespace MQ
{
namespace Web
{

RequestHandlerFactory::RequestHandlerFactory() : Poco::Net::HTTPRequestHandlerFactory()
{
	ControllerRequestHandler::registerControllers();
}

Poco::Net::HTTPRequestHandler* RequestHandlerFactory::createRequestHandler(const Poco::Net::HTTPServerRequest& request)
{
	static std::string staticURI = "/static";
	std::string uri = request.getURI();

	Poco::Logger& logger = Poco::Logger::get("mq.web.access");
	logger.information(Poco::Logger::format("IP: $0 URI: $1 ($2)", request.clientAddress().toString(), uri, request.getMethod()));

	if ( ! filter(request) )
	{
		return new DenyRequestHandler();
	}

	if ( ! uri.compare(0, staticURI.size(), staticURI)
		|| ! uri.compare("/favicon.ico") )
	{
		return new StaticRequestHandler();
	}

	return new ControllerRequestHandler();
}

bool RequestHandlerFactory::filter(const Poco::Net::HTTPServerRequest& request)
{
	Poco::Logger& logger = Poco::Logger::get("mq.web");

	bool allowed = true;

	std::string ip = request.clientAddress().host().toString();

	//TODO: move this to Application and exit MQWeb when an invalid regex is found
	static Poco::Util::AbstractConfiguration* allowIPs = Poco::Util::Application::instance().config().createView("mq.web.allow");
	static Poco::Util::AbstractConfiguration* denyIPs = Poco::Util::Application::instance().config().createView("mq.web.deny");

	Poco::Util::AbstractConfiguration::Keys keys;

	allowIPs->keys(keys);
	if ( keys.size() > 0 ) // Check if IP is allowed
	{
		allowed = false;
		for(Poco::Util::AbstractConfiguration::Keys::iterator it = keys.begin(); it != keys.end(); ++it)
		{
			std::string regexValue = allowIPs->getString(*it);
			poco_trace_f3(logger, "IP Allow Check %s : %s (%s)", ip, regexValue, *it);
			Poco::RegularExpression regex(allowIPs->getString(*it));
			if ( regex.match(ip) )
			{
				poco_debug_f2(logger, "IP %s allowed (mq.web.allow.%s matched)", ip, *it);
				allowed = true;
				break;
			}
		}
	}

	denyIPs->keys(keys);
	if ( keys.size() > 0 ) // Check if IP is denied
	{
		for(Poco::Util::AbstractConfiguration::Keys::iterator it = keys.begin(); it != keys.end(); ++it)
		{
			std::string regexValue = denyIPs->getString(*it);

			poco_trace_f3(logger, "IP Deny Check %s : %s (%s)", ip, regexValue, *it);
			Poco::RegularExpression regex(denyIPs->getString(*it));
			if ( regex.match(ip) )
			{
				poco_warning_f2(logger, "IP %s denied (mq.web.deny.%s matched)", ip, *it);
				allowed = false;
				break;
			}
		}
	}

	return allowed;
}

} } // Namespace MQ::Web
<|endoftext|>


<commit_before>{
	cout << "rootlogon.C for UCNSIM" << endl;
	cout << "-------------------------------------" << endl;
  	if ( gSystem->Load("libPhysics") == 0 ) {
    cout << "Successfully loaded libPhysics.so" << endl;
  	}
	if ( gSystem->Load("libGeom.so") == 0 ) {
    cout << "Successfully loaded libGeom.so" << endl;
  	}
  	if ( gSystem->Load("libGeomPainter.so") == 0 ) {
    cout << "Successfully loaded libGeomPainter.so" << endl;
  	}
 	if ( gSystem->Load("libTree.so") == 0 ) {
	    cout << "Successfully loaded libTree.so" << endl;
	}
 	if ( gSystem->Load("libEG.so") == 0 ) {
	    cout << "Successfully loaded libEG.so" << endl;
	}
	if ( gSystem->Load("libMathCore.so") == 0 ) {
	    cout << "Successfully loaded libMathCore.so" << endl;
	}
	if ( gSystem->Load("libMathMore.so") == 0 ) {
	    cout << "Successfully loaded libMathCore.so" << endl;
	}
	TString ucnsim = gSystem->Getenv("UCNSIM");
	if ( ucnsim.Length() == 0 ) {
		cerr << "-------------------------------------" << endl;
		cerr << "Warning: Failed to find env. variable UCNSIM" << endl;
		cerr << "-------------------------------------" << endl;
	}
	else {
		TString ucnlib = ucnsim + "/lib/libUCN.so";
		cerr << ucnlib.Data() << endl;
		if ( gSystem->Load(ucnlib.Data()) == 0 ) {
		cout << "Successfully loaded libUCN.so" << endl;
  	}
	}

		cout << "-------------------------------------" << endl;
	set_my_style();
}
<commit_msg>Included loading MagScan libraries in root logon <commit_after>{
	cout << "rootlogon.C for UCNSIM" << endl;
	cout << "-------------------------------------" << endl;
  	if ( gSystem->Load("libPhysics") == 0 ) {
    cout << "Successfully loaded libPhysics.so" << endl;
  	}
	if ( gSystem->Load("libGeom.so") == 0 ) {
    cout << "Successfully loaded libGeom.so" << endl;
  	}
  	if ( gSystem->Load("libGeomPainter.so") == 0 ) {
    cout << "Successfully loaded libGeomPainter.so" << endl;
  	}
 	if ( gSystem->Load("libTree.so") == 0 ) {
	    cout << "Successfully loaded libTree.so" << endl;
	}
 	if ( gSystem->Load("libEG.so") == 0 ) {
	    cout << "Successfully loaded libEG.so" << endl;
	}
	if ( gSystem->Load("libMathCore.so") == 0 ) {
	    cout << "Successfully loaded libMathCore.so" << endl;
	}
	if ( gSystem->Load("libMathMore.so") == 0 ) {
	    cout << "Successfully loaded libMathCore.so" << endl;
	}
	TString ucnsim = gSystem->Getenv("UCNSIM");
	if ( ucnsim.Length() == 0 ) {
		cerr << "-------------------------------------" << endl;
		cerr << "Warning: Failed to find env. variable UCNSIM" << endl;
		cerr << "-------------------------------------" << endl;
	}
	else {
		TString ucnlib = ucnsim + "/lib/libUCN.so";
		cerr << ucnlib.Data() << endl;
		if ( gSystem->Load(ucnlib.Data()) == 0 ) {
		   cout << "Successfully loaded libUCN.so" << endl;
  	   }
	}

   TString magdir = gSystem->Getenv("MAGDIR");
	if ( magdir.Length() == 0 ) {
		cerr << "-------------------------------------" << endl;
		cerr << "Warning: Failed to find env. variable MAGDIR" << endl;
		cerr << "-------------------------------------" << endl;
	}
	else {
		TString maglib = magdir + "/lib/libEDM.so";
		cerr << maglib.Data() << endl;
		if ( gSystem->Load(maglib.Data()) == 0 ) {
		   cout << "Successfully loaded libEDM.so" << endl;
  	   }
   }
	cout << "-------------------------------------" << endl;
	set_my_style();
}
<|endoftext|>


<commit_before>//==================================================================================================
//
//  Copyright(c)  2013 - 2015  Naïo Technologies
//
//  This program is free software: you can redistribute it and/or modify it under the terms of the
//  GNU General Public License as published by the Free Software Foundation, either version 3 of
//  the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with This program.
//  If not, see <http://www.gnu.org/licenses/>.
//
//==================================================================================================

//==================================================================================================
// I N C L U D E   F I L E S

#include "BuildVersion.hpp"
#include "EntryPoint.hpp"

#include <IO/IOBlueFoxStereo.hpp>
#include <IO/JsonReader.hpp>
#include "IO/IOTiffWriter.hpp"
#include "IO/IOBufferWriter.hpp"
#include "IO/IOFileWriter.hpp"
#include "Control/CTPid.hpp"

#include "HTUtility.h"
#include <CLFileSystem.h>

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

//==================================================================================================
// C O N S T A N T S   &   L O C A L   V A R I A B L E S

//==================================================================================================
// G L O B A L S

//==================================================================================================
// C O N S T R U C T O R (S) / D E S T R U C T O R   C O D E   S E C T I O N

//--------------------------------------------------------------------------------------------------
//
EntryPoint::EntryPoint()
	: signaled_{ }
{
	signalHandler_.attach_handler( ht::SignalHandler::Signal::Interrupt,
	                               std::bind( &EntryPoint::set_signal, this ) );

	signalHandler_.attach_handler( ht::SignalHandler::Signal::Termination,
	                               std::bind( &EntryPoint::set_signal, this ) );

	signalHandler_.start_watch();

	// Register program info
	std::string appName{ PROGRAM_NAME };
	appName.append( "-" );
	appName.append( PROGRAM_VERSION_STRING );

	// Set logger output name for the program
	HTLogger::SetExecModuleName( appName );

	auto f = std::bind( &EntryPoint::handle_parameters, this, std::placeholders::_1,
	                    std::placeholders::_2 );

	handler_.AddParamHandler( "-c", f );
	parser_.add_switch( "-c", "Calibrate stereo bench" );
}

//--------------------------------------------------------------------------------------------------
//
EntryPoint::~EntryPoint()
{
	signalHandler_.stop_watch();
}

//==================================================================================================
// M E T H O D S   C O D E   S E C T I O N

//--------------------------------------------------------------------------------------------------
//
void
EntryPoint::set_signal()
{
	signaled_ = true;
	ht::log_warning( "signal received" );
}

//--------------------------------------------------------------------------------------------------
//
bool
EntryPoint::is_signaled() const
{
	return signaled_;
}

//--------------------------------------------------------------------------------------------------
//
void
EntryPoint::print_header() const
{
	using namespace cl;
	print_line( "=============================================================================" );
	print_line( "" );
	print_line( "  ", PROGRAM_NAME, " version ", PROGRAM_VERSION_STRING, "  Copyright(c) 2013  ",
	            PROGRAM_OWNER );
	print_line( "  ", PROGRAM_DESCRIPTION );
	print_line( "" );
	print_line( "  This program is free software: you can redistribute it and/or modify" );
	print_line( "  it under the terms of the GNU General Public License as published by" );
	print_line( "  the Free Software Foundation, either version 3 of the License, or" );
	print_line( "  (at your option) any later version." );
	print_line( "" );
	print_line( "  This program is distributed in the hope that it will be useful," );
	print_line( "  but WITHOUT ANY WARRANTY; without even the implied warranty of" );
	print_line( "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the" );
	print_line( "  GNU General Public License for more details." );
	print_line( "" );
	print_line( "=============================================================================" );
}

//--------------------------------------------------------------------------------------------------
//
bool
EntryPoint::handle_parameters( const std::string& paramName, const std::string& paramValue )
{
	cl::ignore( paramName, paramValue );
	return false;
}

//--------------------------------------------------------------------------------------------------
//
int32_t
EntryPoint::run( int32_t argc, const char** argv )
{
	int32_t res{ EXIT_SUCCESS };
	print_header();

	if( parser_.validate_cmd_line( argc, argv, &handler_ ) )
	{
		std::string resourceFolder{ "resources/" };

		io::JsonReader jsonReader;
		jsonReader.load( resourceFolder.append( "config.json" ) );
		Json::Value benchConfig( jsonReader.root()["stereobench"] );

		const uint32_t width = benchConfig.get( "width", 752 ).asUInt();
		const uint32_t height = benchConfig.get( "height", 480 ).asUInt();
		const uint32_t exposure = benchConfig.get( "exposure", 10000 ).asUInt();
		const uint32_t greyLevelTarget = benchConfig.get( "average_gray_value", 50 ).asUInt();
		const bool autoexp = benchConfig.get( "auto_exposure", false ).asBool();
		const uint32_t minExposure = benchConfig.get( "exposure_min", 12 ).asUInt();
		const uint32_t maxExposure = benchConfig.get( "exposure_max", 20000 ).asUInt();

		cl::ignore( exposure, autoexp );

		const bool hdr = benchConfig.get( "hdr", false ).asBool();

		cv::Size size( static_cast<int32_t>(width), static_cast<int32_t>(height) );

		io::BlueFoxStereo stereoBench;

		io::CameraInfo infoL = stereoBench.get_camera_info( io::BlueFoxStereo::Position::Left );
		io::CameraInfo infoR = stereoBench.get_camera_info( io::BlueFoxStereo::Position::Right );
		io::Intrinsics intrinsicsL, intrinsicsR;
		io::Extrinsics extrinsics;
		uint32_t serialNumL = cl::str_to_uint32( infoL.serialNum );
		uint32_t serialNumR = cl::str_to_uint32( infoR.serialNum );
		uint8_t mode{ 0x01 };

		stereoBench.read_bench_params( intrinsicsL, intrinsicsR, extrinsics );

		std::string dateStr{ };
		CLDate date;
		date.GetDateAndTimeMIMEFormat( dateStr );
		cl::filesystem::folder_create( dateStr );

		cl::print_line( "Recording session in: ", dateStr );

		size_t allParamSize = sizeof( mode ) + sizeof( serialNumL ) + sizeof( io::Intrinsics ) +
		                      sizeof( serialNumR ) + sizeof( io::Intrinsics ) +
		                      sizeof( io::Extrinsics );

		io::BufferWriter bufferWriter( allParamSize );

		bufferWriter.write( mode );

		bufferWriter.write( serialNumL );
		io::IntrinsicsArray intrinsicsArrayL = intrinsicsL.to_array();
		bufferWriter.write_array( intrinsicsArrayL.data(), intrinsicsArrayL.size() );

		bufferWriter.write( serialNumR );
		io::IntrinsicsArray intrinsicsArrayR = intrinsicsR.to_array();
		bufferWriter.write_array( intrinsicsArrayR.data(), intrinsicsArrayR.size() );

		io::ExtrinsicsArray extrinsicsArray = extrinsics.to_array();
		bufferWriter.write_array( extrinsicsArray.data(), extrinsicsArray.size() );

		const std::string filePathP = cl::filesystem::create_filespec( dateStr, "params", "bin" );

		io::write_buffer_to_file( filePathP, bufferWriter.get_buffer() );

		stereoBench.start( ht::ColorSpace::Rgb, width, height, minExposure, maxExposure, hdr );

		control::Pid pid;
		pid.set_pid_gains( 3, 0, 0 );

		int32_t currentExposure{ static_cast<int32_t>(maxExposure) };

		int8_t pressed{ };
		while( !is_signaled() && pressed != 27 )
		{
			cm::BitmapPairEntryUniquePtr entry;
			stereoBench.wait_entry( entry );

			stereoBench.clear_entry_buffer();

			const std::string filePath =
				cl::filesystem::create_filespec( dateStr, std::to_string( entry->get_id() ),
				                                 io::tiff_file_extensions()[1] );

			io::TiffWriter tiffWriter{ filePath };
			tiffWriter.write_to_file( entry->bitmap_left(), entry->get_id(),
			                          entry->get_framerate() );
			tiffWriter.write_to_file( entry->bitmap_right(), entry->get_id(),
			                          entry->get_framerate() );

			cv::Mat matL = cv::Mat( size, CV_8UC3 );
			cv::Mat matR = cv::Mat( size, CV_8UC3 );

			cv::Mat bgrL = cv::Mat( size, CV_8UC3 );
			cv::Mat bgrR = cv::Mat( size, CV_8UC3 );

			cv::Mat greyL = cv::Mat( size, CV_8UC1 );
			cv::Mat greyR = cv::Mat( size, CV_8UC1 );

			matL.data = entry->bitmap_left().data();
			matR.data = entry->bitmap_right().data();

			cv::cvtColor( matL, bgrL, CV_RGB2BGR );
			cv::cvtColor( matR, bgrR, CV_RGB2BGR );

			cv::cvtColor( matL, greyL, CV_RGB2GRAY );
			cv::cvtColor( matR, greyR, CV_RGB2GRAY );

			int32_t greyLevelL{ };
			int32_t greyLevelR{ };

			for( int32_t i = 0; i < greyL.rows; ++i )
			{
				for( int32_t j = 0; j < greyL.cols; ++j )
				{
					greyLevelL += greyL.at< uint8_t >( i, j );
					greyLevelR += greyR.at< uint8_t >( i, j );
				}
			}

			greyLevelL /= greyL.rows * greyL.cols;
			greyLevelR /= greyL.rows * greyL.cols;

			const int32_t greyLevel = (greyLevelL + greyLevelR) / 2;
			const int32_t greyLevelDiff = static_cast<int32_t>(greyLevelTarget) - greyLevel;

			const int32_t correctedExposureError =
				static_cast<int32_t>(std::round(
					pid.compute_correction( static_cast<double>(greyLevelDiff) ) ));

			currentExposure += correctedExposureError;

			//cl::print_line( greyLevelDiff, "; ", currentExposure );

			if( currentExposure < 12 )
			{
				currentExposure = 12;
			}
			else if( currentExposure > 20000 )
			{
				currentExposure = 20000;
			}

			stereoBench.set_exposure( static_cast<uint32_t>(currentExposure) );

			cv::Mat combine( std::max( bgrL.size().height, bgrR.size().height ),
			                 bgrL.size().width + bgrR.size().width, CV_8UC3 );

			cv::Mat left_roi( combine, cv::Rect( 0, 0, bgrL.size().width, bgrL.size().height ) );
			bgrL.copyTo( left_roi );

			cv::Mat right_roi( combine, cv::Rect( bgrL.size().width, 0, bgrR.size().width,
			                                      bgrR.size().height ) );
			bgrR.copyTo( right_roi );

			cv::imshow( "images", combine );

			pressed = static_cast<int8_t>(cv::waitKey( 10 ));
		}
		stereoBench.stop();
	}

	return res;
}

//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//----------------------------------------- Main Function ------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------

int32_t
main( int32_t argc, const char** argv )
{
	int32_t ret{ EXIT_SUCCESS };

	try
	{
		ret = EntryPoint().run( argc, argv );
	}
	catch( const cl::SystemError& e )
	{
		ht::log_fatal( "System Error: ", e.what(), e.where() );
		throw;
	}
	catch( const cl::BaseException& e )
	{
		ht::log_fatal( "BaseException caught: ", e.what() );
		throw;
	}
	catch( const std::exception& e )
	{
		ht::log_fatal( "std::exception caught: ", e.what() );
		throw;
	}
	catch( ... )
	{
		ht::log_fatal( "Caught an exception of an undetermined type" );
		throw;
	}

	return ret;
}
<commit_msg>stereo capture with bench params<commit_after>//==================================================================================================
//
//  Copyright(c)  2013 - 2015  Naïo Technologies
//
//  This program is free software: you can redistribute it and/or modify it under the terms of the
//  GNU General Public License as published by the Free Software Foundation, either version 3 of
//  the License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//  See the GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License along with This program.
//  If not, see <http://www.gnu.org/licenses/>.
//
//==================================================================================================

//==================================================================================================
// I N C L U D E   F I L E S

#include "BuildVersion.hpp"
#include "EntryPoint.hpp"

#include <IO/IOBlueFoxStereo.hpp>
#include <IO/JsonReader.hpp>
#include "IO/IOTiffWriter.hpp"
#include "IO/IOBufferWriter.hpp"
#include "IO/IOFileWriter.hpp"
#include "Control/CTPid.hpp"
#include "VisionModule/VMConversion.hpp"
#include "VisionModule/VMStatistics.hpp"

#include "HTUtility.h"
#include "HTBitmap.hpp"
#include "CLFileSystem.h"

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

//==================================================================================================
// C O N S T A N T S   &   L O C A L   V A R I A B L E S

//==================================================================================================
// G L O B A L S

//==================================================================================================
// C O N S T R U C T O R (S) / D E S T R U C T O R   C O D E   S E C T I O N

//--------------------------------------------------------------------------------------------------
//
EntryPoint::EntryPoint()
	: signaled_{ }
{
	signalHandler_.attach_handler( ht::SignalHandler::Signal::Interrupt,
	                               std::bind( &EntryPoint::set_signal, this ) );

	signalHandler_.attach_handler( ht::SignalHandler::Signal::Termination,
	                               std::bind( &EntryPoint::set_signal, this ) );

	signalHandler_.start_watch();

	// Register program info
	std::string appName{ PROGRAM_NAME };
	appName.append( "-" );
	appName.append( PROGRAM_VERSION_STRING );

	// Set logger output name for the program
	HTLogger::SetExecModuleName( appName );

	auto f = std::bind( &EntryPoint::handle_parameters, this, std::placeholders::_1,
	                    std::placeholders::_2 );

	handler_.AddParamHandler( "-c", f );
	parser_.add_switch( "-c", "Calibrate stereo bench" );
}

//--------------------------------------------------------------------------------------------------
//
EntryPoint::~EntryPoint()
{
	signalHandler_.stop_watch();
}

//==================================================================================================
// M E T H O D S   C O D E   S E C T I O N

//--------------------------------------------------------------------------------------------------
//
void
EntryPoint::set_signal()
{
	signaled_ = true;
	ht::log_warning( "signal received" );
}

//--------------------------------------------------------------------------------------------------
//
bool
EntryPoint::is_signaled() const
{
	return signaled_;
}

//--------------------------------------------------------------------------------------------------
//
void
EntryPoint::print_header() const
{
	using namespace cl;
	print_line( "=============================================================================" );
	print_line( "" );
	print_line( "  ", PROGRAM_NAME, " version ", PROGRAM_VERSION_STRING, "  Copyright(c) 2013  ",
	            PROGRAM_OWNER );
	print_line( "  ", PROGRAM_DESCRIPTION );
	print_line( "" );
	print_line( "  This program is free software: you can redistribute it and/or modify" );
	print_line( "  it under the terms of the GNU General Public License as published by" );
	print_line( "  the Free Software Foundation, either version 3 of the License, or" );
	print_line( "  (at your option) any later version." );
	print_line( "" );
	print_line( "  This program is distributed in the hope that it will be useful," );
	print_line( "  but WITHOUT ANY WARRANTY; without even the implied warranty of" );
	print_line( "  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the" );
	print_line( "  GNU General Public License for more details." );
	print_line( "" );
	print_line( "=============================================================================" );
}

//--------------------------------------------------------------------------------------------------
//
bool
EntryPoint::handle_parameters( const std::string& paramName, const std::string& paramValue )
{
	cl::ignore( paramName, paramValue );
	return false;
}

//--------------------------------------------------------------------------------------------------
//
int32_t
EntryPoint::run( int32_t argc, const char** argv )
{
	int32_t res{ EXIT_SUCCESS };
	print_header();

	if( parser_.validate_cmd_line( argc, argv, &handler_ ) )
	{
		std::string resourceFolder{ "resources/" };

		io::JsonReader jsonReader;
		jsonReader.load( resourceFolder.append( "config.json" ) );
		Json::Value benchConfig( jsonReader.root()["stereobench"] );

		const uint32_t width = benchConfig.get( "width", 752 ).asUInt();
		const uint32_t height = benchConfig.get( "height", 480 ).asUInt();
		const uint32_t exposure = benchConfig.get( "exposure", 10000 ).asUInt();
		const uint32_t greyLevelTarget = benchConfig.get( "average_gray_value", 50 ).asUInt();
		const bool autoexp = benchConfig.get( "auto_exposure", false ).asBool();
		const uint32_t minExposure = benchConfig.get( "exposure_min", 12 ).asUInt();
		const uint32_t maxExposure = benchConfig.get( "exposure_max", 20000 ).asUInt();

		cl::ignore( exposure, autoexp );

		const bool hdr = benchConfig.get( "hdr", false ).asBool();

		cv::Size size( static_cast<int32_t>(width), static_cast<int32_t>(height) );

		io::BlueFoxStereo stereoBench;

		io::CameraInfo infoL = stereoBench.get_camera_info( io::BlueFoxStereo::Position::Left );
		io::CameraInfo infoR = stereoBench.get_camera_info( io::BlueFoxStereo::Position::Right );
		io::Intrinsics intrinsicsL, intrinsicsR;
		io::Extrinsics extrinsics;
		uint32_t serialNumL = cl::str_to_uint32( infoL.serialNum );
		uint32_t serialNumR = cl::str_to_uint32( infoR.serialNum );
		uint8_t mode{ 0x01 };

		stereoBench.read_bench_params( intrinsicsL, intrinsicsR, extrinsics );

		std::string dateStr{ };
		CLDate date;
		date.GetDateAndTimeMIMEFormat( dateStr );
		cl::filesystem::folder_create( dateStr );

		cl::print_line( "Recording session in: ", dateStr );

		size_t allParamSize = sizeof( mode ) + sizeof( serialNumL ) + sizeof( io::Intrinsics ) +
		                      sizeof( serialNumR ) + sizeof( io::Intrinsics ) +
		                      sizeof( io::Extrinsics );

		io::BufferWriter bufferWriter( allParamSize );

		bufferWriter.write( mode );

		bufferWriter.write( serialNumL );
		io::IntrinsicsArray intrinsicsArrayL = intrinsicsL.to_array();
		bufferWriter.write_array( intrinsicsArrayL.data(), intrinsicsArrayL.size() );

		bufferWriter.write( serialNumR );
		io::IntrinsicsArray intrinsicsArrayR = intrinsicsR.to_array();
		bufferWriter.write_array( intrinsicsArrayR.data(), intrinsicsArrayR.size() );

		io::ExtrinsicsArray extrinsicsArray = extrinsics.to_array();
		bufferWriter.write_array( extrinsicsArray.data(), extrinsicsArray.size() );

		const std::string filePathP = cl::filesystem::create_filespec( dateStr, "capture", "bin" );

		io::write_buffer_to_file( filePathP, bufferWriter.get_buffer() );

		stereoBench.start( ht::ColorSpace::RGB, width, height, minExposure, maxExposure, hdr );

		control::Pid pid;
		pid.set_pid_gains( 3, 0, 0 );

		int32_t currentExposure{ static_cast<int32_t>(maxExposure) };

		size_t nbr{ };
		int8_t pressed{ };
		while( !is_signaled() && pressed != 27 )
		{
			cm::BitmapPairEntryUniquePtr entry;
			stereoBench.wait_entry( entry );

			stereoBench.clear_entry_buffer();

			ht::BitmapUPtr grayL = ht::unique_bitmap( entry->bitmap_left().width(),
			                                          entry->bitmap_left().height(),
			                                          entry->bitmap_left().bit_depth(),
			                                          ht::ColorSpace::Grayscale );

			ht::BitmapUPtr grayR = ht::unique_bitmap( entry->bitmap_left().width(),
			                                          entry->bitmap_left().height(),
			                                          entry->bitmap_left().bit_depth(),
			                                          ht::ColorSpace::Grayscale );

			vm::rgb_to_bgr( entry->bitmap_left(), *grayL );
			vm::rgb_to_bgr( entry->bitmap_right(), *grayR );

			ht::BitmapUPtr bgrL = ht::unique_bitmap( entry->bitmap_left().width(),
			                                         entry->bitmap_left().height(),
			                                         entry->bitmap_left().bit_depth(),
			                                         ht::ColorSpace::BGR );

			ht::BitmapUPtr bgrR = ht::unique_bitmap( entry->bitmap_left().width(),
			                                         entry->bitmap_left().height(),
			                                         entry->bitmap_left().bit_depth(),
			                                         ht::ColorSpace::BGR );

			vm::rgb_to_bgr( entry->bitmap_left(), *bgrL );
			vm::rgb_to_bgr( entry->bitmap_right(), *bgrR );

			double greyLevelL{ };
			double greyLevelR{ };

			vm::mean( *grayL, greyLevelL );
			vm::mean( *grayR, greyLevelR );

			const double greyLevel = ( greyLevelL + greyLevelR ) / 2;
			const int32_t greyLevelDiff = static_cast<int32_t>(greyLevelTarget) - greyLevel;

			const int32_t correctedExposureError =
				static_cast<int32_t>(std::round(
					pid.compute_correction( static_cast<double>(greyLevelDiff) ) ));

			currentExposure += correctedExposureError;

			if( currentExposure < 12 )
			{
				currentExposure = 12;
			}
			else if( currentExposure > 20000 )
			{
				currentExposure = 20000;
			}

			stereoBench.set_exposure( static_cast<uint32_t>(currentExposure) );

			cv::Mat matL = cv::Mat( size, CV_8UC3 );
			cv::Mat matR = cv::Mat( size, CV_8UC3 );

			matL.data = entry->bitmap_left().data();
			matR.data = entry->bitmap_right().data();

			cv::Mat combine( std::max( matL.size().height, matR.size().height ),
			                 matL.size().width + matR.size().width, CV_8UC3 );

			cv::Mat left_roi( combine, cv::Rect( 0, 0, matL.size().width, matL.size().height ) );
			matL.copyTo( left_roi );

			cv::Mat right_roi( combine, cv::Rect( matL.size().width, 0, matR.size().width,
			                                      matR.size().height ) );
			matR.copyTo( right_roi );

			cv::imshow( "images", combine );

			pressed = static_cast<int8_t>( cv::waitKey( 1 ) );
		}
		stereoBench.stop();
	}

	return res;
}

//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
//----------------------------------------- Main Function ------------------------------------------
//--------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------

int32_t
main( int32_t argc, const char** argv )
{
	int32_t ret{ EXIT_SUCCESS };

	try
	{
		ret = EntryPoint().run( argc, argv );
	}
	catch( const cl::SystemError& e )
	{
		ht::log_fatal( "System Error: ", e.what(), e.where() );
		throw;
	}
	catch( const cl::BaseException& e )
	{
		ht::log_fatal( "BaseException caught: ", e.what() );
		throw;
	}
	catch( const std::exception& e )
	{
		ht::log_fatal( "std::exception caught: ", e.what() );
		throw;
	}
	catch( ... )
	{
		ht::log_fatal( "Caught an exception of an undetermined type" );
		throw;
	}

	return ret;
}
<|endoftext|>


<commit_before>#include "detail/LuaPbIntfImpl.h"

#include <google/protobuf/message.h>
#include <LuaIntf/LuaIntf.h>

#include <iostream>  // for cout
#include <memory>  // for shared_ptr

namespace LuaIntf
{
    LUA_USING_SHARED_PTR_TYPE(std::shared_ptr)
}

namespace {

void test()
{
    std::cout << "test...\n";
}

}  // namespace

extern "C"
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)
__declspec(dllexport)
#endif
int luaopen_luapbintf(lua_State* L)
{
    using string = std::string;
    using Message = google::protobuf::Message;
    using namespace LuaIntf;

    auto pImpl = std::make_shared<LuaPbIntfImpl>();
    LuaRef mod = LuaRef::createTable(L);
    LuaBinding(mod)
        .addFunction("test", &test)

        .addFunction("add_proto_path",
            [pImpl](const string& sProtoPath) {
                pImpl->AddProtoPath(sProtoPath);
            })
        .addFunction("map_path",
            [pImpl](const string& sVirtualPath, const string& sDiskPath) {
                pImpl->MapPath(sVirtualPath, sDiskPath);
            })
        // Input file must be relative to proto paths.
        .addFunction("compile_proto_file",
            [pImpl](const string& sProtoFile) {
                return pImpl->CompileProtoFile(sProtoFile);
            })

        .beginClass<Message>("Message")
            .addFactory([pImpl](const std::string& sTypeName) {
                    return pImpl->MakeSharedMessage(sTypeName);  // maybe nullptr
                })
            .addFunction("debug_string", &Message::DebugString)
            .addFunction("short_debug_string", &Message::ShortDebugString)
            .addFunction("utf8_debug_string", &Message::Utf8DebugString)
            .addFunction("utf8_debug_string", &Message::Utf8DebugString)
            .addPropertyReadOnly("type_name", &Message::GetTypeName)
            .addFunction("clear", &Message::Clear)
            .addPropertyReadOnly("is_initialized", &Message::IsInitialized)
            .addPropertyReadOnly("byte_size_long", &Message::ByteSizeLong)
        .endClass()

        ;
    mod.pushToStack();
    return 1;
}
<commit_msg>Bind parse() and serialize() methods.<commit_after>#include "detail/LuaPbIntfImpl.h"

#include <google/protobuf/message.h>
#include <LuaIntf/LuaIntf.h>

#include <iostream>  // for cout
#include <memory>  // for shared_ptr

namespace LuaIntf
{
    LUA_USING_SHARED_PTR_TYPE(std::shared_ptr)
}

namespace {

void test()
{
    std::cout << "test...\n";
}

}  // namespace

extern "C"
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__)
__declspec(dllexport)
#endif
int luaopen_luapbintf(lua_State* L)
{
    using string = std::string;
    using Message = google::protobuf::Message;
    using namespace LuaIntf;

    auto pImpl = std::make_shared<LuaPbIntfImpl>();
    LuaRef mod = LuaRef::createTable(L);
    LuaBinding(mod)
        .addFunction("test", &test)

        .addFunction("add_proto_path",
            [pImpl](const string& sProtoPath) {
                pImpl->AddProtoPath(sProtoPath);
            })
        .addFunction("map_path",
            [pImpl](const string& sVirtualPath, const string& sDiskPath) {
                pImpl->MapPath(sVirtualPath, sDiskPath);
            })
        // Input file must be relative to proto paths.
        .addFunction("compile_proto_file",
            [pImpl](const string& sProtoFile) {
                return pImpl->CompileProtoFile(sProtoFile);
            })

        .beginClass<Message>("Message")
            .addFactory([pImpl](const std::string& sTypeName) {
                    return pImpl->MakeSharedMessage(sTypeName);  // maybe nullptr
                })
            .addFunction("debug_string", &Message::DebugString)
            .addFunction("short_debug_string", &Message::ShortDebugString)
            .addFunction("utf8_debug_string", &Message::Utf8DebugString)
            .addFunction("utf8_debug_string", &Message::Utf8DebugString)
            .addPropertyReadOnly("type_name", &Message::GetTypeName)
            .addFunction("clear", &Message::Clear)
            .addPropertyReadOnly("is_initialized", &Message::IsInitialized)
            .addPropertyReadOnly("byte_size", &Message::ByteSizeLong)

            // MessageLite API
            .addFunction("parse", &Message::ParseFromString)
            .addFunction("parse_partial", &Message::ParsePartialFromString)
            .addFunction("serialize", &Message::SerializeAsString)
            .addFunction("serialize_partial", &Message::SerializePartialAsString)

        .endClass()

        ;
    mod.pushToStack();
    return 1;
}
<|endoftext|>


<commit_before>#include "MPBuilder.h"

MPBuilder::MPBuilder(const BMessage &msg, const BMessenger &msgr, BString windowTitle, int ideaID)
	:	BWindow(BRect(100, 100, 900, 700), windowTitle, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS, B_CURRENT_WORKSPACE), launcherMessage(msg), launcherMessenger(msgr)
{
	// initialize controls
	BRect r = Bounds();
	r.bottom = r.bottom - 50;
	availableThoughtListView = new BListView(BRect(10, 10, 100, 30), NULL, B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL, B_WILL_DRAW);
	orderedThoughtListView = new BListView(BRect(10, 10, 100, 30), NULL, B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL, B_WILL_DRAW);
	builderTextView = new BTextView(BRect(0, 0, r.right, 100), NULL, BRect(10, 10, r.right, 100), B_FOLLOW_ALL, B_WILL_DRAW);
	rightButton = new BButton(BRect(10, 10, 90, 35), NULL, ">", new BMessage(MOVE_RIGHT), B_FOLLOW_NONE, B_WILL_DRAW);
	leftButton = new BButton(BRect(10, 10, 90, 35), NULL, "<", new BMessage(MOVE_LEFT), B_FOLLOW_NONE, B_WILL_DRAW);
	topButton = new BButton(BRect(10, 10, 90, 35), NULL, "TOP", new BMessage(MOVE_TOP), B_FOLLOW_NONE, B_WILL_DRAW);
	upButton = new BButton(BRect(10, 10, 90, 35), NULL, "UP", new BMessage(MOVE_UP), B_FOLLOW_NONE, B_WILL_DRAW);
	downButton = new BButton(BRect(10, 10, 90, 35), NULL, "DOWN", new BMessage(MOVE_DOWN), B_FOLLOW_NONE, B_WILL_DRAW);
	bottomButton = new BButton(BRect(10, 10, 90, 35), NULL, "BOTTOM", new BMessage(MOVE_BOTTOM), B_FOLLOW_NONE, B_WILL_DRAW);
	backView = new BView(Bounds(), "backview", B_FOLLOW_ALL, B_WILL_DRAW);
	backView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	AddChild(backView);
	// gui layout builder
	backView->SetLayout(new BGroupLayout(B_HORIZONTAL, 0.0));
	backView->AddChild(BGridLayoutBuilder()
		.Add(new BuilderMenu(), 0, 0, 10, 1)
		.Add(new BStringView(BRect(10, 10, 200, 30), NULL, "All Available Thoughts"), 0, 1)
		.Add(new BStringView(BRect(10, 10, 200, 30), NULL, "Ordered Thoughts"), 5, 1)
		.Add(new BScrollView("scroll_available", availableThoughtListView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 0, 2, 4, 10)
		.Add(rightButton, 4, 4)
		.Add(leftButton, 4, 5)
		.Add(topButton, 4, 6)
		.Add(upButton, 4, 7)
		.Add(downButton, 4, 8)
		.Add(bottomButton, 4, 9)
		.Add(new BScrollView("scroll_ordered", orderedThoughtListView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 5, 2, 5, 10)
		.Add(new BScrollView("scroll_editor", builderTextView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 0, 12, 10, 5)
		.SetInsets(0, 0, 0, 0)
	);

	currentideaID = ideaID; // pass current idea id selected to builder window to use

	mpdb = OpenSqliteDB(); // open mpdb db
	if(mpdb == NULL) // if db doesn't exist
	{
		eAlert = new ErrorAlert("1.21 Sql Error: Sql DB was not opened properly");
		eAlert->Launch();
	}
	else
	{
		PopulateBuilderListViews();
		availableThoughtListView->SetSelectionMessage(new BMessage(DISPLAY_AVAIL_TEXT));
		availableThoughtListView->SetInvocationMessage(new BMessage(MOVE_RIGHT));
		orderedThoughtListView->SetSelectionMessage(new BMessage(DISPLAY_ORDER_TEXT));
		orderedThoughtListView->SetInvocationMessage(new BMessage(MOVE_LEFT));
	}
}
void MPBuilder::MessageReceived(BMessage* msg)
{
	switch(msg->what)
	{
		case MOVE_RIGHT: // add item to ordered list
			selected = availableThoughtListView->CurrentSelection(); // selected list item value
			if(selected >= 0) // if something is selected
			{
				IdeaStringItem* item;
				item = dynamic_cast<IdeaStringItem*>(availableThoughtListView->ItemAt(selected));
				// perform sql to move it to the right ordered side by using currentideaID
				// update ideatable set mpid = currentideaID, ordernumber = [orderedlistview->CountItems()] where ideaid = item->ReturnID()

			}
			break;
		case DISPLAY_AVAIL_TEXT: // display preview text from item id
			selected = availableThoughtListView->CurrentSelection(); // selected list item value
			if(selected >= 0) // if something is selected
			{
				IdeaStringItem* item;
				item = dynamic_cast<IdeaStringItem*>(availableThoughtListView->ItemAt(selected));
				builderTextView->SetText(item->ReturnText());
			}
			break;
		case DISPLAY_ORDER_TEXT: // display preview text from item id
			selected = orderedThoughtListView->CurrentSelection(); // selected list item value
			if(selected >= 0) // if something is selected
			{
				IdeaStringItem* item;
				item = dynamic_cast<IdeaStringItem*>(orderedThoughtListView->ItemAt(selected));
				builderTextView->SetText(item->ReturnText());
			}
			break;
		case MOVE_LEFT:
			break;
		default:
		{
			BWindow::MessageReceived(msg);
			break;
		}
	}
}
bool MPBuilder::QuitRequested(void)
{
	// on quit, show launcher with message
	launcherMessage.MakeEmpty();
	launcherMessage.AddInt64("showLauncher", 1);
	launcherMessenger.SendMessage(&launcherMessage);
	return true;
}
void MPBuilder::PopulateBuilderListViews(void)
{
	availableThoughtListView->MakeEmpty();
	orderedThoughtListView->MakeEmpty();
	sqlValue = sqlite3_prepare_v2(mpdb, "select ideaname, ideaid, ideatext from ideatable where ismp = 0 and mpid is null", -1, &ideaStatement, NULL);
	if(sqlValue == SQLITE_OK) // sql statement was prepared
	{
		while(sqlite3_step(ideaStatement) == SQLITE_ROW) // step through the sql return values
		{
			availableThoughtListView->AddItem(new IdeaStringItem(sqlite3_mprintf("%s", sqlite3_column_text(ideaStatement, 0)), sqlite3_mprintf("%s", sqlite3_column_text(ideaStatement, 2)),sqlite3_column_int(ideaStatement, 1)));
		}
	}
	else // sql select failed
	{
		eAlert = new ErrorAlert("1.22 Sql Error: No Available Thoughts Exist. Please Create Some First.");
		eAlert->Launch();
	}
	sqlite3_finalize(ideaStatement); // finish with sql statement
	if(currentideaID != -1) // if id has a real value...
	{
		// populate the ordered list items from here with the information from passed id...
		sqlValue = sqlite3_prepare_v2(mpdb, "select ideaname, ideatext, ismp, mpid, ordernumber, ideaid from ideatable where ismp=0 and mpid=? order by ordernumber", -1, &ideaStatement, NULL);
		if(sqlValue == SQLITE_OK) // sql statement was prepared
		{
			if(sqlite3_bind_int(ideaStatement, 1, currentideaID) == SQLITE_OK)
			{
				while(sqlite3_step(ideaStatement) == SQLITE_ROW) // step through the sql return values
				{
					orderedThoughtListView->AddItem(new IdeaStringItem(sqlite3_mprintf("%d. %s", sqlite3_column_int(ideaStatement, 4), sqlite3_column_text(ideaStatement, 0)), sqlite3_mprintf("%s", sqlite3_column_text(ideaStatement, 1)), sqlite3_column_int(ideaStatement, 2), sqlite3_column_int(ideaStatement, 3), sqlite3_column_int(ideaStatement, 4), sqlite3_column_int(ideaStatement, 5)));
				}
			}
			else
			{
				eAlert = new ErrorAlert("1.24 Sql Error: Sql bind failed.");
				eAlert->Launch();
			}
		}
		else // sql select failed
		{
			eAlert = new ErrorAlert("1.23 Sql Error: No Ordered Thoughts Exist.  Please Add Some First.");
			eAlert->Launch();
		}
		sqlite3_finalize(ideaStatement); // finish with sql statement
	}
}
<commit_msg>decided double click would open the thought editor<commit_after>#include "MPBuilder.h"

MPBuilder::MPBuilder(const BMessage &msg, const BMessenger &msgr, BString windowTitle, int ideaID)
	:	BWindow(BRect(100, 100, 900, 700), windowTitle, B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS, B_CURRENT_WORKSPACE), launcherMessage(msg), launcherMessenger(msgr)
{
	// initialize controls
	BRect r = Bounds();
	r.bottom = r.bottom - 50;
	availableThoughtListView = new BListView(BRect(10, 10, 100, 30), NULL, B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL, B_WILL_DRAW);
	orderedThoughtListView = new BListView(BRect(10, 10, 100, 30), NULL, B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL, B_WILL_DRAW);
	builderTextView = new BTextView(BRect(0, 0, r.right, 100), NULL, BRect(10, 10, r.right, 100), B_FOLLOW_ALL, B_WILL_DRAW);
	rightButton = new BButton(BRect(10, 10, 90, 35), NULL, ">", new BMessage(MOVE_RIGHT), B_FOLLOW_NONE, B_WILL_DRAW);
	leftButton = new BButton(BRect(10, 10, 90, 35), NULL, "<", new BMessage(MOVE_LEFT), B_FOLLOW_NONE, B_WILL_DRAW);
	topButton = new BButton(BRect(10, 10, 90, 35), NULL, "TOP", new BMessage(MOVE_TOP), B_FOLLOW_NONE, B_WILL_DRAW);
	upButton = new BButton(BRect(10, 10, 90, 35), NULL, "UP", new BMessage(MOVE_UP), B_FOLLOW_NONE, B_WILL_DRAW);
	downButton = new BButton(BRect(10, 10, 90, 35), NULL, "DOWN", new BMessage(MOVE_DOWN), B_FOLLOW_NONE, B_WILL_DRAW);
	bottomButton = new BButton(BRect(10, 10, 90, 35), NULL, "BOTTOM", new BMessage(MOVE_BOTTOM), B_FOLLOW_NONE, B_WILL_DRAW);
	backView = new BView(Bounds(), "backview", B_FOLLOW_ALL, B_WILL_DRAW);
	backView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	AddChild(backView);
	// gui layout builder
	backView->SetLayout(new BGroupLayout(B_HORIZONTAL, 0.0));
	backView->AddChild(BGridLayoutBuilder()
		.Add(new BuilderMenu(), 0, 0, 10, 1)
		.Add(new BStringView(BRect(10, 10, 200, 30), NULL, "All Available Thoughts"), 0, 1)
		.Add(new BStringView(BRect(10, 10, 200, 30), NULL, "Ordered Thoughts"), 5, 1)
		.Add(new BScrollView("scroll_available", availableThoughtListView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 0, 2, 4, 10)
		.Add(rightButton, 4, 4)
		.Add(leftButton, 4, 5)
		.Add(topButton, 4, 6)
		.Add(upButton, 4, 7)
		.Add(downButton, 4, 8)
		.Add(bottomButton, 4, 9)
		.Add(new BScrollView("scroll_ordered", orderedThoughtListView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 5, 2, 5, 10)
		.Add(new BScrollView("scroll_editor", builderTextView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 0, 12, 10, 5)
		.SetInsets(0, 0, 0, 0)
	);

	currentideaID = ideaID; // pass current idea id selected to builder window to use

	mpdb = OpenSqliteDB(); // open mpdb db
	if(mpdb == NULL) // if db doesn't exist
	{
		eAlert = new ErrorAlert("1.21 Sql Error: Sql DB was not opened properly");
		eAlert->Launch();
	}
	else
	{
		PopulateBuilderListViews();
		availableThoughtListView->SetSelectionMessage(new BMessage(DISPLAY_AVAIL_TEXT));
		//availableThoughtListView->SetInvocationMessage(new BMessage(MOVE_RIGHT));
		// double clicking should open the thought editor with the id and information displayed...
		orderedThoughtListView->SetSelectionMessage(new BMessage(DISPLAY_ORDER_TEXT));
		//orderedThoughtListView->SetInvocationMessage(new BMessage(MOVE_LEFT));
	}
}
void MPBuilder::MessageReceived(BMessage* msg)
{
	switch(msg->what)
	{
		case MOVE_RIGHT: // add item to ordered list
			selected = availableThoughtListView->CurrentSelection(); // selected list item value
			if(selected >= 0) // if something is selected
			{
				IdeaStringItem* item;
				item = dynamic_cast<IdeaStringItem*>(availableThoughtListView->ItemAt(selected));
				// perform sql to move it to the right ordered side by using currentideaID
				// update ideatable set mpid = currentideaID, ordernumber = [orderedlistview->CountItems()] where ideaid = item->ReturnID()

			}
			break;
		case DISPLAY_AVAIL_TEXT: // display preview text from item id
			selected = availableThoughtListView->CurrentSelection(); // selected list item value
			if(selected >= 0) // if something is selected
			{
				IdeaStringItem* item;
				item = dynamic_cast<IdeaStringItem*>(availableThoughtListView->ItemAt(selected));
				builderTextView->SetText(item->ReturnText());
			}
			break;
		case DISPLAY_ORDER_TEXT: // display preview text from item id
			selected = orderedThoughtListView->CurrentSelection(); // selected list item value
			if(selected >= 0) // if something is selected
			{
				IdeaStringItem* item;
				item = dynamic_cast<IdeaStringItem*>(orderedThoughtListView->ItemAt(selected));
				builderTextView->SetText(item->ReturnText());
			}
			break;
		case MOVE_LEFT:
			break;
		default:
		{
			BWindow::MessageReceived(msg);
			break;
		}
	}
}
bool MPBuilder::QuitRequested(void)
{
	// on quit, show launcher with message
	launcherMessage.MakeEmpty();
	launcherMessage.AddInt64("showLauncher", 1);
	launcherMessenger.SendMessage(&launcherMessage);
	return true;
}
void MPBuilder::PopulateBuilderListViews(void)
{
	availableThoughtListView->MakeEmpty();
	orderedThoughtListView->MakeEmpty();
	sqlValue = sqlite3_prepare_v2(mpdb, "select ideaname, ideaid, ideatext from ideatable where ismp = 0 and mpid is null", -1, &ideaStatement, NULL);
	if(sqlValue == SQLITE_OK) // sql statement was prepared
	{
		while(sqlite3_step(ideaStatement) == SQLITE_ROW) // step through the sql return values
		{
			availableThoughtListView->AddItem(new IdeaStringItem(sqlite3_mprintf("%s", sqlite3_column_text(ideaStatement, 0)), sqlite3_mprintf("%s", sqlite3_column_text(ideaStatement, 2)),sqlite3_column_int(ideaStatement, 1)));
		}
	}
	else // sql select failed
	{
		eAlert = new ErrorAlert("1.22 Sql Error: No Available Thoughts Exist. Please Create Some First.");
		eAlert->Launch();
	}
	sqlite3_finalize(ideaStatement); // finish with sql statement
	if(currentideaID != -1) // if id has a real value...
	{
		// populate the ordered list items from here with the information from passed id...
		sqlValue = sqlite3_prepare_v2(mpdb, "select ideaname, ideatext, ismp, mpid, ordernumber, ideaid from ideatable where ismp=0 and mpid=? order by ordernumber", -1, &ideaStatement, NULL);
		if(sqlValue == SQLITE_OK) // sql statement was prepared
		{
			if(sqlite3_bind_int(ideaStatement, 1, currentideaID) == SQLITE_OK)
			{
				while(sqlite3_step(ideaStatement) == SQLITE_ROW) // step through the sql return values
				{
					orderedThoughtListView->AddItem(new IdeaStringItem(sqlite3_mprintf("%d. %s", sqlite3_column_int(ideaStatement, 4), sqlite3_column_text(ideaStatement, 0)), sqlite3_mprintf("%s", sqlite3_column_text(ideaStatement, 1)), sqlite3_column_int(ideaStatement, 2), sqlite3_column_int(ideaStatement, 3), sqlite3_column_int(ideaStatement, 4), sqlite3_column_int(ideaStatement, 5)));
				}
			}
			else
			{
				eAlert = new ErrorAlert("1.24 Sql Error: Sql bind failed.");
				eAlert->Launch();
			}
		}
		else // sql select failed
		{
			eAlert = new ErrorAlert("1.23 Sql Error: No Ordered Thoughts Exist.  Please Add Some First.");
			eAlert->Launch();
		}
		sqlite3_finalize(ideaStatement); // finish with sql statement
	}
}
<|endoftext|>


<commit_before>#include "MPPreview.h"

MPPreview::MPPreview(int ideaID)
	:	BWindow(BRect(100, 100, 900, 700), "tmp", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS, B_CURRENT_WORKSPACE)
{
	// initialize controls
	BRect r = Bounds();
	r.bottom = r.bottom - 50;
	previewTextView = new BTextView(r, NULL, r, B_FOLLOW_ALL, B_WILL_DRAW);
	previewTextView->SetStylable(true);
	previewTextView->MakeEditable(false);
	previewTextView->MakeSelectable(true);
	previewTextView->MakeResizable(true);
	backView = new BView(Bounds(), "backview", B_FOLLOW_ALL, B_WILL_DRAW);
	backView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	AddChild(backView);
	// gui layout builder
	backView->SetLayout(new BGroupLayout(B_HORIZONTAL, 0.0));
	backView->AddChild(BGridLayoutBuilder()
		.Add(new BScrollView("scroll_editor", previewTextView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 0, 0)
		.SetInsets(0, 0, 0, 0)
	);
	currentideaID = ideaID; // pass current idea id selected to editor window for use
	if(currentideaID != -1) // if id has a real value
	{
		sqlObject = new SqlObject(ideaStatement, "7");
		sqlObject->PrepareSql("select ideatext, ideaname, ismp from ideatable where ideaid = ?");
		sqlObject->BindValue(1, currentideaID);
		sqlObject->StepSql();
		if(sqlObject->ReturnInt(2) == 0) // thought was selected to preview
		{
			rawText = sqlObject->ReturnText(0);
			previewTextView->SetText(rawText);
			BString tmpText;
			tmpText = "MasterPiece Preview - ";
			tmpText += sqlObject->ReturnText(1);
			this->SetTitle(tmpText);
			IdeaParser(rawText, previewTextView);
			// parse rawText here....
			// getfontandcolor, store it, modify it, then setfontandcolor
			// ParseRawText(rawText, previewTextView);
			/*
				{
					previewTextView->InsertText(parsed lines);
					BEST METHOD MIGHT BE TO SETTEXT IN PREVIEWTEXTVIEW, THEN
					SELECT THE TEXT AND PARSE ACCORDINGLY USING SETFONTANDCOLOR
				}
			*/
			// display text in previewTextView such as...
		}
		else if(sqlObject->ReturnInt(2) == 1) // masterpiece was selected to preview
		{
			// sql query to get all thoughts
			// parse rawText for each thought and call insert to previewtextview here....
		}

		sqlObject->FinalizeSql();
		sqlObject->CloseSql();
	}
}
/*
void GetFontAndColor(BFont     *font,
                     uint32    *sameProperties,
                     rgb_color *color = NULL,
                     bool      *sameColor = NULL)

void SetFontAndColor(const BFont *font,
                     uint32      properties = B_FONT_ALL,
                     rgb_color   *color = NULL)

BFont   font;
uint32  sameProperties;
theTextView->GetFontAndColor(&font, &sameProperties);
font.SetSize(24.0);
theTextView->SetFontAndColor(&font, B_FONT_ALL);

BFont theBigFont(be_plain_font);
theBigFont.SetSize(48.0);
theBigFont.SetRotation(-45.0);
theBigFont.SetShear(120.0);
theTextView->SetFontAndColor(&theBigFont, B_FONT_SIZE);

BFont      font;
uint32     sameProperties;
rgb_color  redColor = {255, 0, 0, 255};
theTextView->GetFontAndColor(&font, &sameProperties);
theTextView->SetFontAndColor(&font, B_FONT_ALL, &redColor);

*/
void MPPreview::IdeaParser(BString inputText, BTextView* displayTextView)
{
	displayTextView->SelectAll();
	displayTextView->GetSelection(&startPos, &endPos);
	displayTextView->GetFontAndColor(&parseFont, &sameProperties);
	parseFont.SetSize(24.0);
	displayTextView->SetFontAndColor(startPos, endPos, &parseFont, B_FONT_SIZE);

	// create parser here
	//return displayTextView;

	// TEST REGEX PARSER - this works and handles the parser conversion from BString to C string and back...
	/*
	string s;
	int i;
	pcrecpp::RE re("(\\w+):(\\d+)");
	re.FullMatch("ruby:1234 ruby:123", &s, &i);
	printf("\r\n%d\r\n", i);
	reTester = s.c_str();
	eAlert = new ErrorAlert(reTester);
	eAlert->Launch();
	s = "yabba dabba doo";
	pcrecpp::RE("b+").GlobalReplace("d", &s);
	eAlert = new ErrorAlert(s.c_str());
	eAlert->Launch();
	*/

	// TEST REGEX PARSER

	// 1.  it seems to do this, i will need to copy the entire string from the textview
	// 2.  split the string into substrings based on the parsing... (possibly capture the length)
	// 2.4 strlen to get the length.
	// 2.5 get the length, then use offset=0 + length for each substring as i go...
	// 3.  add the formatting requirements to the substrings based on the parsing
	// 3.  use InsertText(text, length, offset, runs) to add the formatted text

	// EXAMPLE TEXT "Test of some *bold* text and more *bold* text."

	// ACTUAL REGEX PARSER TEST

	// 1.  use global replace to search for a pattern in the textview string
}
void MPPreview::MessageReceived(BMessage* msg)
{
	switch(msg->what)
	{
		default:
		{
			BWindow::MessageReceived(msg);
			break;
		}
	}
}
bool MPPreview::QuitRequested(void)
{
	return true;
}
<commit_msg>working on regex stuff.<commit_after>#include "MPPreview.h"

MPPreview::MPPreview(int ideaID)
	:	BWindow(BRect(100, 100, 900, 700), "tmp", B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS, B_CURRENT_WORKSPACE)
{
	// initialize controls
	BRect r = Bounds();
	r.bottom = r.bottom - 50;
	previewTextView = new BTextView(r, NULL, r, B_FOLLOW_ALL, B_WILL_DRAW);
	previewTextView->SetStylable(true);
	previewTextView->MakeEditable(false);
	previewTextView->MakeSelectable(true);
	previewTextView->MakeResizable(true);
	backView = new BView(Bounds(), "backview", B_FOLLOW_ALL, B_WILL_DRAW);
	backView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
	AddChild(backView);
	// gui layout builder
	backView->SetLayout(new BGroupLayout(B_HORIZONTAL, 0.0));
	backView->AddChild(BGridLayoutBuilder()
		.Add(new BScrollView("scroll_editor", previewTextView, B_FOLLOW_ALL_SIDES, 0, false, true, B_FANCY_BORDER), 0, 0)
		.SetInsets(0, 0, 0, 0)
	);
	currentideaID = ideaID; // pass current idea id selected to editor window for use
	if(currentideaID != -1) // if id has a real value
	{
		sqlObject = new SqlObject(ideaStatement, "7");
		sqlObject->PrepareSql("select ideatext, ideaname, ismp from ideatable where ideaid = ?");
		sqlObject->BindValue(1, currentideaID);
		sqlObject->StepSql();
		if(sqlObject->ReturnInt(2) == 0) // thought was selected to preview
		{
			rawText = sqlObject->ReturnText(0);
			previewTextView->SetText(rawText);
			BString tmpText;
			tmpText = "MasterPiece Preview - ";
			tmpText += sqlObject->ReturnText(1);
			this->SetTitle(tmpText);
			IdeaParser(rawText, previewTextView);
			// parse rawText here....
			// getfontandcolor, store it, modify it, then setfontandcolor
			// ParseRawText(rawText, previewTextView);
			/*
				{
					previewTextView->InsertText(parsed lines);
					BEST METHOD MIGHT BE TO SETTEXT IN PREVIEWTEXTVIEW, THEN
					SELECT THE TEXT AND PARSE ACCORDINGLY USING SETFONTANDCOLOR
				}
			*/
			// display text in previewTextView such as...
		}
		else if(sqlObject->ReturnInt(2) == 1) // masterpiece was selected to preview
		{
			// sql query to get all thoughts
			// parse rawText for each thought and call insert to previewtextview here....
		}

		sqlObject->FinalizeSql();
		sqlObject->CloseSql();
	}
}
/*
void GetFontAndColor(BFont     *font,
                     uint32    *sameProperties,
                     rgb_color *color = NULL,
                     bool      *sameColor = NULL)

void SetFontAndColor(const BFont *font,
                     uint32      properties = B_FONT_ALL,
                     rgb_color   *color = NULL)

BFont   font;
uint32  sameProperties;
theTextView->GetFontAndColor(&font, &sameProperties);
font.SetSize(24.0);
theTextView->SetFontAndColor(&font, B_FONT_ALL);

BFont theBigFont(be_plain_font);
theBigFont.SetSize(48.0);
theBigFont.SetRotation(-45.0);
theBigFont.SetShear(120.0);
theTextView->SetFontAndColor(&theBigFont, B_FONT_SIZE);

BFont      font;
uint32     sameProperties;
rgb_color  redColor = {255, 0, 0, 255};
theTextView->GetFontAndColor(&font, &sameProperties);
theTextView->SetFontAndColor(&font, B_FONT_ALL, &redColor);

*/
void MPPreview::IdeaParser(BString inputText, BTextView* displayTextView)
{
	displayTextView->SelectAll();
	displayTextView->GetSelection(&startPos, &endPos);
	displayTextView->GetFontAndColor(&parseFont, &sameProperties);
	parseFont.SetSize(24.0);
	displayTextView->SetFontAndColor(startPos, endPos, &parseFont, B_FONT_SIZE);

	// create parser here
	//return displayTextView;

	// TEST REGEX PARSER - this works and handles the parser conversion from BString to C string and back...
	/*
	string s;
	int i;
	pcrecpp::RE re("(\\w+):(\\d+)");
	re.FullMatch("ruby:1234 ruby:123", &s, &i);
	printf("\r\n%d\r\n", i);
	reTester = s.c_str();
	eAlert = new ErrorAlert(reTester);
	eAlert->Launch();
	s = "yabba dabba doo";
	pcrecpp::RE("b+").GlobalReplace("d", &s);
	eAlert = new ErrorAlert(s.c_str());
	eAlert->Launch();
	*/

	// TEST REGEX PARSER

	// 1.  it seems to do this, i will need to copy the entire string from the textview
	// 2.  split the string into substrings based on the parsing... (possibly capture the length)
	// 2.4 strlen to get the length.
	// 2.5 get the length, then use offset=0 + length for each substring as i go...
	// 3.  add the formatting requirements to the substrings based on the parsing
	// 3.  use InsertText(text, length, offset, runs) to add the formatted text

	// EXAMPLE TEXT "Test of some *bold* text and more *bold* text."

	// ACTUAL REGEX PARSER TEST

	// 1.  use global replace to search for a pattern in the textview string
	string s;
	s = "Test of some |bold| text and more |bold| text.";
	pcrecpp::RE("\|[^\|]*\|").GlobalReplace("bb", &s);
	eAlert = new ErrorAlert(s.c_str());
	eAlert->Launch();
}
void MPPreview::MessageReceived(BMessage* msg)
{
	switch(msg->what)
	{
		default:
		{
			BWindow::MessageReceived(msg);
			break;
		}
	}
}
bool MPPreview::QuitRequested(void)
{
	return true;
}
<|endoftext|>


<commit_before>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <string.h>
#include <strings.h>
#include <stdio.h>

#include "MeshGroup.h"
#include "utils/logoutput.h"
#include "utils/string.h"

namespace cura
{

FILE* binaryMeshBlob = nullptr;

/* Custom fgets function to support Mac line-ends in Ascii STL files. OpenSCAD produces this when used on Mac */
void* fgets_(char* ptr, size_t len, FILE* f)
{
    while(len && fread(ptr, 1, 1, f) > 0)
    {
        if (*ptr == '\n' || *ptr == '\r')
        {
            *ptr = '\0';
            return ptr;
        }
        ptr++;
        len--;
    }
    return nullptr;
}

bool loadMeshSTL_ascii(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rt");
    char buffer[1024];
    FPoint3 vertex;
    int n = 0;
    Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
    while(fgets_(buffer, sizeof(buffer), f))
    {
        if (sscanf(buffer, " vertex %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
        {
            n++;
            switch(n)
            {
            case 1:
                v0 = matrix.apply(vertex);
                break;
            case 2:
                v1 = matrix.apply(vertex);
                break;
            case 3:
                v2 = matrix.apply(vertex);
                mesh->addFace(v0, v1, v2);
                n = 0;
                break;
            }
        }
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL_binary(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rb");

    fseek(f, 0L, SEEK_END);
    long long file_size = ftell(f); //The file size is the position of the cursor after seeking to the end.
    rewind(f); //Seek back to start.
    size_t face_count = (file_size - 1 - sizeof(uint32_t)) / 50; //Subtract the size of the header. Every face uses exactly 50 bytes.

    char buffer[80];
    //Skip the header
    if (fread(buffer, 80, 1, f) != 1)
    {
        fclose(f);
        return false;
    }

    uint32_t reported_face_count;
    //Read the face count. We'll use it as a sort of redundancy code to check for file corruption.
    if (fread(&reported_face_count, sizeof(uint32_t), 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    if (reported_face_count != face_count)
    {
        logWarning("Face count reported by file (%s) is not equal to actual face count (%s). File could be corrupt!\n", std::to_string(reported_face_count).c_str(), std::to_string(face_count).c_str());
    }

    //For each face read:
    //float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
    // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer
    mesh->faces.reserve(face_count);
    mesh->vertices.reserve(face_count);
    for (unsigned int i = 0; i < face_count; i++)
    {
        if (fread(buffer, 50, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
        float *v= ((float*)buffer)+3;

        Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
        Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
        Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
        mesh->addFace(v0, v1, v2);
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "r");
    if (f == nullptr)
    {
        return false;
    }

    //Skip any whitespace at the beginning of the file.
    unsigned long long num_whitespace = 0; //Number of whitespace characters.
    unsigned char whitespace;
    if (fread(&whitespace, 1, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    while(isspace(whitespace))
    {
        num_whitespace++;
        if (fread(&whitespace, 1, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
    }
    fseek(f, num_whitespace, SEEK_SET); //Seek to the place after all whitespace (we may have just read too far).

    char buffer[6];
    if (fread(buffer, 5, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    fclose(f);

    buffer[5] = '\0';
    if (stringcasecompare(buffer, "solid") == 0)
    {
        bool load_success = loadMeshSTL_ascii(mesh, filename, matrix);
        if (!load_success)
            return false;

        // This logic is used to handle the case where the file starts with
        // "solid" but is a binary file.
        if (mesh->faces.size() < 1)
        {
            mesh->clear();
            return loadMeshSTL_binary(mesh, filename, matrix);
        }
        return true;
    }
    return loadMeshSTL_binary(mesh, filename, matrix);
}

bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, FMatrix3x3& transformation, SettingsBaseVirtual* object_parent_settings)
{
    const char* ext = strrchr(filename, '.');
    if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
    {
        Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
        if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
        {
            meshgroup->meshes.push_back(mesh);
            return true;
        }
    }
    return false;
}

}//namespace cura<commit_msg>Fix STL header size<commit_after>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <string.h>
#include <strings.h>
#include <stdio.h>

#include "MeshGroup.h"
#include "utils/logoutput.h"
#include "utils/string.h"

namespace cura
{

FILE* binaryMeshBlob = nullptr;

/* Custom fgets function to support Mac line-ends in Ascii STL files. OpenSCAD produces this when used on Mac */
void* fgets_(char* ptr, size_t len, FILE* f)
{
    while(len && fread(ptr, 1, 1, f) > 0)
    {
        if (*ptr == '\n' || *ptr == '\r')
        {
            *ptr = '\0';
            return ptr;
        }
        ptr++;
        len--;
    }
    return nullptr;
}

bool loadMeshSTL_ascii(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rt");
    char buffer[1024];
    FPoint3 vertex;
    int n = 0;
    Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
    while(fgets_(buffer, sizeof(buffer), f))
    {
        if (sscanf(buffer, " vertex %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
        {
            n++;
            switch(n)
            {
            case 1:
                v0 = matrix.apply(vertex);
                break;
            case 2:
                v1 = matrix.apply(vertex);
                break;
            case 3:
                v2 = matrix.apply(vertex);
                mesh->addFace(v0, v1, v2);
                n = 0;
                break;
            }
        }
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL_binary(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "rb");

    fseek(f, 0L, SEEK_END);
    long long file_size = ftell(f); //The file size is the position of the cursor after seeking to the end.
    rewind(f); //Seek back to start.
    size_t face_count = (file_size - 80 - sizeof(uint32_t)) / 50; //Subtract the size of the header. Every face uses exactly 50 bytes.

    char buffer[80];
    //Skip the header
    if (fread(buffer, 80, 1, f) != 1)
    {
        fclose(f);
        return false;
    }

    uint32_t reported_face_count;
    //Read the face count. We'll use it as a sort of redundancy code to check for file corruption.
    if (fread(&reported_face_count, sizeof(uint32_t), 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    if (reported_face_count != face_count)
    {
        logWarning("Face count reported by file (%s) is not equal to actual face count (%s). File could be corrupt!\n", std::to_string(reported_face_count).c_str(), std::to_string(face_count).c_str());
    }

    //For each face read:
    //float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
    // Every Face is 50 Bytes: Normal(3*float), Vertices(9*float), 2 Bytes Spacer
    mesh->faces.reserve(face_count);
    mesh->vertices.reserve(face_count);
    for (unsigned int i = 0; i < face_count; i++)
    {
        if (fread(buffer, 50, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
        float *v= ((float*)buffer)+3;

        Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
        Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
        Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
        mesh->addFace(v0, v1, v2);
    }
    fclose(f);
    mesh->finish();
    return true;
}

bool loadMeshSTL(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
    FILE* f = fopen(filename, "r");
    if (f == nullptr)
    {
        return false;
    }

    //Skip any whitespace at the beginning of the file.
    unsigned long long num_whitespace = 0; //Number of whitespace characters.
    unsigned char whitespace;
    if (fread(&whitespace, 1, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    while(isspace(whitespace))
    {
        num_whitespace++;
        if (fread(&whitespace, 1, 1, f) != 1)
        {
            fclose(f);
            return false;
        }
    }
    fseek(f, num_whitespace, SEEK_SET); //Seek to the place after all whitespace (we may have just read too far).

    char buffer[6];
    if (fread(buffer, 5, 1, f) != 1)
    {
        fclose(f);
        return false;
    }
    fclose(f);

    buffer[5] = '\0';
    if (stringcasecompare(buffer, "solid") == 0)
    {
        bool load_success = loadMeshSTL_ascii(mesh, filename, matrix);
        if (!load_success)
            return false;

        // This logic is used to handle the case where the file starts with
        // "solid" but is a binary file.
        if (mesh->faces.size() < 1)
        {
            mesh->clear();
            return loadMeshSTL_binary(mesh, filename, matrix);
        }
        return true;
    }
    return loadMeshSTL_binary(mesh, filename, matrix);
}

bool loadMeshIntoMeshGroup(MeshGroup* meshgroup, const char* filename, FMatrix3x3& transformation, SettingsBaseVirtual* object_parent_settings)
{
    const char* ext = strrchr(filename, '.');
    if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
    {
        Mesh mesh = object_parent_settings ? Mesh(object_parent_settings) : Mesh(meshgroup); //If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
        if(loadMeshSTL(&mesh,filename,transformation)) //Load it! If successful...
        {
            meshgroup->meshes.push_back(mesh);
            return true;
        }
    }
    return false;
}

}//namespace cura<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <algorithm>
#include <functional>

#include "ParseNode.hpp"
#include "Context.hpp"
#include "StringPool.hpp"
#include "AssemblyFileWriter.hpp"
#include "Utils.hpp"

using std::list;
using std::vector;
using std::mem_fun;
using std::bind2nd;

using namespace eddic;

ParseNode::~ParseNode() {
    for_each(begin(), end(), deleter());
    for_each(trash.begin(), trash.end(), deleter());
}

void ParseNode::write(AssemblyFileWriter& writer) {
    for_each(begin(), end(), bind2nd(mem_fun(&ParseNode::write), writer));
}

void ParseNode::checkFunctions(Program& program){
    for_each(begin(), end(), bind2nd(mem_fun(&ParseNode::checkFunctions), program));
}

void ParseNode::checkVariables() {
    for_each(begin(), end(), mem_fun(&ParseNode::checkVariables));
}

void ParseNode::checkStrings(StringPool& pool) {
    for_each(begin(), end(), bind2nd(mem_fun(&ParseNode::checkStrings), pool));
}

void ParseNode::optimize() {
    for_each(begin(), end(), mem_fun(&ParseNode::optimize));
}

void ParseNode::addLast(ParseNode* node) {
    childs.push_back(node);

    node->parent = this;
}

void ParseNode::addFirst(ParseNode* node) {
    childs.push_front(node);

    node->parent = this;
}

void ParseNode::replace(ParseNode* old, ParseNode* node) {
    trash.push_back(old);
    old->parent = NULL;

    node->parent = this;

    list<ParseNode*>::iterator it = find(childs.begin(), childs.end(), old);
    if(it != childs.end()){
        *it = node;
    }
}

void ParseNode::remove(ParseNode* node) {
    childs.remove(node);

    trash.push_back(node);
    node->parent = NULL;
}

NodeIterator ParseNode::begin() {
    return childs.begin();
}

NodeIterator ParseNode::end() {
    return childs.end();
}
<commit_msg>Test lambda expression<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <algorithm>
#include <functional>

#include "ParseNode.hpp"
#include "Context.hpp"
#include "StringPool.hpp"
#include "AssemblyFileWriter.hpp"
#include "Utils.hpp"

using std::list;
using std::vector;
using std::mem_fun;
using std::bind2nd;

using namespace eddic;

ParseNode::~ParseNode() {
    for_each(begin(), end(), deleter());
    for_each(trash.begin(), trash.end(), deleter());
}

void ParseNode::write(AssemblyFileWriter& writer) {
    for_each(begin(), end(), bind2nd(mem_fun(&ParseNode::write), writer));
}

void ParseNode::checkFunctions(Program& program){
    for_each(begin(), end(), bind2nd(mem_fun(&ParseNode::checkFunctions), program));
}

void ParseNode::checkVariables() {
    for_each(begin(), end(), mem_fun(&ParseNode::checkVariables));
}

void ParseNode::checkStrings(StringPool& pool) {
    for_each(begin(), end(), bind2nd(mem_fun(&ParseNode::checkStrings), pool));
}

void ParseNode::optimize() {
    for_each(begin(), end(), [=](ParseNode* p){ p->optimize(); });
}

void ParseNode::addLast(ParseNode* node) {
    childs.push_back(node);

    node->parent = this;
}

void ParseNode::addFirst(ParseNode* node) {
    childs.push_front(node);

    node->parent = this;
}

void ParseNode::replace(ParseNode* old, ParseNode* node) {
    trash.push_back(old);
    old->parent = NULL;

    node->parent = this;

    list<ParseNode*>::iterator it = find(childs.begin(), childs.end(), old);
    if(it != childs.end()){
        *it = node;
    }
}

void ParseNode::remove(ParseNode* node) {
    childs.remove(node);

    trash.push_back(node);
    node->parent = NULL;
}

NodeIterator ParseNode::begin() {
    return childs.begin();
}

NodeIterator ParseNode::end() {
    return childs.end();
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "KafkaWriter.h"

using namespace logging;
using namespace writer;

KafkaWriter::KafkaWriter(WriterFrontend* frontend):
    WriterBackend(frontend),
    formatter(NULL),
    producer(NULL),
    topic(NULL)
{
  // need thread-local copies of all user-defined settings coming from
  // bro scripting land.  accessing these is not thread-safe and 'DoInit'
  // is potentially accessed from multiple threads.

  // tag_json - thread local copy
  tag_json = BifConst::Kafka::tag_json;

  // json_timestamps
  ODesc tsfmt;
  BifConst::Kafka::json_timestamps->Describe(&tsfmt);
  json_timestamps.assign(
      (const char*) tsfmt.Bytes(),
      tsfmt.Len()
    );

  // topic name - thread local copy
  topic_name.assign(
    (const char*)BifConst::Kafka::topic_name->Bytes(),
    BifConst::Kafka::topic_name->Len());

  // kafka_conf - thread local copy
  Val* val = BifConst::Kafka::kafka_conf->AsTableVal();
  IterCookie* c = val->AsTable()->InitForIteration();
  HashKey* k;
  TableEntryVal* v;
  while ((v = val->AsTable()->NextEntry(k, c))) {

      // fetch the key and value
      ListVal* index = val->AsTableVal()->RecoverIndex(k);
      string key = index->Index(0)->AsString()->CheckString();
      string val = v->Value()->AsString()->CheckString();
      kafka_conf.insert (kafka_conf.begin(), pair<string, string> (key, val));

      // cleanup
      Unref(index);
      delete k;
  }
}

KafkaWriter::~KafkaWriter()
{

    // Cleanup all the things
    delete topic;
    delete producer;
    delete formatter;
    delete conf;
    delete topic_conf;

}

bool KafkaWriter::DoInit(const WriterInfo& info, int num_fields, const threading::Field* const* fields)
{
    // Timeformat object, default to TS_EPOCH
    threading::formatter::JSON::TimeFormat tf = threading::formatter::JSON::TS_EPOCH;

    // if no global 'topic_name' is defined, use the log stream's 'path'
    if(topic_name.empty()) {
        topic_name = info.path;
    }

    // format timestamps
    // NOTE: This string comparision implementation is currently the necessary
    // way to do it, as there isn't a way to pass the Bro enum into C++ enum.
    // This makes the user interface consistent with the existing Bro Logging
    // configuration for the ASCII log output.
    if ( strcmp(json_timestamps.c_str(), "JSON::TS_EPOCH") == 0 ) {
      tf = threading::formatter::JSON::TS_EPOCH;
    }
    else if ( strcmp(json_timestamps.c_str(), "JSON::TS_MILLIS") == 0 ) {
      tf = threading::formatter::JSON::TS_MILLIS;
    }
    else if ( strcmp(json_timestamps.c_str(), "JSON::TS_ISO8601") == 0 ) {
      tf = threading::formatter::JSON::TS_ISO8601;
    }
    else {
      Error(Fmt("KafkaWriter::DoInit: Invalid JSON timestamp format %s",
        json_timestamps.c_str()));
      return false;
    }

    // initialize the formatter
    if(BifConst::Kafka::tag_json) {
      formatter = new threading::formatter::TaggedJSON(info.path, this, tf);
    }
    else {
      formatter = new threading::formatter::JSON(this, tf);
    }

    // is debug enabled
    string debug;
    debug.assign((const char*)BifConst::Kafka::debug->Bytes(), BifConst::Kafka::debug->Len());
    bool is_debug(!debug.empty());
    if(is_debug) {
      MsgThread::Info(Fmt("Debug is turned on and set to: %s.  Available debug context: %s.", debug.c_str(), RdKafka::get_debug_contexts().c_str()));
    }
    else {
      MsgThread::Info(Fmt("Debug is turned off."));
    }

    // kafka global configuration
    string err;
    conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL);

    // apply the user-defined settings to kafka
    map<string,string>::iterator i;
    for (i = kafka_conf.begin(); i != kafka_conf.end(); ++i) {
      string key = i->first;
      string val = i->second;

      // apply setting to kafka
      if (RdKafka::Conf::CONF_OK != conf->set(key, val, err)) {
          Error(Fmt("Failed to set '%s'='%s': %s", key.c_str(), val.c_str(), err.c_str()));
          return false;
      }
    }

    if(is_debug) {
        string key("debug");
        string val(debug);
        if (RdKafka::Conf::CONF_OK != conf->set(key, val, err)) {
            Error(Fmt("Failed to set '%s'='%s': %s", key.c_str(), val.c_str(), err.c_str()));
            return false;
        }
    }

    // create kafka producer
    producer = RdKafka::Producer::create(conf, err);
    if (!producer) {
        Error(Fmt("Failed to create producer: %s", err.c_str()));
        return false;
    }

    // create handle to topic
    topic_conf = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC);
    topic = RdKafka::Topic::create(producer, topic_name, topic_conf, err);
    if (!topic) {
        Error(Fmt("Failed to create topic handle: %s", err.c_str()));
        return false;
    }

    if(is_debug) {
        MsgThread::Info(Fmt("Successfully created producer."));
    }

    return true;
}

/**
 * Writer-specific method called just before the threading system is
 * going to shutdown. It is assumed that once this messages returns,
 * the thread can be safely terminated.
 */
bool KafkaWriter::DoFinish(double network_time)
{
    bool success = false;
    int poll_interval = 1000;
    int waited = 0;
    int max_wait = BifConst::Kafka::max_wait_on_shutdown;

    // wait a bit for queued messages to be delivered
    while (producer->outq_len() > 0 && waited <= max_wait) {
        producer->poll(poll_interval);
        waited += poll_interval;
    }

    // successful only if all messages delivered
    if (producer->outq_len() == 0) {
        success = true;
    } else {
        Error(Fmt("Unable to deliver %0d message(s)", producer->outq_len()));
    }

    delete topic;
    delete producer;
    delete formatter;

    return success;
}

/**
 * Writer-specific output method implementing recording of one log
 * entry.
 */
bool KafkaWriter::DoWrite(int num_fields, const threading::Field* const* fields, threading::Value** vals)
{
    ODesc buff;
    buff.Clear();

    // format the log entry
    formatter->Describe(&buff, num_fields, fields, vals);

    // send the formatted log entry to kafka
    const char* raw = (const char*)buff.Bytes();
    RdKafka::ErrorCode resp = producer->produce(
        topic, RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY,
        const_cast<char*>(raw), strlen(raw), NULL, NULL);

    if (RdKafka::ERR_NO_ERROR == resp) {
        producer->poll(0);
    }
    else {
        string err = RdKafka::err2str(resp);
        Error(Fmt("Kafka send failed: %s", err.c_str()));
    }

    return true;
}

/**
 * Writer-specific method implementing a change of fthe buffering
 * state.	If buffering is disabled, the writer should attempt to
 * write out information as quickly as possible even if doing so may
 * have a performance impact. If enabled (which is the default), it
 * may buffer data as helpful and write it out later in a way
 * optimized for performance. The current buffering state can be
 * queried via IsBuf().
 */
bool KafkaWriter::DoSetBuf(bool enabled)
{
    // no change in behavior
    return true;
}

/**
 * Writer-specific method implementing flushing of its output.	A writer
 * implementation must override this method but it can just
 * ignore calls if flushing doesn't align with its semantics.
 */
bool KafkaWriter::DoFlush(double network_time)
{
    producer->poll(0);
    return true;
}

/**
 * Writer-specific method implementing log rotation.	Most directly
 * this only applies to writers writing into files, which should then
 * close the current file and open a new one.	However, a writer may
 * also trigger other apppropiate actions if semantics are similar.
 * Once rotation has finished, the implementation *must* call
 * FinishedRotation() to signal the log manager that potential
 * postprocessors can now run.
 */
bool KafkaWriter::DoRotate(const char* rotated_path, double open, double close, bool terminating)
{
    // no need to perform log rotation
    return FinishedRotation();
}

/**
 * Triggered by regular heartbeat messages from the main thread.
 */
bool KafkaWriter::DoHeartbeat(double network_time, double current_time)
{
    producer->poll(0);
    return true;
}
<commit_msg>METRON-1910 bro plugin segfaults on src/KafkaWriter.cc:72 (JonZeolla) closes apache/metron-bro-plugin-kafka#20<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 "KafkaWriter.h"

using namespace logging;
using namespace writer;

// The Constructor is called once for each log filter that uses this log writer.
KafkaWriter::KafkaWriter(WriterFrontend* frontend):
    WriterBackend(frontend),
    formatter(NULL),
    producer(NULL),
    topic(NULL)
{
  /**
   * We need thread-local copies of all user-defined settings coming from bro
   * scripting land.  accessing these is not thread-safe and 'DoInit' is
   * potentially accessed from multiple threads.
   */

  // tag_json - thread local copy
  tag_json = BifConst::Kafka::tag_json;

  // json_timestamps
  ODesc tsfmt;
  BifConst::Kafka::json_timestamps->Describe(&tsfmt);
  json_timestamps.assign(
      (const char*) tsfmt.Bytes(),
      tsfmt.Len()
    );

  // topic name - thread local copy
  topic_name.assign(
    (const char*)BifConst::Kafka::topic_name->Bytes(),
    BifConst::Kafka::topic_name->Len());

  // kafka_conf - thread local copy
  Val* val = BifConst::Kafka::kafka_conf->AsTableVal();
  IterCookie* c = val->AsTable()->InitForIteration();
  HashKey* k;
  TableEntryVal* v;
  while ((v = val->AsTable()->NextEntry(k, c))) {

      // fetch the key and value
      ListVal* index = val->AsTableVal()->RecoverIndex(k);
      string key = index->Index(0)->AsString()->CheckString();
      string val = v->Value()->AsString()->CheckString();
      kafka_conf.insert (kafka_conf.begin(), pair<string, string> (key, val));

      // cleanup
      Unref(index);
      delete k;
  }
}

KafkaWriter::~KafkaWriter()
{
  // Cleanup must happen in DoFinish, not in the destructor
}

/**
 * DoInit is called once for each call to the constructor, but in a separate
 * thread
 */
bool KafkaWriter::DoInit(const WriterInfo& info, int num_fields, const threading::Field* const* fields)
{
    // Timeformat object, default to TS_EPOCH
    threading::formatter::JSON::TimeFormat tf = threading::formatter::JSON::TS_EPOCH;

    // if no global 'topic_name' is defined, use the log stream's 'path'
    if(topic_name.empty()) {
        topic_name = info.path;
    }

    /**
     * Format the timestamps
     * NOTE: This string comparision implementation is currently the necessary
     * way to do it, as there isn't a way to pass the Bro enum into C++ enum.
     * This makes the user interface consistent with the existing Bro Logging
     * configuration for the ASCII log output.
     */
    if ( strcmp(json_timestamps.c_str(), "JSON::TS_EPOCH") == 0 ) {
      tf = threading::formatter::JSON::TS_EPOCH;
    }
    else if ( strcmp(json_timestamps.c_str(), "JSON::TS_MILLIS") == 0 ) {
      tf = threading::formatter::JSON::TS_MILLIS;
    }
    else if ( strcmp(json_timestamps.c_str(), "JSON::TS_ISO8601") == 0 ) {
      tf = threading::formatter::JSON::TS_ISO8601;
    }
    else {
      Error(Fmt("KafkaWriter::DoInit: Invalid JSON timestamp format %s",
        json_timestamps.c_str()));
      return false;
    }

    // initialize the formatter
    if(BifConst::Kafka::tag_json) {
      formatter = new threading::formatter::TaggedJSON(info.path, this, tf);
    }
    else {
      formatter = new threading::formatter::JSON(this, tf);
    }

    // is debug enabled
    string debug;
    debug.assign((const char*)BifConst::Kafka::debug->Bytes(), BifConst::Kafka::debug->Len());
    bool is_debug(!debug.empty());
    if(is_debug) {
      MsgThread::Info(Fmt("Debug is turned on and set to: %s.  Available debug context: %s.", debug.c_str(), RdKafka::get_debug_contexts().c_str()));
    }
    else {
      MsgThread::Info(Fmt("Debug is turned off."));
    }

    // kafka global configuration
    string err;
    conf = RdKafka::Conf::create(RdKafka::Conf::CONF_GLOBAL);

    // apply the user-defined settings to kafka
    map<string,string>::iterator i;
    for (i = kafka_conf.begin(); i != kafka_conf.end(); ++i) {
      string key = i->first;
      string val = i->second;

      // apply setting to kafka
      if (RdKafka::Conf::CONF_OK != conf->set(key, val, err)) {
          Error(Fmt("Failed to set '%s'='%s': %s", key.c_str(), val.c_str(), err.c_str()));
          return false;
      }
    }

    if(is_debug) {
        string key("debug");
        string val(debug);
        if (RdKafka::Conf::CONF_OK != conf->set(key, val, err)) {
            Error(Fmt("Failed to set '%s'='%s': %s", key.c_str(), val.c_str(), err.c_str()));
            return false;
        }
    }

    // create kafka producer
    producer = RdKafka::Producer::create(conf, err);
    if (!producer) {
        Error(Fmt("Failed to create producer: %s", err.c_str()));
        return false;
    }

    // create handle to topic
    topic_conf = RdKafka::Conf::create(RdKafka::Conf::CONF_TOPIC);
    topic = RdKafka::Topic::create(producer, topic_name, topic_conf, err);
    if (!topic) {
        Error(Fmt("Failed to create topic handle: %s", err.c_str()));
        return false;
    }

    if(is_debug) {
        MsgThread::Info(Fmt("Successfully created producer."));
    }

    return true;
}

/**
 * Writer-specific method called just before the threading system is
 * going to shutdown. It is assumed that once this messages returns,
 * the thread can be safely terminated. As such, all resources created must be
 * removed here.
 */
bool KafkaWriter::DoFinish(double network_time)
{
    bool success = false;
    int poll_interval = 1000;
    int waited = 0;
    int max_wait = BifConst::Kafka::max_wait_on_shutdown;

    // wait a bit for queued messages to be delivered
    while (producer->outq_len() > 0 && waited <= max_wait) {
        producer->poll(poll_interval);
        waited += poll_interval;
    }

    // successful only if all messages delivered
    if (producer->outq_len() == 0) {
        success = true;
    } else {
        Error(Fmt("Unable to deliver %0d message(s)", producer->outq_len()));
    }

    delete topic;
    delete producer;
    delete formatter;
    delete conf;
    delete topic_conf;

    return success;
}

/**
 * Writer-specific output method implementing recording of one log
 * entry.
 */
bool KafkaWriter::DoWrite(int num_fields, const threading::Field* const* fields, threading::Value** vals)
{
    ODesc buff;
    buff.Clear();

    // format the log entry
    formatter->Describe(&buff, num_fields, fields, vals);

    // send the formatted log entry to kafka
    const char* raw = (const char*)buff.Bytes();
    RdKafka::ErrorCode resp = producer->produce(
        topic, RdKafka::Topic::PARTITION_UA, RdKafka::Producer::RK_MSG_COPY,
        const_cast<char*>(raw), strlen(raw), NULL, NULL);

    if (RdKafka::ERR_NO_ERROR == resp) {
        producer->poll(0);
    }
    else {
        string err = RdKafka::err2str(resp);
        Error(Fmt("Kafka send failed: %s", err.c_str()));
    }

    return true;
}

/**
 * Writer-specific method implementing a change of fthe buffering
 * state.	If buffering is disabled, the writer should attempt to
 * write out information as quickly as possible even if doing so may
 * have a performance impact. If enabled (which is the default), it
 * may buffer data as helpful and write it out later in a way
 * optimized for performance. The current buffering state can be
 * queried via IsBuf().
 */
bool KafkaWriter::DoSetBuf(bool enabled)
{
    // no change in behavior
    return true;
}

/**
 * Writer-specific method implementing flushing of its output.	A writer
 * implementation must override this method but it can just
 * ignore calls if flushing doesn't align with its semantics.
 */
bool KafkaWriter::DoFlush(double network_time)
{
    producer->poll(0);
    return true;
}

/**
 * Writer-specific method implementing log rotation.	Most directly
 * this only applies to writers writing into files, which should then
 * close the current file and open a new one.	However, a writer may
 * also trigger other apppropiate actions if semantics are similar.
 * Once rotation has finished, the implementation *must* call
 * FinishedRotation() to signal the log manager that potential
 * postprocessors can now run.
 */
bool KafkaWriter::DoRotate(const char* rotated_path, double open, double close, bool terminating)
{
    // no need to perform log rotation
    return FinishedRotation();
}

/**
 * Triggered by regular heartbeat messages from the main thread.
 */
bool KafkaWriter::DoHeartbeat(double network_time, double current_time)
{
    producer->poll(0);
    return true;
}
<|endoftext|>