<commit_before>#include <stdio.h>
#include <windows.h>
#include <winuser.h>
#include <process.h>

#include <myo/myo.hpp>

#include "../module_headers/module.h"
#include "../module_headers/control_module.h"
#include "../rcml_compiler/globals.h"

#include "myo_data_collector.h"
#include "myo_control_module.h"

const unsigned int COUNT_AXIS = 6;

#define DEFINE_ALL_AXIS \
	ADD_AXIS("fist", 1, 0)\
	ADD_AXIS("left_or_right", 1, -1)\
	ADD_AXIS("fingers_spread", 1, 0)\
	ADD_AXIS("double_tap", 1, 0)\
	ADD_AXIS("locked", 1, 0)\
	ADD_AXIS("arm_pitch_angle", 18, 0)

bool myo_working = false;
CRITICAL_SECTION myo_working_mutex;

unsigned int WINAPI waitTerminateSignal(void *arg) {
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	if (hStdin == INVALID_HANDLE_VALUE) {
		goto exit; //error
	}

	DWORD fdwSaveOldMode;
	if (!GetConsoleMode(hStdin, &fdwSaveOldMode)) {
		goto exit; //error
	}
	DWORD fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
	if (!SetConsoleMode(hStdin, fdwMode)) {
		goto exit; //error
	}

	INPUT_RECORD irInBuf[128];
	DWORD cNumRead;
	DWORD i;

	while (1) {
		if (!ReadConsoleInput(hStdin, irInBuf, 128, &cNumRead))  {
			goto exit; //error
		}

		for (i = 0; i < cNumRead; ++i) {
			if (irInBuf[i].EventType == KEY_EVENT) {
				WORD key_code = irInBuf[i].Event.KeyEvent.wVirtualKeyCode;
				if (key_code == VK_ESCAPE) {
					goto exit; //exit
				}
			}
		}
	}

	exit:

	EnterCriticalSection(&myo_working_mutex);
	myo_working = false;
	LeaveCriticalSection(&myo_working_mutex);

	SetConsoleMode(hStdin, fdwSaveOldMode);
	return 0;
}

void MyoControlModule::execute(sendAxisState_t sendAxisState) {
	myo->vibrate(myo::Myo::VibrationType::vibrationShort);
	myo_data_collector->start(sendAxisState);

	myo_working = true;
	InitializeCriticalSection(&myo_working_mutex);

	unsigned int tid;
	HANDLE thread_handle = (HANDLE) _beginthreadex(NULL, 0, waitTerminateSignal, NULL, 0, &tid);

	EnterCriticalSection(&myo_working_mutex);
	while (myo_working) {
		LeaveCriticalSection(&myo_working_mutex);

        hub->run(1000/20);
        myo_data_collector->print();

		EnterCriticalSection(&myo_working_mutex);
    }
	LeaveCriticalSection(&myo_working_mutex);

	WaitForSingleObject(thread_handle, INFINITE);
	CloseHandle(thread_handle);
	DeleteCriticalSection(&myo_working_mutex);

	myo_data_collector->finish();
	myo->vibrate(myo::Myo::VibrationType::vibrationShort);
}

MyoControlModule::MyoControlModule() {
	robot_axis = new AxisData*[COUNT_AXIS];
	system_value axis_id = 0;
	DEFINE_ALL_AXIS
}

int MyoControlModule::init() {
	 try {
		hub = new myo::Hub("com.example.myo_control_module");

		colorPrintf(ConsoleColor(), "Attempting to find a Myo...\n");

		myo = hub->waitForMyo(10000);
		if (!myo) {
			throw std::runtime_error("Unable to find a Myo!");
		}
		colorPrintf(ConsoleColor(ConsoleColor::green), "Connected to a Myo armband!\n");

		myo_data_collector = new DataCollector();
		hub->addListener(myo_data_collector);

    } catch (const std::exception& e) {
        colorPrintf(ConsoleColor(ConsoleColor::red), "Error: %s\n", e.what());
        return 1;
    }
	return 0;
}

const char *MyoControlModule::getUID() {
	return "Myo control module v0.99b by m79lol";
}

void MyoControlModule::prepare(colorPrintf_t *colorPrintf_p, colorPrintfVA_t *colorPrintfVA_p) {
	this->colorPrintf_p = colorPrintfVA_p;
}

void MyoControlModule::colorPrintf(ConsoleColor colors, const char *mask, ...) {
	va_list args;
    va_start(args, mask);
    (*colorPrintf_p)(this, colors, mask, args);
    va_end(args);
}

void MyoControlModule::final() {
	hub->removeListener(myo_data_collector);
	delete myo_data_collector;
	delete hub;
}

AxisData** MyoControlModule::getAxis(unsigned int *count_axis) {
	(*count_axis) = COUNT_AXIS;
	return robot_axis;
}

void MyoControlModule::destroy() {
	for (unsigned int j = 0; j < COUNT_AXIS; ++j) {
		delete robot_axis[j];
	}
	delete[] robot_axis;
	delete this;
}

void *MyoControlModule::writePC(unsigned int *buffer_length) {
	*buffer_length = 0;
	return NULL;
}

int MyoControlModule::startProgram(int uniq_index, void *buffer, unsigned int buffer_length) {
	return 0;
}
int MyoControlModule::endProgram(int uniq_index) {
	return 0;
}

__declspec(dllexport) ControlModule* getControlModuleObject() {
	return new MyoControlModule();
}<commit_msg>Fixed bug with key "escape".<commit_after>#include <stdio.h>
#include <windows.h>
#include <winuser.h>
#include <process.h>

#include <myo/myo.hpp>

#include "../module_headers/module.h"
#include "../module_headers/control_module.h"
#include "../rcml_compiler/globals.h"

#include "myo_data_collector.h"
#include "myo_control_module.h"

const unsigned int COUNT_AXIS = 6;

#define DEFINE_ALL_AXIS \
	ADD_AXIS("fist", 1, 0)\
	ADD_AXIS("left_or_right", 1, -1)\
	ADD_AXIS("fingers_spread", 1, 0)\
	ADD_AXIS("double_tap", 1, 0)\
	ADD_AXIS("locked", 1, 0)\
	ADD_AXIS("arm_pitch_angle", 18, 0)

bool myo_working = false;
CRITICAL_SECTION myo_working_mutex;

unsigned int WINAPI waitTerminateSignal(void *arg) {
	HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
	if (hStdin == INVALID_HANDLE_VALUE) {
		goto exit; //error
	}

	DWORD fdwSaveOldMode;
	if (!GetConsoleMode(hStdin, &fdwSaveOldMode)) {
		goto exit; //error
	}
	DWORD fdwMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
	if (!SetConsoleMode(hStdin, fdwMode)) {
		goto exit; //error
	}

	INPUT_RECORD irInBuf[128];
	DWORD cNumRead;
	DWORD i;

	while (1) {
		if (!ReadConsoleInput(hStdin, irInBuf, 128, &cNumRead))  {
			goto exit; //error
		}

		for (i = 0; i < cNumRead; ++i) {
			if (irInBuf[i].EventType == KEY_EVENT) {
				WORD key_code = irInBuf[i].Event.KeyEvent.wVirtualKeyCode;
				if ((key_code == VK_ESCAPE) && (irInBuf[i].Event.KeyEvent.bKeyDown)) {
					goto exit; //exit
				}
			}
		}
	}

	exit:

	EnterCriticalSection(&myo_working_mutex);
	myo_working = false;
	LeaveCriticalSection(&myo_working_mutex);

	SetConsoleMode(hStdin, fdwSaveOldMode);
	return 0;
}

void MyoControlModule::execute(sendAxisState_t sendAxisState) {
	myo->vibrate(myo::Myo::VibrationType::vibrationShort);
	myo_data_collector->start(sendAxisState);

	myo_working = true;
	InitializeCriticalSection(&myo_working_mutex);

	unsigned int tid;
	HANDLE thread_handle = (HANDLE) _beginthreadex(NULL, 0, waitTerminateSignal, NULL, 0, &tid);

	EnterCriticalSection(&myo_working_mutex);
	while (myo_working) {
		LeaveCriticalSection(&myo_working_mutex);

        hub->run(1000/20);
        myo_data_collector->print();

		EnterCriticalSection(&myo_working_mutex);
    }
	LeaveCriticalSection(&myo_working_mutex);

	WaitForSingleObject(thread_handle, INFINITE);
	CloseHandle(thread_handle);
	DeleteCriticalSection(&myo_working_mutex);

	myo_data_collector->finish();
	myo->vibrate(myo::Myo::VibrationType::vibrationShort);
}

MyoControlModule::MyoControlModule() {
	robot_axis = new AxisData*[COUNT_AXIS];
	system_value axis_id = 0;
	DEFINE_ALL_AXIS
}

int MyoControlModule::init() {
	 try {
		hub = new myo::Hub("com.example.myo_control_module");

		colorPrintf(ConsoleColor(), "Attempting to find a Myo...\n");

		myo = hub->waitForMyo(10000);
		if (!myo) {
			throw std::runtime_error("Unable to find a Myo!");
		}
		colorPrintf(ConsoleColor(ConsoleColor::green), "Connected to a Myo armband!\n");

		myo_data_collector = new DataCollector();
		hub->addListener(myo_data_collector);

    } catch (const std::exception& e) {
        colorPrintf(ConsoleColor(ConsoleColor::red), "Error: %s\n", e.what());
        return 1;
    }
	return 0;
}

const char *MyoControlModule::getUID() {
	return "Myo control module v0.99b by m79lol";
}

void MyoControlModule::prepare(colorPrintf_t *colorPrintf_p, colorPrintfVA_t *colorPrintfVA_p) {
	this->colorPrintf_p = colorPrintfVA_p;
}

void MyoControlModule::colorPrintf(ConsoleColor colors, const char *mask, ...) {
	va_list args;
    va_start(args, mask);
    (*colorPrintf_p)(this, colors, mask, args);
    va_end(args);
}

void MyoControlModule::final() {
	hub->removeListener(myo_data_collector);
	delete myo_data_collector;
	delete hub;
}

AxisData** MyoControlModule::getAxis(unsigned int *count_axis) {
	(*count_axis) = COUNT_AXIS;
	return robot_axis;
}

void MyoControlModule::destroy() {
	for (unsigned int j = 0; j < COUNT_AXIS; ++j) {
		delete robot_axis[j];
	}
	delete[] robot_axis;
	delete this;
}

void *MyoControlModule::writePC(unsigned int *buffer_length) {
	*buffer_length = 0;
	return NULL;
}

int MyoControlModule::startProgram(int uniq_index, void *buffer, unsigned int buffer_length) {
	return 0;
}
int MyoControlModule::endProgram(int uniq_index) {
	return 0;
}

__declspec(dllexport) ControlModule* getControlModuleObject() {
	return new MyoControlModule();
}<|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.
 *
 * Modified by Cloudius Systems.
 * Copyright 2015 Cloudius Systems.
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "core/sstring.hh"
#include "query-request.hh"
#include "dht/i_partitioner.hh"
#include <vector>

namespace streaming {

class stream_request {
public:
    using token = dht::token;
    sstring keyspace;
    std::vector<query::range<token>> ranges;
    std::vector<sstring> column_families;
    long repaired_at;
    stream_request() = default;
    stream_request(sstring _keyspace, std::vector<query::range<token>> _ranges, std::vector<sstring> _column_families)
        : keyspace(std::move(_keyspace))
        , ranges(std::move(_ranges))
        , column_families(std::move(_column_families)) {
    }
    friend std::ostream& operator<<(std::ostream& os, const stream_request& r);
public:
    void serialize(bytes::iterator& out) const;
    static stream_request deserialize(bytes_view& v);
    size_t serialized_size() const;
};

} // namespace streaming
<commit_msg>streaming: Drop unused repaired_at in stream_request<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.
 *
 * Modified by Cloudius Systems.
 * Copyright 2015 Cloudius Systems.
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "core/sstring.hh"
#include "query-request.hh"
#include "dht/i_partitioner.hh"
#include <vector>

namespace streaming {

class stream_request {
public:
    using token = dht::token;
    sstring keyspace;
    std::vector<query::range<token>> ranges;
    std::vector<sstring> column_families;
    stream_request() = default;
    stream_request(sstring _keyspace, std::vector<query::range<token>> _ranges, std::vector<sstring> _column_families)
        : keyspace(std::move(_keyspace))
        , ranges(std::move(_ranges))
        , column_families(std::move(_column_families)) {
    }
    friend std::ostream& operator<<(std::ostream& os, const stream_request& r);
public:
    void serialize(bytes::iterator& out) const;
    static stream_request deserialize(bytes_view& v);
    size_t serialized_size() const;
};

} // namespace streaming
<|endoftext|>


<commit_before><commit_msg>linux: fix warning message that was bugging me<commit_after><|endoftext|>


<commit_before><commit_msg>Build fix to pick up changes in gpu_messages_internal.h for mac.<commit_after><|endoftext|>


<commit_before><commit_msg>fdo#75757: remove inheritance to std::vector<commit_after><|endoftext|>


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

#pragma hdrstop

#ifndef _SVX_FMPAGE_HXX
#include "fmpage.hxx"
#endif

#ifndef _SVX_FMOBJ_HXX
#include "fmobj.hxx"
#endif

#ifndef _SVX_FMGLOB_HXX
#include "fmglob.hxx"
#endif

#ifndef _SVX_FMDPAGE_HXX
#include "fmdpage.hxx"
#endif

#ifndef _SVX_UNOSHAPE_HXX //autogen
#include "unoshape.hxx"
#endif
#ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
#include <cppuhelper/queryinterface.hxx>
#endif
#ifndef _CPPUHELPER_TYPEPROVIDER_HXX_
#include <cppuhelper/typeprovider.hxx>
#endif

DBG_NAME(SvxFmDrawPage);
SvxFmDrawPage::SvxFmDrawPage( SdrPage* pInPage ) :
    SvxDrawPage( pInPage )
{
    DBG_CTOR(SvxFmDrawPage,NULL);
}

SvxFmDrawPage::~SvxFmDrawPage() throw ()
{
    DBG_DTOR(SvxFmDrawPage,NULL);
}

::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL SvxFmDrawPage::getImplementationId() throw(::com::sun::star::uno::RuntimeException)
{
    static ::cppu::OImplementationId* pId = 0;
    if (! pId)
    {
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
        if (! pId)
        {
            static ::cppu::OImplementationId aId;
            pId = &aId;
        }
    }
    return pId->getImplementationId();
}

::com::sun::star::uno::Any SAL_CALL SvxFmDrawPage::queryAggregation( const ::com::sun::star::uno::Type& aType ) throw(::com::sun::star::uno::RuntimeException)
{
    ::com::sun::star::uno::Any aRet = ::cppu::queryInterface(aType,
        static_cast< ::com::sun::star::form::XFormsSupplier*>(this));
    if(aRet.hasValue())
        return aRet;

    return SvxDrawPage::queryAggregation(aType);
}

/***********************************************************************
*                                                                      *
***********************************************************************/
::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL SvxFmDrawPage::getTypes(  ) throw(::com::sun::star::uno::RuntimeException)
{
    ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > aTypes(SvxDrawPage::getTypes());
    aTypes.realloc(aTypes.getLength() + 1);
    ::com::sun::star::uno::Type* pTypes = aTypes.getArray();

    pTypes[aTypes.getLength()-1] = ::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormsSupplier>*)0);
    return aTypes;
}

SdrObject *SvxFmDrawPage::_CreateSdrObject( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > & xDescr ) throw ()
{
    ::rtl::OUString aShapeType( xDescr->getShapeType() );

    if (aShapeType  ==  ::rtl::OUString::createFromAscii("com.sun.star.drawing.ShapeControl"))
        return new FmFormObj(OBJ_FM_CONTROL);
    else
        return SvxDrawPage::_CreateSdrObject( xDescr );

}

::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >  SvxFmDrawPage::_CreateShape( SdrObject *pObj ) const throw ()
{
    if( FmFormInventor == pObj->GetObjInventor() )
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >  xShape = (SvxShape*)new SvxShapeControl( pObj );
        return xShape;
    }
    else
        return SvxDrawPage::_CreateShape( pObj );
}

// ::com::sun::star::form::XFormsSupplier
::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > SAL_CALL SvxFmDrawPage::getForms(void) throw( ::com::sun::star::uno::RuntimeException )
{
    ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >  xForms;

    FmFormPage *pFmPage = PTR_CAST( FmFormPage, GetSdrPage() );
    if( pFmPage )
        xForms = pFmPage->GetForms();

    return xForms;
}

// ::com::sun::star::lang::XServiceInfo
::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL SvxFmDrawPage::getSupportedServiceNames(void) throw( ::com::sun::star::uno::RuntimeException )
{
    /* TODO: DG? Irgendwelche Services?
    ::com::sun::star::uno::Sequence aSeq( SvxDrawPage::getSupportedServiceNames() );
    addToSequence( aSeq, 1, ::rtl::OUString::createFromAscii("stardiv.form.superservice?") );
    return aSeq;
    */

    return SvxDrawPage::getSupportedServiceNames();
}

<commit_msg>INTEGRATION: CWS xmlperf02 (1.4.584); FILE MERGED 2005/03/17 12:03:15 fs 1.4.584.2: #119224# ::cppu::queryInterface does not care for interface inheritance 2005/02/01 14:45:03 fs 1.4.584.1: #119224# XFormsSupplier2: asking (cheaply) for hasForms, without actually obtaining the forms container<commit_after>/*************************************************************************
 *
 *  $RCSfile: fmdpage.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2005-03-18 18:42:33 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#pragma hdrstop

#ifndef _SVX_FMPAGE_HXX
#include "fmpage.hxx"
#endif

#ifndef _SVX_FMOBJ_HXX
#include "fmobj.hxx"
#endif

#ifndef _SVX_FMGLOB_HXX
#include "fmglob.hxx"
#endif

#ifndef _SVX_FMDPAGE_HXX
#include "fmdpage.hxx"
#endif

#ifndef _SVX_UNOSHAPE_HXX //autogen
#include "unoshape.hxx"
#endif
#ifndef _CPPUHELPER_QUERYINTERFACE_HXX_
#include <cppuhelper/queryinterface.hxx>
#endif
#ifndef _CPPUHELPER_TYPEPROVIDER_HXX_
#include <cppuhelper/typeprovider.hxx>
#endif

using ::com::sun::star::uno::Any;
using ::com::sun::star::uno::RuntimeException;
using ::com::sun::star::form::XFormsSupplier2;

DBG_NAME(SvxFmDrawPage);
SvxFmDrawPage::SvxFmDrawPage( SdrPage* pInPage ) :
    SvxDrawPage( pInPage )
{
    DBG_CTOR(SvxFmDrawPage,NULL);
}

SvxFmDrawPage::~SvxFmDrawPage() throw ()
{
    DBG_DTOR(SvxFmDrawPage,NULL);
}

::com::sun::star::uno::Sequence< sal_Int8 > SAL_CALL SvxFmDrawPage::getImplementationId() throw(::com::sun::star::uno::RuntimeException)
{
    static ::cppu::OImplementationId* pId = 0;
    if (! pId)
    {
        ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
        if (! pId)
        {
            static ::cppu::OImplementationId aId;
            pId = &aId;
        }
    }
    return pId->getImplementationId();
}

Any SAL_CALL SvxFmDrawPage::queryAggregation( const ::com::sun::star::uno::Type& _rType ) throw(RuntimeException)
{
    Any aRet = ::cppu::queryInterface   (   _rType
                                        ,   static_cast< XFormsSupplier2* >( this )
                                        ,   static_cast< XFormsSupplier* >( this )
                                        );
    if ( !aRet.hasValue() )
        aRet = SvxDrawPage::queryAggregation( _rType );

    return aRet;
}

/***********************************************************************
*                                                                      *
***********************************************************************/
::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL SvxFmDrawPage::getTypes(  ) throw(::com::sun::star::uno::RuntimeException)
{
    ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > aTypes(SvxDrawPage::getTypes());
    aTypes.realloc(aTypes.getLength() + 1);
    ::com::sun::star::uno::Type* pTypes = aTypes.getArray();

    pTypes[aTypes.getLength()-1] = ::getCppuType((const ::com::sun::star::uno::Reference< ::com::sun::star::form::XFormsSupplier>*)0);
    return aTypes;
}

SdrObject *SvxFmDrawPage::_CreateSdrObject( const ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape > & xDescr ) throw ()
{
    ::rtl::OUString aShapeType( xDescr->getShapeType() );

    if (aShapeType  ==  ::rtl::OUString::createFromAscii("com.sun.star.drawing.ShapeControl"))
        return new FmFormObj(OBJ_FM_CONTROL);
    else
        return SvxDrawPage::_CreateSdrObject( xDescr );

}

::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >  SvxFmDrawPage::_CreateShape( SdrObject *pObj ) const throw ()
{
    if( FmFormInventor == pObj->GetObjInventor() )
    {
        ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShape >  xShape = (SvxShape*)new SvxShapeControl( pObj );
        return xShape;
    }
    else
        return SvxDrawPage::_CreateShape( pObj );
}

// XFormsSupplier
::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer > SAL_CALL SvxFmDrawPage::getForms(void) throw( ::com::sun::star::uno::RuntimeException )
{
    ::com::sun::star::uno::Reference< ::com::sun::star::container::XNameContainer >  xForms;

    FmFormPage *pFmPage = PTR_CAST( FmFormPage, GetSdrPage() );
    if( pFmPage )
        xForms = pFmPage->GetForms();

    return xForms;
}

// XFormsSupplier2
sal_Bool SAL_CALL SvxFmDrawPage::hasForms(void) throw( ::com::sun::star::uno::RuntimeException )
{
    sal_Bool bHas = sal_False;
    FmFormPage* pFormPage = PTR_CAST( FmFormPage, GetSdrPage() );
    if ( pFormPage )
        bHas = pFormPage->GetForms( false ).is();
    return bHas;
}

// ::com::sun::star::lang::XServiceInfo
::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL SvxFmDrawPage::getSupportedServiceNames(void) throw( ::com::sun::star::uno::RuntimeException )
{
    return SvxDrawPage::getSupportedServiceNames();
}

<|endoftext|>


<commit_before>/*
kmsc - Kurento Media Server C/C++ implementation
Copyright (C) 2012 Tikal Technologies

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3
as published by the Free Software Foundation.

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/>.
*/

#include <signal.h>
#include <execinfo.h>

#include "MediaServerServiceHandler.h"

#include <protocol/TBinaryProtocol.h>
#include <transport/TServerSocket.h>
#include <transport/TBufferTransports.h>
#include <server/TNonblockingServer.h>
#include <concurrency/PosixThreadFactory.h>
#include <concurrency/ThreadManager.h>

#include "media_config_loader.h"

#include <glibmm.h>
#include <fstream>

#include <gst/gst.h>

#include <version.h>

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::apache::thrift::concurrency;

using namespace ::kurento;

using boost::shared_ptr;
using ::kurento::MediaServerServiceHandler;
using ::Glib::KeyFile;
using ::Glib::KeyFileFlags;

#define GST_CAT_DEFAULT media_server
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "media_server"

#define DEFAULT_CONFIG_FILE "/etc/kurento/kurento.conf"

#define MEDIA_SERVER_ADDRESS "localhost"
#define MEDIA_SERVER_SERVICE_PORT 9090

#define MEDIA_SERVER_ADDRESS_KEY "serverAddress"
#define MEDIA_SERVER_SERVICE_PORT_KEY "serverPort"

static std::string serverAddress;
static gint serverServicePort;
static std::string sessionSpec;
static KeyFile configFile;

Glib::RefPtr<Glib::MainLoop> loop = Glib::MainLoop::create(true);
static TNonblockingServer *p_server = NULL;

static void create_media_server_service() {
	int port;

	port = MEDIA_SERVER_SERVICE_PORT;

	shared_ptr<MediaServerServiceHandler> handler(
			new MediaServerServiceHandler());
	shared_ptr<TProcessor> processor(new MediaServerServiceProcessor(handler));
	shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
	shared_ptr<PosixThreadFactory> threadFactory(new PosixThreadFactory ());
	shared_ptr<ThreadManager> threadManager= ThreadManager::newSimpleThreadManager(15);

	threadManager->threadFactory(threadFactory);
	threadManager->start();
	TNonblockingServer server(processor, protocolFactory, port, threadManager);
	p_server = &server;
	GST_INFO("Starting MediaServerService");
	server.serve();

	GST_INFO("MediaServerService stopped finishing thread");
	throw Glib::Thread::Exit();
}

static void
check_port(int port)
{
	if (port <=0 || port > G_MAXUSHORT)
		throw Glib::KeyFileError(Glib::KeyFileError::PARSE,
							"Invalid value");
}

static void
set_default_server_config()
{
	serverAddress = MEDIA_SERVER_ADDRESS;
	serverServicePort = MEDIA_SERVER_SERVICE_PORT;
}

static void load_config(const std::string &file_name) {
	gint port;

	GST_INFO("Reading configuration from: %s", file_name.c_str());
	/* Try to open de file */
	{
		std::ifstream file(file_name);
		if (!file) {
			GST_INFO("Config file not found, creating a new one");
			std::ofstream of(file_name);
		}
	}
	try {
		if (!configFile.load_from_file(file_name,
				KeyFileFlags::KEY_FILE_KEEP_COMMENTS |
				KeyFileFlags::KEY_FILE_KEEP_TRANSLATIONS )) {
			GST_WARNING("Error loading configuration from %s, loading "
						"default server config, but no "
						"codecs will be available", file_name.c_str());
			set_default_server_config();
			return;
		}
	} catch (Glib::Error ex) {
		GST_WARNING("Error loading configuration: %s", ex.what().c_str());
		GST_WARNING("Error loading configuration from %s, loading "
						"default server config, but no "
						"codecs will be available", file_name.c_str());
		set_default_server_config();
		return;
	}

	try {
		serverAddress = configFile.get_string(SERVER_GROUP,
							MEDIA_SERVER_ADDRESS_KEY);
	} catch (Glib::KeyFileError err) {
		GST_INFO(err.what().c_str());
		GST_INFO("Setting default address");
		configFile.set_string(SERVER_GROUP, MEDIA_SERVER_ADDRESS_KEY,
								MEDIA_SERVER_ADDRESS);
		serverAddress = MEDIA_SERVER_ADDRESS;
	}

	try {
		port = configFile.get_integer(SERVER_GROUP, MEDIA_SERVER_SERVICE_PORT_KEY);
		check_port(port);
		serverServicePort = port;
	} catch (Glib::KeyFileError err) {
		GST_INFO(err.what().c_str());
		GST_INFO("Setting default server port");
		configFile.set_integer(SERVER_GROUP, MEDIA_SERVER_SERVICE_PORT_KEY,
							MEDIA_SERVER_SERVICE_PORT);
		serverServicePort = MEDIA_SERVER_SERVICE_PORT;
	}

	try {
		load_spec(configFile, sessionSpec);
	} catch (Glib::KeyFileError err) {
		GST_WARNING(err.what().c_str());
		GST_WARNING("Wrong codec configuration, communication won't be possible");
	}

	std::ofstream f(file_name, std::ios::out | std::ios::trunc);
	f << configFile.to_data();
	f.close();

	GST_INFO("Configuration loaded successfully");
	GST_DEBUG("Final config file:\n%s", configFile.to_data().c_str());
}

static void
initialiseExecutableName(char *exe, int size) {
	char link[1024];
	int len;

	snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
	len = readlink(link, exe, size);

	if(len ==-1) {
		fprintf(stderr,"ERROR GETTING NAME\n");
		exit(1);
	}

	exe[len] = '\0';
}

static const char*
getExecutableName() {
	static char* exe = NULL;
	static char aux[1024];

	if (exe == NULL) {
		initialiseExecutableName(aux, sizeof(aux));
		exe = aux;
	}

	return exe;
}

static void
bt_sighandler(int sig, siginfo_t *info, gpointer data) {

	void *trace[35];
	char **messages = (char **)NULL;
	int i, trace_size = 0;
// 	ucontext_t *uc = (ucontext_t *)data;

	/* Do something useful with siginfo_t */
	if (sig == SIGSEGV) {
		printf("Got signal %d, faulty address is %p\n", sig,
						(gpointer) info->si_addr);
	} else if (sig == SIGKILL || sig == SIGINT) {
		loop->quit();
		if (p_server != NULL) {
			p_server->stop();
			p_server = NULL;
		}
		return;
	} else {
		printf("Got signal %d\n", sig);
	}

	trace_size = backtrace(trace, 35);
	/* overwrite sigaction with caller's address */
	//trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];

	messages = backtrace_symbols(trace, trace_size);
	/* skip first stack frame (points here) */
	g_print("\t[bt] Execution path:\n");
	for (i=1; i<trace_size; ++i) {
		g_print("\t[bt] #%d %s\n", i, messages[i]);
		char syscom[256];
		gchar **strs;
		const gchar *exe;

		strs = g_strsplit(messages[i], "(", 2);

		if (strs[1] == NULL)
			exe = getExecutableName();
		else
			exe = strs[0];

		sprintf(syscom, "echo -n \"\t[bt]\t\t\"; addr2line %p -s -e %s",
								trace[i], exe);

		g_strfreev(strs);
		system(syscom);
	}

	if (sig == SIGPIPE) {
		GST_DEBUG("Ignore sigpipe");
	} else {
		exit(sig);
	}
}

int main(int argc, char **argv) {
	struct sigaction sa;

	gst_init(&argc, &argv);
	GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);

	/* Install our signal handler */
	sa.sa_sigaction = /*(void (*)(int, siginfo*, gpointer))*/bt_sighandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART | SA_SIGINFO;

	sigaction(SIGSEGV, &sa, NULL);
	sigaction(SIGPIPE, &sa, NULL);
	sigaction(SIGINT, &sa, NULL);
	sigaction(SIGKILL, &sa, NULL);
	Glib::thread_init();

	GST_INFO("Kmsc version: %s", get_version());

	load_config(DEFAULT_CONFIG_FILE);

	sigc::slot<void> ss = sigc::ptr_fun(&create_media_server_service);
	Glib::Thread *serverServiceThread = Glib::Thread::create(ss, true);
	loop->run();
	serverServiceThread->join();

	return 0;
}
<commit_msg>Use command line option parser.<commit_after>/*
kmsc - Kurento Media Server C/C++ implementation
Copyright (C) 2012 Tikal Technologies

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3
as published by the Free Software Foundation.

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/>.
*/

#include <signal.h>
#include <execinfo.h>

#include "MediaServerServiceHandler.h"

#include <protocol/TBinaryProtocol.h>
#include <transport/TServerSocket.h>
#include <transport/TBufferTransports.h>
#include <server/TNonblockingServer.h>
#include <concurrency/PosixThreadFactory.h>
#include <concurrency/ThreadManager.h>

#include "media_config_loader.h"

#include <glibmm.h>
#include <fstream>

#include <gst/gst.h>

#include <version.h>

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;
using namespace ::apache::thrift::concurrency;

using namespace ::kurento;

using boost::shared_ptr;
using ::kurento::MediaServerServiceHandler;
using ::Glib::KeyFile;
using ::Glib::KeyFileFlags;

#define GST_CAT_DEFAULT media_server
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "media_server"

#define DEFAULT_CONFIG_FILE "/etc/kurento/kurento.conf"

#define MEDIA_SERVER_ADDRESS "localhost"
#define MEDIA_SERVER_SERVICE_PORT 9090

#define MEDIA_SERVER_ADDRESS_KEY "serverAddress"
#define MEDIA_SERVER_SERVICE_PORT_KEY "serverPort"

static std::string serverAddress;
static gint serverServicePort;
static std::string sessionSpec;
static KeyFile configFile;

Glib::RefPtr<Glib::MainLoop> loop = Glib::MainLoop::create(true);
static TNonblockingServer *p_server = NULL;

static gchar *conf_file;

static GOptionEntry entries[] =
{
	{ "conf-file", 'f', 0, G_OPTION_ARG_FILENAME, &conf_file, "Configuration file", NULL },
	{ NULL }
};

static void create_media_server_service() {
	int port;

	port = MEDIA_SERVER_SERVICE_PORT;

	shared_ptr<MediaServerServiceHandler> handler(
			new MediaServerServiceHandler());
	shared_ptr<TProcessor> processor(new MediaServerServiceProcessor(handler));
	shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
	shared_ptr<PosixThreadFactory> threadFactory(new PosixThreadFactory ());
	shared_ptr<ThreadManager> threadManager= ThreadManager::newSimpleThreadManager(15);

	threadManager->threadFactory(threadFactory);
	threadManager->start();
	TNonblockingServer server(processor, protocolFactory, port, threadManager);
	p_server = &server;
	GST_INFO("Starting MediaServerService");
	server.serve();

	GST_INFO("MediaServerService stopped finishing thread");
	throw Glib::Thread::Exit();
}

static void
check_port(int port)
{
	if (port <=0 || port > G_MAXUSHORT)
		throw Glib::KeyFileError(Glib::KeyFileError::PARSE,
							"Invalid value");
}

static void
set_default_server_config()
{
	serverAddress = MEDIA_SERVER_ADDRESS;
	serverServicePort = MEDIA_SERVER_SERVICE_PORT;
}

static void load_config(const std::string &file_name) {
	gint port;

	GST_INFO("Reading configuration from: %s", file_name.c_str());
	/* Try to open de file */
	{
		std::ifstream file(file_name);
		if (!file) {
			GST_INFO("Config file not found, creating a new one");
			std::ofstream of(file_name);
		}
	}
	try {
		if (!configFile.load_from_file(file_name,
				KeyFileFlags::KEY_FILE_KEEP_COMMENTS |
				KeyFileFlags::KEY_FILE_KEEP_TRANSLATIONS )) {
			GST_WARNING("Error loading configuration from %s, loading "
						"default server config, but no "
						"codecs will be available", file_name.c_str());
			set_default_server_config();
			return;
		}
	} catch (Glib::Error ex) {
		GST_WARNING("Error loading configuration: %s", ex.what().c_str());
		GST_WARNING("Error loading configuration from %s, loading "
						"default server config, but no "
						"codecs will be available", file_name.c_str());
		set_default_server_config();
		return;
	}

	try {
		serverAddress = configFile.get_string(SERVER_GROUP,
							MEDIA_SERVER_ADDRESS_KEY);
	} catch (Glib::KeyFileError err) {
		GST_INFO(err.what().c_str());
		GST_INFO("Setting default address");
		configFile.set_string(SERVER_GROUP, MEDIA_SERVER_ADDRESS_KEY,
								MEDIA_SERVER_ADDRESS);
		serverAddress = MEDIA_SERVER_ADDRESS;
	}

	try {
		port = configFile.get_integer(SERVER_GROUP, MEDIA_SERVER_SERVICE_PORT_KEY);
		check_port(port);
		serverServicePort = port;
	} catch (Glib::KeyFileError err) {
		GST_INFO(err.what().c_str());
		GST_INFO("Setting default server port");
		configFile.set_integer(SERVER_GROUP, MEDIA_SERVER_SERVICE_PORT_KEY,
							MEDIA_SERVER_SERVICE_PORT);
		serverServicePort = MEDIA_SERVER_SERVICE_PORT;
	}

	try {
		load_spec(configFile, sessionSpec);
	} catch (Glib::KeyFileError err) {
		GST_WARNING(err.what().c_str());
		GST_WARNING("Wrong codec configuration, communication won't be possible");
	}

	std::ofstream f(file_name, std::ios::out | std::ios::trunc);
	f << configFile.to_data();
	f.close();

	GST_INFO("Configuration loaded successfully");
	GST_DEBUG("Final config file:\n%s", configFile.to_data().c_str());
}

static void
initialiseExecutableName(char *exe, int size) {
	char link[1024];
	int len;

	snprintf(link, sizeof(link), "/proc/%d/exe", getpid());
	len = readlink(link, exe, size);

	if(len ==-1) {
		fprintf(stderr,"ERROR GETTING NAME\n");
		exit(1);
	}

	exe[len] = '\0';
}

static const char*
getExecutableName() {
	static char* exe = NULL;
	static char aux[1024];

	if (exe == NULL) {
		initialiseExecutableName(aux, sizeof(aux));
		exe = aux;
	}

	return exe;
}

static void
bt_sighandler(int sig, siginfo_t *info, gpointer data) {

	void *trace[35];
	char **messages = (char **)NULL;
	int i, trace_size = 0;
// 	ucontext_t *uc = (ucontext_t *)data;

	/* Do something useful with siginfo_t */
	if (sig == SIGSEGV) {
		printf("Got signal %d, faulty address is %p\n", sig,
						(gpointer) info->si_addr);
	} else if (sig == SIGKILL || sig == SIGINT) {
		loop->quit();
		if (p_server != NULL) {
			p_server->stop();
			p_server = NULL;
		}
		return;
	} else {
		printf("Got signal %d\n", sig);
	}

	trace_size = backtrace(trace, 35);
	/* overwrite sigaction with caller's address */
	//trace[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];

	messages = backtrace_symbols(trace, trace_size);
	/* skip first stack frame (points here) */
	g_print("\t[bt] Execution path:\n");
	for (i=1; i<trace_size; ++i) {
		g_print("\t[bt] #%d %s\n", i, messages[i]);
		char syscom[256];
		gchar **strs;
		const gchar *exe;

		strs = g_strsplit(messages[i], "(", 2);

		if (strs[1] == NULL)
			exe = getExecutableName();
		else
			exe = strs[0];

		sprintf(syscom, "echo -n \"\t[bt]\t\t\"; addr2line %p -s -e %s",
								trace[i], exe);

		g_strfreev(strs);
		system(syscom);
	}

	if (sig == SIGPIPE) {
		GST_DEBUG("Ignore sigpipe");
	} else {
		exit(sig);
	}
}

int main(int argc, char **argv) {
	GError *error = NULL;
	GOptionContext *context;

	struct sigaction sa;

	context = g_option_context_new("");
	g_option_context_add_main_entries(context, entries, NULL);
	g_option_context_add_group(context, gst_init_get_option_group());
	if (!g_option_context_parse(context, &argc, &argv, &error)) {
		GST_ERROR("option parsing failed: %s\n", error->message);
		exit (1);
	}

	gst_init(&argc, &argv);
	GST_DEBUG_CATEGORY_INIT(GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0, GST_DEFAULT_NAME);

	/* Install our signal handler */
	sa.sa_sigaction = /*(void (*)(int, siginfo*, gpointer))*/bt_sighandler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART | SA_SIGINFO;

	sigaction(SIGSEGV, &sa, NULL);
	sigaction(SIGPIPE, &sa, NULL);
	sigaction(SIGINT, &sa, NULL);
	sigaction(SIGKILL, &sa, NULL);
	Glib::thread_init();

	GST_INFO("Kmsc version: %s", get_version());

	load_config(DEFAULT_CONFIG_FILE);

	sigc::slot<void> ss = sigc::ptr_fun(&create_media_server_service);
	Glib::Thread *serverServiceThread = Glib::Thread::create(ss, true);
	loop->run();
	serverServiceThread->join();

	return 0;
}
<|endoftext|>


<commit_before>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>

#include <regex>
#include <unordered_map>
#include <thread>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        class Request {
            friend class ServerBase<socket_type>;
        public:
            std::string method, path, http_version;

            std::istream content;

            std::unordered_map<std::string, std::string> header;

            std::smatch path_match;

        private:
            Request(): content(&content_buffer) {}

            boost::asio::streambuf content_buffer;
        };

        typedef std::map<std::string, std::unordered_map<std::string,
                std::function<void(std::ostream&, std::shared_ptr<ServerBase<socket_type>::Request>)> > > resource_type;

        resource_type resource;

        resource_type default_resource;

        void start() {
            //All resources with default_resource at the end of vector
            //Used in the respond-method
            for(auto it=resource.begin(); it!=resource.end();it++) {
                all_resources.push_back(it);
            }
            for(auto it=default_resource.begin(); it!=default_resource.end();it++) {
                all_resources.push_back(it);
            }

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            for(size_t c=1;c<num_threads;c++) {
                threads.emplace_back([this](){
                    m_io_service.run();
                });
            }

            //Main thread
            m_io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

    protected:
        boost::asio::io_service m_io_service;
        boost::asio::ip::tcp::endpoint endpoint;
        boost::asio::ip::tcp::acceptor acceptor;
        size_t num_threads;
        std::vector<std::thread> threads;

        size_t timeout_request;
        size_t timeout_content;

        //All resources with default_resource at the end of vector
        //Created in start()
        std::vector<typename resource_type::iterator> all_resources;

        ServerBase(unsigned short port, size_t num_threads, size_t timeout_request, size_t timeout_send_or_receive) :
                endpoint(boost::asio::ip::tcp::v4(), port), acceptor(m_io_service, endpoint), num_threads(num_threads),
                timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        virtual std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, size_t seconds)=0;

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->content_buffer, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->content_buffer.size()-bytes_transferred;

                    parse_request(request, request->content);

                    //If content, read that as well
                    if(request->header.count("Content-Length")>0) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);

                        boost::asio::async_read(*socket, request->content_buffer,
                                boost::asio::transfer_exactly(stoull(request->header["Content-Length"])-num_additional_bytes),
                                [this, socket, request, timer]
                                (const boost::system::error_code& ec, size_t bytes_transferred) {
                            if(timeout_content>0)
                                timer->cancel();
                            if(!ec)
                                write_response(socket, request);
                        });
                    }
                    else {
                        write_response(socket, request);
                    }
                }
            });
        }

        void parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::regex e("^([^ ]*) ([^ ]*) HTTP/([^ ]*)$");

            std::smatch sm;

            //First parse request method, path, and HTTP-version from the first line
            std::string line;
            getline(stream, line);
            line.pop_back();
            if(std::regex_match(line, sm, e)) {
                request->method=sm[1];
                request->path=sm[2];
                request->http_version=sm[3];

                bool matched;
                e="^([^:]*): ?(.*)$";
                //Parse the rest of the header
                do {
                    getline(stream, line);
                    line.pop_back();
                    matched=std::regex_match(line, sm, e);
                    if(matched) {
                        request->header[sm[1]]=sm[2];
                    }

                } while(matched==true);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and generate response
            for(auto res_it: all_resources) {
                std::regex e(res_it->first);
                std::smatch sm_res;
                if(std::regex_match(request->path, sm_res, e)) {
                    if(res_it->second.count(request->method)>0) {
                        request->path_match=move(sm_res);

                        std::shared_ptr<boost::asio::streambuf> write_buffer(new boost::asio::streambuf);
                        std::ostream response(write_buffer.get());
                        res_it->second[request->method](response, request);

                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);

                        //Capture write_buffer in lambda so it is not destroyed before async_write is finished
                        boost::asio::async_write(*socket, *write_buffer,
                                [this, socket, request, write_buffer, timer]
                                (const boost::system::error_code& ec, size_t bytes_transferred) {
                            if(timeout_content>0)
                                timer->cancel();
                            //HTTP persistent connection (HTTP 1.1):
                            if(!ec && stof(request->http_version)>1.05)
                                read_request_and_content(socket);
                        });
                        return;
                    }
                }
            }
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, size_t timeout_request=5, size_t timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {};

    private:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(m_io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec) {
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    read_request_and_content(socket);
                }
            });
        }

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<HTTP> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(m_io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
                    socket->close();
                }
            });
            return timer;
        }
    };
}
#endif	/* SERVER_HTTP_HPP */<commit_msg>Added Server::stop()<commit_after>#ifndef SERVER_HTTP_HPP
#define	SERVER_HTTP_HPP

#include <boost/asio.hpp>

#include <regex>
#include <unordered_map>
#include <thread>

namespace SimpleWeb {
    template <class socket_type>
    class ServerBase {
    public:
        class Request {
            friend class ServerBase<socket_type>;
        public:
            std::string method, path, http_version;

            std::istream content;

            std::unordered_map<std::string, std::string> header;

            std::smatch path_match;

        private:
            Request(): content(&content_buffer) {}

            boost::asio::streambuf content_buffer;
        };

        typedef std::map<std::string, std::unordered_map<std::string,
                std::function<void(std::ostream&, std::shared_ptr<ServerBase<socket_type>::Request>)> > > resource_type;

        resource_type resource;

        resource_type default_resource;

        void start() {
            //All resources with default_resource at the end of vector
            //Used in the respond-method
            for(auto it=resource.begin(); it!=resource.end();it++) {
                all_resources.push_back(it);
            }
            for(auto it=default_resource.begin(); it!=default_resource.end();it++) {
                all_resources.push_back(it);
            }

            accept();

            //If num_threads>1, start m_io_service.run() in (num_threads-1) threads for thread-pooling
            for(size_t c=1;c<num_threads;c++) {
                threads.emplace_back([this](){
                    m_io_service.run();
                });
            }

            //Main thread
            m_io_service.run();

            //Wait for the rest of the threads, if any, to finish as well
            for(auto& t: threads) {
                t.join();
            }
        }

        void stop() {
            m_io_service.stop();
        }

    protected:
        boost::asio::io_service m_io_service;
        boost::asio::ip::tcp::endpoint endpoint;
        boost::asio::ip::tcp::acceptor acceptor;
        size_t num_threads;
        std::vector<std::thread> threads;

        size_t timeout_request;
        size_t timeout_content;

        //All resources with default_resource at the end of vector
        //Created in start()
        std::vector<typename resource_type::iterator> all_resources;

        ServerBase(unsigned short port, size_t num_threads, size_t timeout_request, size_t timeout_send_or_receive) :
                endpoint(boost::asio::ip::tcp::v4(), port), acceptor(m_io_service, endpoint), num_threads(num_threads),
                timeout_request(timeout_request), timeout_content(timeout_send_or_receive) {}

        virtual void accept()=0;

        virtual std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<socket_type> socket, size_t seconds)=0;

        void read_request_and_content(std::shared_ptr<socket_type> socket) {
            //Create new streambuf (Request::streambuf) for async_read_until()
            //shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<Request> request(new Request());

            //Set timeout on the following boost::asio::async-read or write function
            std::shared_ptr<boost::asio::deadline_timer> timer;
            if(timeout_request>0)
                timer=set_timeout_on_socket(socket, timeout_request);

            boost::asio::async_read_until(*socket, request->content_buffer, "\r\n\r\n",
                    [this, socket, request, timer](const boost::system::error_code& ec, size_t bytes_transferred) {
                if(timeout_request>0)
                    timer->cancel();
                if(!ec) {
                    //request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
                    //"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
                    //The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
                    //streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
                    size_t num_additional_bytes=request->content_buffer.size()-bytes_transferred;

                    parse_request(request, request->content);

                    //If content, read that as well
                    if(request->header.count("Content-Length")>0) {
                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);

                        boost::asio::async_read(*socket, request->content_buffer,
                                boost::asio::transfer_exactly(stoull(request->header["Content-Length"])-num_additional_bytes),
                                [this, socket, request, timer]
                                (const boost::system::error_code& ec, size_t bytes_transferred) {
                            if(timeout_content>0)
                                timer->cancel();
                            if(!ec)
                                write_response(socket, request);
                        });
                    }
                    else {
                        write_response(socket, request);
                    }
                }
            });
        }

        void parse_request(std::shared_ptr<Request> request, std::istream& stream) const {
            std::regex e("^([^ ]*) ([^ ]*) HTTP/([^ ]*)$");

            std::smatch sm;

            //First parse request method, path, and HTTP-version from the first line
            std::string line;
            getline(stream, line);
            line.pop_back();
            if(std::regex_match(line, sm, e)) {
                request->method=sm[1];
                request->path=sm[2];
                request->http_version=sm[3];

                bool matched;
                e="^([^:]*): ?(.*)$";
                //Parse the rest of the header
                do {
                    getline(stream, line);
                    line.pop_back();
                    matched=std::regex_match(line, sm, e);
                    if(matched) {
                        request->header[sm[1]]=sm[2];
                    }

                } while(matched==true);
            }
        }

        void write_response(std::shared_ptr<socket_type> socket, std::shared_ptr<Request> request) {
            //Find path- and method-match, and generate response
            for(auto res_it: all_resources) {
                std::regex e(res_it->first);
                std::smatch sm_res;
                if(std::regex_match(request->path, sm_res, e)) {
                    if(res_it->second.count(request->method)>0) {
                        request->path_match=move(sm_res);

                        std::shared_ptr<boost::asio::streambuf> write_buffer(new boost::asio::streambuf);
                        std::ostream response(write_buffer.get());
                        res_it->second[request->method](response, request);

                        //Set timeout on the following boost::asio::async-read or write function
                        std::shared_ptr<boost::asio::deadline_timer> timer;
                        if(timeout_content>0)
                            timer=set_timeout_on_socket(socket, timeout_content);

                        //Capture write_buffer in lambda so it is not destroyed before async_write is finished
                        boost::asio::async_write(*socket, *write_buffer,
                                [this, socket, request, write_buffer, timer]
                                (const boost::system::error_code& ec, size_t bytes_transferred) {
                            if(timeout_content>0)
                                timer->cancel();
                            //HTTP persistent connection (HTTP 1.1):
                            if(!ec && stof(request->http_version)>1.05)
                                read_request_and_content(socket);
                        });
                        return;
                    }
                }
            }
        }
    };

    template<class socket_type>
    class Server : public ServerBase<socket_type> {};

    typedef boost::asio::ip::tcp::socket HTTP;

    template<>
    class Server<HTTP> : public ServerBase<HTTP> {
    public:
        Server(unsigned short port, size_t num_threads=1, size_t timeout_request=5, size_t timeout_content=300) :
                ServerBase<HTTP>::ServerBase(port, num_threads, timeout_request, timeout_content) {};

    private:
        void accept() {
            //Create new socket for this connection
            //Shared_ptr is used to pass temporary objects to the asynchronous functions
            std::shared_ptr<HTTP> socket(new HTTP(m_io_service));

            acceptor.async_accept(*socket, [this, socket](const boost::system::error_code& ec) {
                //Immediately start accepting a new connection
                accept();

                if(!ec) {
                    read_request_and_content(socket);
                }
            });
        }

        std::shared_ptr<boost::asio::deadline_timer> set_timeout_on_socket(std::shared_ptr<HTTP> socket, size_t seconds) {
            std::shared_ptr<boost::asio::deadline_timer> timer(new boost::asio::deadline_timer(m_io_service));
            timer->expires_from_now(boost::posix_time::seconds(seconds));
            timer->async_wait([socket](const boost::system::error_code& ec){
                if(!ec) {
                    socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
                    socket->close();
                }
            });
            return timer;
        }
    };
}
#endif	/* SERVER_HTTP_HPP */<|endoftext|>


<commit_before>#include <cassert>
#include <stdexcept>

extern "C" {
#include <Zend/zend_API.h>
}

#include "array.h"
#include "helpers.h"
#include "string.h"
#include "value.h"
#include "zendstring.h"

phpcxx::Array::Array()
{
    array_init(&this->m_z);
}

phpcxx::Array::Array(zval* z)
{
    assert(z != nullptr);

    if (Z_ISREF_P(z) && Z_TYPE_P(Z_REFVAL_P(z)) == IS_ARRAY) {
        ZVAL_COPY(&this->m_z, Z_REFVAL_P(z));
    }
    else {
        ZVAL_COPY(&this->m_z, z);
        if (Z_TYPE_P(z) != IS_ARRAY) {
            convert_to_array(&this->m_z);
        }
    }
}

phpcxx::Array::Array(Value& v)
    : Array(v.pzval())
{
}

phpcxx::Array::Array(Array& other)
{
    ZVAL_COPY(&this->m_z, &other.m_z);
}

phpcxx::Array::Array(Array&& other)
{
    ZVAL_UNDEF(&this->m_z);
    std::swap(this->m_z, other.m_z);
}

phpcxx::Array::~Array()
{
    i_zval_ptr_dtor(&this->m_z ZEND_FILE_LINE_CC);
#ifdef PHPCXX_DEBUG
    ZVAL_UNDEF(&this->m_z);
#endif
}

phpcxx::Array& phpcxx::Array::operator=(Array& other)
{
    phpcxx::assign(&this->m_z, &other.m_z);
    return *this;
}

phpcxx::Value& phpcxx::Array::operator[](std::nullptr_t)
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    zval* var_ptr = zend_hash_next_index_insert(Z_ARRVAL(this->m_z), &EG(uninitialized_zval));
    if (UNEXPECTED(!var_ptr)) {
        throw std::runtime_error("Cannot add element to the array as the next element is already occupied");
    }

    return *(new(var_ptr) Value(placement_construct));
}

phpcxx::Value& phpcxx::Array::operator[](zend_long idx)
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    zend_ulong h = static_cast<zend_ulong>(idx);
    zval* retval = zend_hash_index_find(Z_ARRVAL(this->m_z), h);
    if (!retval) {
        retval = zend_hash_index_add_new(Z_ARRVAL(this->m_z), h, &EG(uninitialized_zval));
        if (UNEXPECTED(!retval)) {
            throw std::runtime_error("Cannot add element to the array as the next element is already occupied");
        }
    }

    return *(new(retval) Value(placement_construct));
}

phpcxx::Value& phpcxx::Array::operator[](const Value& key)
{
    zval* z = key.pzval();

    while (true) {
        switch (key.type()) {
            case Type::String:    return this->operator[](Z_STR_P(z));
            case Type::Integer:   return this->operator[](Z_LVAL_P(z));
            case Type::Double:    return this->operator[](zend_dval_to_lval(Z_DVAL_P(z)));
            case Type::True:      return this->operator[](static_cast<zend_long>(1l));
            case Type::False:     return this->operator[](static_cast<zend_long>(0l));
            case Type::Resource:  return this->operator[](Z_RES_HANDLE_P(z));
            case Type::Undefined: return this->operator[](ZSTR_EMPTY_ALLOC());
            case Type::Null:      return this->operator[](ZSTR_EMPTY_ALLOC());
            case Type::Reference:
                z = Z_REFVAL_P(z);
                break;

            default:
                throw std::invalid_argument("Illegal offset type");
        }
    }
}

phpcxx::Value& phpcxx::Array::operator[](zend_string* key)
{
    zend_ulong hval;
    if (ZEND_HANDLE_NUMERIC(key, hval)) {
        return this->operator[](static_cast<zend_long>(hval));
    }

    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    zval* retval = zend_hash_find(Z_ARRVAL(this->m_z), key);
    if (retval) {
        if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
            retval = Z_INDIRECT_P(retval);
            if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
                ZVAL_NULL(retval);
            }
        }
    }
    else {
        retval = zend_hash_add_new(Z_ARRVAL(this->m_z), key, &EG(uninitialized_zval));
        if (UNEXPECTED(!retval)) {
            throw std::runtime_error("Cannot add element to the array as the next element is already occupied");
        }
    }

    return *(new(retval) Value(placement_construct));
}

std::size_t phpcxx::Array::size() const
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    return zend_hash_num_elements(Z_ARRVAL(this->m_z));
}

bool phpcxx::Array::isset(zend_long idx) const
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    return zend_hash_index_exists(Z_ARRVAL(this->m_z), static_cast<zend_ulong>(idx));
}

bool phpcxx::Array::isset(const Value& key) const
{
    zval* z = key.pzval();

    while (true) {
        switch (key.type()) {
            case Type::String:    return this->isset(Z_STR_P(z));
            case Type::Integer:   return this->isset(Z_LVAL_P(z));
            case Type::Double:    return this->isset(zend_dval_to_lval(Z_DVAL_P(z)));
            case Type::True:      return this->isset(static_cast<zend_long>(1));
            case Type::False:     return this->isset(static_cast<zend_long>(0));
            case Type::Resource:  return this->isset(Z_RES_HANDLE_P(z));
            case Type::Undefined: return this->isset(ZSTR_EMPTY_ALLOC());
            case Type::Null:      return this->isset(ZSTR_EMPTY_ALLOC());
            case Type::Reference:
                z = Z_REFVAL_P(z);
                break;

            default:
                throw std::invalid_argument("Illegal offset type");
        }
    }
}

bool phpcxx::Array::isset(zend_string* key) const
{
    zend_ulong hval;
    if (ZEND_HANDLE_NUMERIC(key, hval)) {
        return this->isset(static_cast<zend_long>(hval));
    }

    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    return zend_hash_exists(Z_ARRVAL(this->m_z), key);
}

void phpcxx::Array::unset(zend_long idx)
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);
    zend_hash_index_del(Z_ARRVAL(this->m_z), static_cast<zend_ulong>(idx));
}

void phpcxx::Array::unset(const Value& key)
{
    zval* z = key.pzval();

    while (true) {
        switch (key.type()) {
            case Type::String:    return this->unset(Z_STR_P(z));
            case Type::Integer:   return this->unset(Z_LVAL_P(z));
            case Type::Double:    return this->unset(zend_dval_to_lval(Z_DVAL_P(z)));
            case Type::True:      return this->unset(static_cast<zend_long>(1));
            case Type::False:     return this->unset(static_cast<zend_long>(0));
            case Type::Resource:  return this->unset(Z_RES_HANDLE_P(z));
            case Type::Undefined: return this->unset(ZSTR_EMPTY_ALLOC());
            case Type::Null:      return this->unset(ZSTR_EMPTY_ALLOC());
            case Type::Reference:
                z = Z_REFVAL_P(z);
                break;

            default:
                throw std::invalid_argument("Illegal offset type");
        }
    }
}

void phpcxx::Array::unset(zend_string* key)
{
    zend_ulong hval;
    if (ZEND_HANDLE_NUMERIC(key, hval)) {
        return this->unset(static_cast<zend_long>(hval));
    }

    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    HashTable* ht = Z_ARRVAL(this->m_z);
    if (UNEXPECTED(ht == &EG(symbol_table))) {
        zend_delete_global_variable(key);
    }
    else {
        zend_hash_del(ht, key);
    }
}

phpcxx::Value& phpcxx::Array::operator[](const char* key)
{
    return this->operator[](ZendString(key).get());
}

phpcxx::Value& phpcxx::Array::operator[](const string& key)
{
    return this->operator[](ZendString(key).get());
}

phpcxx::Value& phpcxx::Array::operator[](const ZendString& key)
{
    return this->operator[](key.get());
}

bool phpcxx::Array::isset(const char* key) const
{
    return this->isset(ZendString(key).get());
}

bool phpcxx::Array::isset(const string& key) const
{
    return this->isset(ZendString(key).get());
}

bool phpcxx::Array::isset(const ZendString& key) const
{
    return this->isset(key.get());
}

void phpcxx::Array::unset(const char* key)
{
    this->unset(ZendString(key).get());
}

void phpcxx::Array::unset(const string& key)
{
    this->unset(ZendString(key).get());
}

void phpcxx::Array::unset(const ZendString& key)
{
    this->unset(key.get());
}
<commit_msg>Fix segmentation fault<commit_after>#include <cassert>
#include <stdexcept>

extern "C" {
#include <Zend/zend_API.h>
}

#include "array.h"
#include "helpers.h"
#include "string.h"
#include "value.h"
#include "zendstring.h"

phpcxx::Array::Array()
{
    array_init(&this->m_z);
}

phpcxx::Array::Array(zval* z)
{
    assert(z != nullptr);

    if (Z_ISREF_P(z) && Z_TYPE_P(Z_REFVAL_P(z)) == IS_ARRAY) {
        ZVAL_COPY(&this->m_z, Z_REFVAL_P(z));
    }
    else {
        ZVAL_COPY(&this->m_z, z);
        if (Z_TYPE_P(z) != IS_ARRAY) {
            convert_to_array(&this->m_z);
        }
    }
}

phpcxx::Array::Array(Value& v)
    : Array(v.pzval())
{
}

phpcxx::Array::Array(Array& other)
{
    ZVAL_COPY(&this->m_z, &other.m_z);
}

phpcxx::Array::Array(Array&& other)
{
    ZVAL_UNDEF(&this->m_z);
    std::swap(this->m_z, other.m_z);
}

phpcxx::Array::~Array()
{
    i_zval_ptr_dtor(&this->m_z ZEND_FILE_LINE_CC);
#ifdef PHPCXX_DEBUG
    ZVAL_UNDEF(&this->m_z);
#endif
}

phpcxx::Array& phpcxx::Array::operator=(Array& other)
{
    phpcxx::assign(&this->m_z, &other.m_z);
    return *this;
}

phpcxx::Value& phpcxx::Array::operator[](std::nullptr_t)
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    zval* var_ptr = zend_hash_next_index_insert(Z_ARRVAL(this->m_z), &EG(uninitialized_zval));
    if (UNEXPECTED(!var_ptr)) {
        throw std::runtime_error("Cannot add element to the array as the next element is already occupied");
    }

    return *(new(var_ptr) Value(placement_construct));
}

phpcxx::Value& phpcxx::Array::operator[](zend_long idx)
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    zend_ulong h = static_cast<zend_ulong>(idx);
    zval* retval = zend_hash_index_find(Z_ARRVAL(this->m_z), h);
    if (!retval) {
        retval = zend_hash_index_add_new(Z_ARRVAL(this->m_z), h, &EG(uninitialized_zval));
        if (UNEXPECTED(!retval)) {
            throw std::runtime_error("Cannot add element to the array as the next element is already occupied");
        }
    }

    return *(new(retval) Value(placement_construct));
}

phpcxx::Value& phpcxx::Array::operator[](const Value& key)
{
    zval* z = key.pzval();

    while (true) {
        switch (Z_TYPE_P(z)) {
            case IS_STRING:    return this->operator[](Z_STR_P(z));
            case IS_LONG:      return this->operator[](Z_LVAL_P(z));
            case IS_DOUBLE:    return this->operator[](zend_dval_to_lval(Z_DVAL_P(z)));
            case IS_TRUE:      return this->operator[](static_cast<zend_long>(1l));
            case IS_FALSE:     return this->operator[](static_cast<zend_long>(0l));
            case IS_RESOURCE:  return this->operator[](Z_RES_HANDLE_P(z));
            case IS_UNDEF:     return this->operator[](ZSTR_EMPTY_ALLOC());
            case IS_NULL:      return this->operator[](ZSTR_EMPTY_ALLOC());
            case IS_REFERENCE:
                z = Z_REFVAL_P(z);
                break;

            default:
                throw std::invalid_argument("Illegal offset type");
        }
    }
}

phpcxx::Value& phpcxx::Array::operator[](zend_string* key)
{
    zend_ulong hval;
    if (ZEND_HANDLE_NUMERIC(key, hval)) {
        return this->operator[](static_cast<zend_long>(hval));
    }

    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    zval* retval = zend_hash_find(Z_ARRVAL(this->m_z), key);
    if (retval) {
        if (UNEXPECTED(Z_TYPE_P(retval) == IS_INDIRECT)) {
            retval = Z_INDIRECT_P(retval);
            if (UNEXPECTED(Z_TYPE_P(retval) == IS_UNDEF)) {
                ZVAL_NULL(retval);
            }
        }
    }
    else {
        retval = zend_hash_add_new(Z_ARRVAL(this->m_z), key, &EG(uninitialized_zval));
        if (UNEXPECTED(!retval)) {
            throw std::runtime_error("Cannot add element to the array as the next element is already occupied");
        }
    }

    return *(new(retval) Value(placement_construct));
}

std::size_t phpcxx::Array::size() const
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    return zend_hash_num_elements(Z_ARRVAL(this->m_z));
}

bool phpcxx::Array::isset(zend_long idx) const
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    return zend_hash_index_exists(Z_ARRVAL(this->m_z), static_cast<zend_ulong>(idx));
}

bool phpcxx::Array::isset(const Value& key) const
{
    zval* z = key.pzval();

    while (true) {
        switch (Z_TYPE_P(z)) {
            case IS_STRING:    return this->isset(Z_STR_P(z));
            case IS_LONG:      return this->isset(Z_LVAL_P(z));
            case IS_DOUBLE:    return this->isset(zend_dval_to_lval(Z_DVAL_P(z)));
            case IS_TRUE:      return this->isset(static_cast<zend_long>(1));
            case IS_FALSE:     return this->isset(static_cast<zend_long>(0));
            case IS_RESOURCE:  return this->isset(Z_RES_HANDLE_P(z));
            case IS_UNDEF:     return this->isset(ZSTR_EMPTY_ALLOC());
            case IS_NULL:      return this->isset(ZSTR_EMPTY_ALLOC());
            case IS_REFERENCE:
                z = Z_REFVAL_P(z);
                break;

            default:
                throw std::invalid_argument("Illegal offset type");
        }
    }
}

bool phpcxx::Array::isset(zend_string* key) const
{
    zend_ulong hval;
    if (ZEND_HANDLE_NUMERIC(key, hval)) {
        return this->isset(static_cast<zend_long>(hval));
    }

    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    return zend_hash_exists(Z_ARRVAL(this->m_z), key);
}

void phpcxx::Array::unset(zend_long idx)
{
    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);
    zend_hash_index_del(Z_ARRVAL(this->m_z), static_cast<zend_ulong>(idx));
}

void phpcxx::Array::unset(const Value& key)
{
    zval* z = key.pzval();

    while (true) {
        switch (Z_TYPE_P(z)) {
            case IS_STRING:    return this->unset(Z_STR_P(z));
            case IS_LONG:      return this->unset(Z_LVAL_P(z));
            case IS_DOUBLE:    return this->unset(zend_dval_to_lval(Z_DVAL_P(z)));
            case IS_TRUE:      return this->unset(static_cast<zend_long>(1));
            case IS_FALSE:     return this->unset(static_cast<zend_long>(0));
            case IS_RESOURCE:  return this->unset(Z_RES_HANDLE_P(z));
            case IS_UNDEF:     return this->unset(ZSTR_EMPTY_ALLOC());
            case IS_NULL:      return this->unset(ZSTR_EMPTY_ALLOC());
            case IS_REFERENCE:
                z = Z_REFVAL_P(z);
                break;

            default:
                throw std::invalid_argument("Illegal offset type");
        }
    }
}

void phpcxx::Array::unset(zend_string* key)
{
    zend_ulong hval;
    if (ZEND_HANDLE_NUMERIC(key, hval)) {
        return this->unset(static_cast<zend_long>(hval));
    }

    assert(Z_TYPE(this->m_z) == IS_ARRAY);
    SEPARATE_ARRAY(&this->m_z);

    HashTable* ht = Z_ARRVAL(this->m_z);
    if (UNEXPECTED(ht == &EG(symbol_table))) {
        zend_delete_global_variable(key);
    }
    else {
        zend_hash_del(ht, key);
    }
}

phpcxx::Value& phpcxx::Array::operator[](const char* key)
{
    return this->operator[](ZendString(key).get());
}

phpcxx::Value& phpcxx::Array::operator[](const string& key)
{
    return this->operator[](ZendString(key).get());
}

phpcxx::Value& phpcxx::Array::operator[](const ZendString& key)
{
    return this->operator[](key.get());
}

bool phpcxx::Array::isset(const char* key) const
{
    return this->isset(ZendString(key).get());
}

bool phpcxx::Array::isset(const string& key) const
{
    return this->isset(ZendString(key).get());
}

bool phpcxx::Array::isset(const ZendString& key) const
{
    return this->isset(key.get());
}

void phpcxx::Array::unset(const char* key)
{
    this->unset(ZendString(key).get());
}

void phpcxx::Array::unset(const string& key)
{
    this->unset(ZendString(key).get());
}

void phpcxx::Array::unset(const ZendString& key)
{
    this->unset(key.get());
}
<|endoftext|>


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

#include <ros/ros.h>
#include <sensor_msgs/fill_image.h>
#include <usb_cam/usb_cam.h>
#include <image_transport/image_transport.h>
#include <camera_info_manager/camera_info_manager.h>
#include <sstream>

class UsbCamNode
{
public:
  // private ROS node handle
  ros::NodeHandle node_;

  // shared image message
  sensor_msgs::Image img_;
  usb_cam_camera_image_t *camera_image_;
  image_transport::CameraPublisher image_pub_;

  // parameters
  std::string video_device_name_, io_method_name_, pixel_format_name_, camera_name_, camera_info_url_;
  int image_width_, image_height_, framerate_, exposure_, brightness_, contrast_, saturation_, sharpness_, focus_,
      white_balance_;
  bool autofocus_, autoexposure_, auto_white_balance_;
  boost::shared_ptr<camera_info_manager::CameraInfoManager> cinfo_;

  UsbCamNode() :
      node_("~")
  {
    // advertise the main image topic
    image_transport::ImageTransport it(node_);
    image_pub_ = it.advertiseCamera("image_raw", 1);

    // grab the parameters
    node_.param("video_device", video_device_name_, std::string("/dev/video0"));
    node_.param("brightness", brightness_, 128); //0-255
    node_.param("contrast", contrast_, 32); //0-255
    node_.param("saturation", saturation_, 32); //0-255
    node_.param("sharpness", sharpness_, 22); //0-255
    // possible values: mmap, read, userptr
    node_.param("io_method", io_method_name_, std::string("mmap"));
    node_.param("image_width", image_width_, 640);
    node_.param("image_height", image_height_, 480);
    node_.param("framerate", framerate_, 30);
    // possible values: yuyv, uyvy, mjpeg, yuvmono10, rgb24
    node_.param("pixel_format", pixel_format_name_, std::string("mjpeg"));
    // enable/disable autofocus
    node_.param("autofocus", autofocus_, false);
    node_.param("focus", focus_, 51);
    // enable/disable autoexposure
    node_.param("autoexposure", autoexposure_, true);
    node_.param("exposure", exposure_, 100);
    // enable/disable auto white balance temperature
    node_.param("auto_white_balance", auto_white_balance_, true);
    node_.param("white_balance", white_balance_, 4000);

    // load the camera info
    node_.param("camera_frame_id", img_.header.frame_id, std::string("head_camera"));
    node_.param("camera_name", camera_name_, std::string("head_camera"));
    node_.param("camera_info_url", camera_info_url_, std::string(""));
    cinfo_.reset(new camera_info_manager::CameraInfoManager(node_, camera_name_, camera_info_url_));

    ROS_INFO("Starting '%s' (%s) at %dx%d via %s (%s) at %i FPS", camera_name_.c_str(), video_device_name_.c_str(),
             image_width_, image_height_, io_method_name_.c_str(), pixel_format_name_.c_str(), framerate_);

    // set the IO method
    usb_cam_io_method io_method;
    if (io_method_name_ == "mmap")
      io_method = IO_METHOD_MMAP;
    else if (io_method_name_ == "read")
      io_method = IO_METHOD_READ;
    else if (io_method_name_ == "userptr")
      io_method = IO_METHOD_USERPTR;
    else
    {
      ROS_FATAL("Unknown IO method '%s'", io_method_name_.c_str());
      node_.shutdown();
      return;
    }

    // set the pixel format
    usb_cam_pixel_format pixel_format;
    if (pixel_format_name_ == "yuyv")
      pixel_format = PIXEL_FORMAT_YUYV;
    else if (pixel_format_name_ == "uyvy")
      pixel_format = PIXEL_FORMAT_UYVY;
    else if (pixel_format_name_ == "mjpeg")
      pixel_format = PIXEL_FORMAT_MJPEG;
    else if (pixel_format_name_ == "yuvmono10")
      pixel_format = PIXEL_FORMAT_YUVMONO10;
    else if (pixel_format_name_ == "rgb24")
      pixel_format = PIXEL_FORMAT_RGB24;
    else
    {
      ROS_FATAL("Unknown pixel format '%s'", pixel_format_name_.c_str());
      node_.shutdown();
      return;
    }

    // start the camera
    camera_image_ = usb_cam_camera_start(video_device_name_.c_str(), io_method, pixel_format, image_width_,
                                         image_height_, framerate_);

    // set camera parameters
    std::stringstream paramstream;
    paramstream << "brightness=" << brightness_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());
    paramstream.str("");
    paramstream << "contrast=" << contrast_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());
    paramstream.str("");
    paramstream << "saturation=" << saturation_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());
    paramstream.str("");
    paramstream << "sharpness=" << sharpness_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());

    // check auto white balance
    if (!auto_white_balance_)
    {
      this->set_v4l_parameters(video_device_name_, "white_balance_temperature_auto=0");
      std::stringstream ss;
      ss << "white_balance_temperature=" << white_balance_;
      this->set_v4l_parameters(video_device_name_, ss.str());
    }

    // check auto exposure
    if (!autoexposure_)
    {
      // turn down exposure control (from max of 3)
      this->set_v4l_parameters(video_device_name_, "exposure_auto=1");
      // change the exposure level
      std::stringstream ss;
      ss << "exposure_absolute=" << exposure_;
      this->set_v4l_parameters(video_device_name_, ss.str());
    }

    // check auto focus
    if (autofocus_)
    {
      usb_cam_camera_set_auto_focus(1);
      this->set_v4l_parameters(video_device_name_, "focus_auto=1");
    }
    else
    {
      this->set_v4l_parameters(video_device_name_, "focus_auto=0");
      std::stringstream ss;
      ss << "focus_absolute=" << focus_;
      this->set_v4l_parameters(video_device_name_, ss.str());
    }
  }

  virtual ~UsbCamNode()
  {
    usb_cam_camera_shutdown();
  }

  bool take_and_send_image()
  {
    // grab the image
    usb_cam_camera_grab_image(camera_image_);
    // fill the info
    fillImage(img_, "rgb8", camera_image_->height, camera_image_->width, 3 * camera_image_->width,
              camera_image_->image);
    // stamp the image
    img_.header.stamp = ros::Time::now();

    // grab the camera info
    sensor_msgs::CameraInfoPtr ci(new sensor_msgs::CameraInfo(cinfo_->getCameraInfo()));
    ci->header.frame_id = img_.header.frame_id;
    ci->header.stamp = img_.header.stamp;

    // publish the image
    image_pub_.publish(img_, *ci);

    return true;
  }

  bool spin()
  {
    ros::Rate loop_rate(this->framerate_);
    while (node_.ok())
    {
      if (!take_and_send_image())
        ROS_WARN("USB camera did not respond in time.");
      ros::spinOnce();
      loop_rate.sleep();
    }
    return true;
  }

private:

  /**
   * Set video device parameters via calls to v4l-utils.
   *
   * @param dev The device (e.g., "/dev/video0")
   * @param param The full parameter to set (e.g., "focus_auto=1")
   */
  void set_v4l_parameters(std::string dev, std::string param)
  {
    // build the command
    std::stringstream ss;
    ss << "v4l2-ctl --device=" << dev << " -c " << param << " 2>&1";
    std::string cmd = ss.str();

    // capture the output
    std::string output;
    int buffer_size = 256;
    char buffer[buffer_size];
    FILE *stream = popen(cmd.c_str(), "r");
    if (stream)
    {
      while (!feof(stream))
        if (fgets(buffer, buffer_size, stream) != NULL)
          output.append(buffer);
      pclose(stream);
      // any output should be an error
      if (output.length() > 0)
        ROS_WARN("%s", output.c_str());
    }
    else
      ROS_WARN("usb_cam_node could not run '%s'", cmd.c_str());
  }
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "usb_cam");
  UsbCamNode a;
  a.spin();
  return EXIT_SUCCESS;
}
<commit_msg>Parameter to enable/disable auto white balance<commit_after>/*********************************************************************
 *
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2014, Robert Bosch LLC.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the Robert Bosch nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************/

#include <ros/ros.h>
#include <sensor_msgs/fill_image.h>
#include <usb_cam/usb_cam.h>
#include <image_transport/image_transport.h>
#include <camera_info_manager/camera_info_manager.h>
#include <sstream>

class UsbCamNode
{
public:
  // private ROS node handle
  ros::NodeHandle node_;

  // shared image message
  sensor_msgs::Image img_;
  usb_cam_camera_image_t *camera_image_;
  image_transport::CameraPublisher image_pub_;

  // parameters
  std::string video_device_name_, io_method_name_, pixel_format_name_, camera_name_, camera_info_url_;
  int image_width_, image_height_, framerate_, exposure_, brightness_, contrast_, saturation_, sharpness_, focus_,
      white_balance_;
  bool autofocus_, autoexposure_, auto_white_balance_;
  boost::shared_ptr<camera_info_manager::CameraInfoManager> cinfo_;

  UsbCamNode() :
      node_("~")
  {
    // advertise the main image topic
    image_transport::ImageTransport it(node_);
    image_pub_ = it.advertiseCamera("image_raw", 1);

    // grab the parameters
    node_.param("video_device", video_device_name_, std::string("/dev/video0"));
    node_.param("brightness", brightness_, 128); //0-255
    node_.param("contrast", contrast_, 32); //0-255
    node_.param("saturation", saturation_, 32); //0-255
    node_.param("sharpness", sharpness_, 22); //0-255
    // possible values: mmap, read, userptr
    node_.param("io_method", io_method_name_, std::string("mmap"));
    node_.param("image_width", image_width_, 640);
    node_.param("image_height", image_height_, 480);
    node_.param("framerate", framerate_, 30);
    // possible values: yuyv, uyvy, mjpeg, yuvmono10, rgb24
    node_.param("pixel_format", pixel_format_name_, std::string("mjpeg"));
    // enable/disable autofocus
    node_.param("autofocus", autofocus_, false);
    node_.param("focus", focus_, 51);
    // enable/disable autoexposure
    node_.param("autoexposure", autoexposure_, true);
    node_.param("exposure", exposure_, 100);
    // enable/disable auto white balance temperature
    node_.param("auto_white_balance", auto_white_balance_, true);
    node_.param("white_balance", white_balance_, 4000);

    // load the camera info
    node_.param("camera_frame_id", img_.header.frame_id, std::string("head_camera"));
    node_.param("camera_name", camera_name_, std::string("head_camera"));
    node_.param("camera_info_url", camera_info_url_, std::string(""));
    cinfo_.reset(new camera_info_manager::CameraInfoManager(node_, camera_name_, camera_info_url_));

    ROS_INFO("Starting '%s' (%s) at %dx%d via %s (%s) at %i FPS", camera_name_.c_str(), video_device_name_.c_str(),
             image_width_, image_height_, io_method_name_.c_str(), pixel_format_name_.c_str(), framerate_);

    // set the IO method
    usb_cam_io_method io_method;
    if (io_method_name_ == "mmap")
      io_method = IO_METHOD_MMAP;
    else if (io_method_name_ == "read")
      io_method = IO_METHOD_READ;
    else if (io_method_name_ == "userptr")
      io_method = IO_METHOD_USERPTR;
    else
    {
      ROS_FATAL("Unknown IO method '%s'", io_method_name_.c_str());
      node_.shutdown();
      return;
    }

    // set the pixel format
    usb_cam_pixel_format pixel_format;
    if (pixel_format_name_ == "yuyv")
      pixel_format = PIXEL_FORMAT_YUYV;
    else if (pixel_format_name_ == "uyvy")
      pixel_format = PIXEL_FORMAT_UYVY;
    else if (pixel_format_name_ == "mjpeg")
      pixel_format = PIXEL_FORMAT_MJPEG;
    else if (pixel_format_name_ == "yuvmono10")
      pixel_format = PIXEL_FORMAT_YUVMONO10;
    else if (pixel_format_name_ == "rgb24")
      pixel_format = PIXEL_FORMAT_RGB24;
    else
    {
      ROS_FATAL("Unknown pixel format '%s'", pixel_format_name_.c_str());
      node_.shutdown();
      return;
    }

    // start the camera
    camera_image_ = usb_cam_camera_start(video_device_name_.c_str(), io_method, pixel_format, image_width_,
                                         image_height_, framerate_);

    // set camera parameters
    std::stringstream paramstream;
    paramstream << "brightness=" << brightness_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());
    paramstream.str("");
    paramstream << "contrast=" << contrast_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());
    paramstream.str("");
    paramstream << "saturation=" << saturation_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());
    paramstream.str("");
    paramstream << "sharpness=" << sharpness_;
    this->set_v4l_parameters(video_device_name_, paramstream.str());

    // check auto white balance
    if (auto_white_balance_)
    {
      this->set_v4l_parameters(video_device_name_, "white_balance_temperature_auto=1");
    }
    else
    {
      this->set_v4l_parameters(video_device_name_, "white_balance_temperature_auto=0");
      std::stringstream ss;
      ss << "white_balance_temperature=" << white_balance_;
      this->set_v4l_parameters(video_device_name_, ss.str());
    }

    // check auto exposure
    if (!autoexposure_)
    {
      // turn down exposure control (from max of 3)
      this->set_v4l_parameters(video_device_name_, "exposure_auto=1");
      // change the exposure level
      std::stringstream ss;
      ss << "exposure_absolute=" << exposure_;
      this->set_v4l_parameters(video_device_name_, ss.str());
    }

    // check auto focus
    if (autofocus_)
    {
      usb_cam_camera_set_auto_focus(1);
      this->set_v4l_parameters(video_device_name_, "focus_auto=1");
    }
    else
    {
      this->set_v4l_parameters(video_device_name_, "focus_auto=0");
      std::stringstream ss;
      ss << "focus_absolute=" << focus_;
      this->set_v4l_parameters(video_device_name_, ss.str());
    }
  }

  virtual ~UsbCamNode()
  {
    usb_cam_camera_shutdown();
  }

  bool take_and_send_image()
  {
    // grab the image
    usb_cam_camera_grab_image(camera_image_);
    // fill the info
    fillImage(img_, "rgb8", camera_image_->height, camera_image_->width, 3 * camera_image_->width,
              camera_image_->image);
    // stamp the image
    img_.header.stamp = ros::Time::now();

    // grab the camera info
    sensor_msgs::CameraInfoPtr ci(new sensor_msgs::CameraInfo(cinfo_->getCameraInfo()));
    ci->header.frame_id = img_.header.frame_id;
    ci->header.stamp = img_.header.stamp;

    // publish the image
    image_pub_.publish(img_, *ci);

    return true;
  }

  bool spin()
  {
    ros::Rate loop_rate(this->framerate_);
    while (node_.ok())
    {
      if (!take_and_send_image())
        ROS_WARN("USB camera did not respond in time.");
      ros::spinOnce();
      loop_rate.sleep();
    }
    return true;
  }

private:

  /**
   * Set video device parameters via calls to v4l-utils.
   *
   * @param dev The device (e.g., "/dev/video0")
   * @param param The full parameter to set (e.g., "focus_auto=1")
   */
  void set_v4l_parameters(std::string dev, std::string param)
  {
    // build the command
    std::stringstream ss;
    ss << "v4l2-ctl --device=" << dev << " -c " << param << " 2>&1";
    std::string cmd = ss.str();

    // capture the output
    std::string output;
    int buffer_size = 256;
    char buffer[buffer_size];
    FILE *stream = popen(cmd.c_str(), "r");
    if (stream)
    {
      while (!feof(stream))
        if (fgets(buffer, buffer_size, stream) != NULL)
          output.append(buffer);
      pclose(stream);
      // any output should be an error
      if (output.length() > 0)
        ROS_WARN("%s", output.c_str());
    }
    else
      ROS_WARN("usb_cam_node could not run '%s'", cmd.c_str());
  }
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "usb_cam");
  UsbCamNode a;
  a.spin();
  return EXIT_SUCCESS;
}
<|endoftext|>