<commit_before>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the Campcaster project.
    http://campcaster.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    Campcaster is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Campcaster 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 Campcaster; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author$
    Version  : $Revision$
    Location : $URL$

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#define DEBUG_PREFIX "GstreamerPlayer"
#include "LiveSupport/Core/Debug.h"

#include "LiveSupport/Core/TimeConversion.h"

#include "GstreamerPlayer.h"

using namespace boost::posix_time;
using namespace LiveSupport::Core;
using namespace LiveSupport::PlaylistExecutor;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/**
 *  The name of the config element for this class
 */
const std::string GstreamerPlayer::configElementNameStr = "gstreamerPlayer";

/**
 *  The name of the audio device attribute.
 */
static const std::string    audioDeviceName = "audioDevice";

/* ===============================================  local function prototypes */

/* =============================================================  module code */

static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data)
{

    GstreamerPlayer* const player = (GstreamerPlayer*) data;

    switch (GST_MESSAGE_TYPE (message)) {
        case GST_MESSAGE_EOS:
            if(player->playNextSmil()){
                break;
            }
            player->close();
            // Important: We *must* use an idle function call here, so that the signal handler returns
            // before fireOnStopEvent() is executed.
            g_idle_add(GstreamerPlayer::fireOnStopEvent, data);
            break;
        case GST_MESSAGE_ERROR:
            // We make sure that we don't send multiple error messages in a row to the GUI
            if (!player->m_errorWasRaised) {
                GError *gerror;
                gchar *debug;
                gst_message_parse_error (message, &gerror, &debug);
                player->m_errorMessage.reset(new const Glib::ustring(gerror->message));
                player->m_errorWasRaised = true;

                std::cerr << "gstreamer error: " << gerror->message << std::endl;
                g_error_free (gerror);
                g_free (debug);
                // Important: We *must* use an idle function call here, so that the signal handler returns
                // before fireOnStopEvent() is executed.
                g_idle_add(GstreamerPlayer::fireOnStopEvent, data);
            }
            break;
    }
}

/*------------------------------------------------------------------------------
 *  Configure the Audio Player.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: configure(const xmlpp::Element   &  element)
                                                throw (std::invalid_argument,
                                                       std::logic_error)
{
    DEBUG_FUNC_INFO

    if (element.get_name() != configElementNameStr) {
        std::string eMsg = "Bad configuration element ";
        eMsg += element.get_name();
        throw std::invalid_argument(eMsg);
    }

    const xmlpp::Attribute    * attribute = 0;

    if ((attribute = element.get_attribute(audioDeviceName))) {
        m_audioDevice = attribute->get_value();
    }
}

/*------------------------------------------------------------------------------
 *  Initialize the Audio Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: initialize(void)                 throw (std::exception)
{
    DEBUG_FUNC_INFO

    if (m_initialized) {
        return;
    }

    // initialize the gstreamer library
    if (!gst_init_check(0, 0, 0)) {
        throw std::runtime_error("couldn't initialize the gstreamer library");
    }

    m_playContext = new GstreamerPlayContext();

    m_playContext->setParentData(this);

    // set up other variables
    m_initialized = true;
}

/*------------------------------------------------------------------------------
 *  De-initialize the Gstreamer Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: deInitialize(void)                       throw ()
{
    DEBUG_FUNC_INFO

    if (m_initialized) {
        m_playContext->closeContext();
        delete m_playContext;
        m_playContext = NULL;
        m_initialized = false;
    }
}

/*------------------------------------------------------------------------------
 *  Attach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: attachListener(AudioPlayerEventListener*     eventListener)
                                                                    throw ()
{
    m_listeners.push_back(eventListener);
}

/*------------------------------------------------------------------------------
 *  Detach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: detachListener(AudioPlayerEventListener*     eventListener)
                                                throw (std::invalid_argument)
{
    ListenerVector::iterator    it  = m_listeners.begin();
    ListenerVector::iterator    end = m_listeners.end();

    while (it != end) {
        if (*it == eventListener) {
            m_listeners.erase(it);
            return;
        }
        ++it;
    }

    throw std::invalid_argument("supplied event listener not found");
}

/*------------------------------------------------------------------------------
 *  Send the onStop event to all attached listeners.
 *----------------------------------------------------------------------------*/
gboolean
GstreamerPlayer :: fireOnStopEvent(gpointer self)                       throw ()
{
    DEBUG_BLOCK

    GstreamerPlayer* const player = (GstreamerPlayer*) self;

    ListenerVector::iterator    it  = player->m_listeners.begin();
    ListenerVector::iterator    end = player->m_listeners.end();
    while (it != end) {
        (*it)->onStop(player->m_errorMessage);
        ++it;
    }

    player->m_errorMessage.reset();

    // false == Don't call this idle function again
    return false;
}

/*------------------------------------------------------------------------------
 * Preload a file, to speed up the subsequent open() call.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: preload(const std::string   fileUrl)
                                                throw (std::invalid_argument,
                                                       std::runtime_error)
{
    DEBUG_BLOCK
    //According to the Gstreamer documentation, stream buffering happens
    //automatically when the pipeline is set to GST_STATE_PAUSED.
    //As this state is now set automatically in the open function,
    //we no longer have a need for preloading.
}

/*------------------------------------------------------------------------------
 *  Specify which file to play
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: open(const std::string   fileUri)
                                                throw (std::invalid_argument,
                                                       std::runtime_error)
{
    DEBUG_BLOCK

    if (isOpen()) {
        close();
    }

    m_smilOffset = 0L;

    debug() << "Opening URL: " << fileUri << endl;
    debug() << "Timestamp: " << *TimeConversion::now() << endl;

    m_errorMessage.reset();
    m_errorWasRaised = false;

    m_playContext->setAudioDevice(m_audioDevice);
    if (fileUri.find(std::string(".smil")) != std::string::npos) {
        m_smilHandler = new SmilHandler();
        m_smilHandler->openSmilFile(fileUri.c_str());
        AudioDescription *audioDescription = m_smilHandler->getNext();
        m_open=m_playContext->openSource(audioDescription);
    }else{
        m_open=m_playContext->openSource(fileUri.c_str());
    }

    if(!m_open){
      m_errorMessage.reset(new const Glib::ustring("GstreamerPlayer :: open failed! Please consult console output for details."));
      m_errorWasRaised = true;
      fireOnStopEvent(this);
    }
}

bool
GstreamerPlayer :: playNextSmil(void)                                    throw ()
{
    DEBUG_BLOCK
    m_currentPlayLength = m_playContext->getPosition();//this gets the length of the stream that just completed
    m_playContext->closeContext();
    if(m_smilHandler == NULL){
        return false;
    }
    AudioDescription *audioDescription = m_smilHandler->getNext();
    if(audioDescription == NULL){//no more audio entries to play
        delete m_smilHandler;
        m_smilHandler = NULL;
        return false;
    }
    if(!m_playContext->openSource(audioDescription)){
        return false;
    }
    m_smilOffset += m_currentPlayLength;
    m_playContext->playContext();
}

/*------------------------------------------------------------------------------
 *  Tell if we've been opened.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isOpen(void)                                 throw ()
{
    return m_open;
}

/*------------------------------------------------------------------------------
 *  Get the length of the current audio clip.
 *  Currently not used by the Studio, but may be used later on.
 *----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref
GstreamerPlayer :: getPlaylength(void)              throw (std::logic_error)
{
    DEBUG_BLOCK

    if (!isOpen()) {
        throw std::logic_error("player not open");
    }

    Ptr<time_duration>::Ref   length;

    gint64 ns = m_playContext->getPlayLength();

    length.reset(new time_duration(microsec(ns / 1000LL)));

    debug() << length << endl;
    return length;
}

/*------------------------------------------------------------------------------
 *  Get the current position of the current audio clip.
 *----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref
GstreamerPlayer :: getPosition(void)                throw (std::logic_error)
{
    Ptr<time_duration>::Ref   length;

    if (!isOpen()) {
        throw std::logic_error("player not open");
    }

    gint64                    ns = m_playContext->getPosition();

    length.reset(new time_duration(microseconds((m_smilOffset + ns) / 1000LL)));

    return length;
}

/*------------------------------------------------------------------------------
 *  Start playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: start(void)                      throw (std::logic_error)
{
    DEBUG_BLOCK

    if (!isOpen()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (!isPlaying()) {
        m_playContext->playContext();
    }else{
        error() << "Already playing!" << endl;
    }
}

/*------------------------------------------------------------------------------
 *  Pause the player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: pause(void)                      throw (std::logic_error)
{
    DEBUG_BLOCK

    if (isPlaying()) {
        m_playContext->pauseContext();
    }
}

/*------------------------------------------------------------------------------
 *  Tell if we're playing
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isPlaying(void)                  throw ()
{
    return m_playContext->isPlaying();
}

/*------------------------------------------------------------------------------
 *  Stop playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: stop(void)                       throw (std::logic_error)
{
    DEBUG_BLOCK

    if (!isOpen()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (isPlaying()) {
        m_playContext->stopContext();
    }
}

/*------------------------------------------------------------------------------
 *  Close the currently opened audio file.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: close(void)                       throw (std::logic_error)
{
    DEBUG_BLOCK

    m_playContext->stopContext();
    m_playContext->closeContext();
    if(m_smilHandler != NULL){
        delete m_smilHandler;
        m_smilHandler = NULL;
    }

    m_open            = false;
}

/*------------------------------------------------------------------------------
 *  Get the volume of the player. *Unimplemented*: Feature is currently not used.
 *----------------------------------------------------------------------------*/
unsigned int
GstreamerPlayer :: getVolume(void)                                  throw ()
{
    return 0;
}

/*------------------------------------------------------------------------------
 *  Set the volume of the player. *Unimplemented*: Feature is currently not used.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: setVolume(unsigned int   volume)                 throw ()
{}

/*------------------------------------------------------------------------------
 *  Set the audio device.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: setAudioDevice(const std::string &deviceName)
                                                                throw ()
{
    DEBUG_BLOCK

    debug() << "Using device: " << deviceName << endl;

    if (deviceName.size() == 0) {
        return false;
    }

    m_playContext->setAudioDevice(deviceName);

    return true;
}

<commit_msg>Fixing ticket #2292<commit_after>/*------------------------------------------------------------------------------

    Copyright (c) 2004 Media Development Loan Fund

    This file is part of the Campcaster project.
    http://campcaster.campware.org/
    To report bugs, send an e-mail to bugs@campware.org

    Campcaster is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Campcaster 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 Campcaster; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Author   : $Author$
    Version  : $Revision$
    Location : $URL$

------------------------------------------------------------------------------*/

/* ============================================================ include files */

#ifdef HAVE_CONFIG_H
#include "configure.h"
#endif

#define DEBUG_PREFIX "GstreamerPlayer"
#include "LiveSupport/Core/Debug.h"

#include "LiveSupport/Core/TimeConversion.h"

#include "GstreamerPlayer.h"

using namespace boost::posix_time;
using namespace LiveSupport::Core;
using namespace LiveSupport::PlaylistExecutor;

/* ===================================================  local data structures */

/* ================================================  local constants & macros */

/**
 *  The name of the config element for this class
 */
const std::string GstreamerPlayer::configElementNameStr = "gstreamerPlayer";

/**
 *  The name of the audio device attribute.
 */
static const std::string    audioDeviceName = "audioDevice";

/* ===============================================  local function prototypes */

/* =============================================================  module code */

static gboolean my_bus_callback (GstBus *bus, GstMessage *message, gpointer data)
{

    GstreamerPlayer* const player = (GstreamerPlayer*) data;

    switch (GST_MESSAGE_TYPE (message)) {
        case GST_MESSAGE_EOS:
            if(player->playNextSmil()){
                break;
            }
            player->close();
            // Important: We *must* use an idle function call here, so that the signal handler returns
            // before fireOnStopEvent() is executed.
            g_idle_add(GstreamerPlayer::fireOnStopEvent, data);
            break;
        case GST_MESSAGE_ERROR:
            // We make sure that we don't send multiple error messages in a row to the GUI
            if (!player->m_errorWasRaised) {
                GError *gerror;
                gchar *debug;
                gst_message_parse_error (message, &gerror, &debug);
                player->m_errorMessage.reset(new const Glib::ustring(gerror->message));
                player->m_errorWasRaised = true;

                std::cerr << "gstreamer error: " << gerror->message << std::endl;
                g_error_free (gerror);
                g_free (debug);
                // Important: We *must* use an idle function call here, so that the signal handler returns
                // before fireOnStopEvent() is executed.
                g_idle_add(GstreamerPlayer::fireOnStopEvent, data);
            }
            break;
    }
}

/*------------------------------------------------------------------------------
 *  Configure the Audio Player.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: configure(const xmlpp::Element   &  element)
                                                throw (std::invalid_argument,
                                                       std::logic_error)
{
    DEBUG_FUNC_INFO

    if (element.get_name() != configElementNameStr) {
        std::string eMsg = "Bad configuration element ";
        eMsg += element.get_name();
        throw std::invalid_argument(eMsg);
    }

    const xmlpp::Attribute    * attribute = 0;

    if ((attribute = element.get_attribute(audioDeviceName))) {
        m_audioDevice = attribute->get_value();
    }
}

/*------------------------------------------------------------------------------
 *  Initialize the Audio Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: initialize(void)                 throw (std::exception)
{
    DEBUG_FUNC_INFO

    if (m_initialized) {
        return;
    }

    // initialize the gstreamer library
    if (!gst_init_check(0, 0, 0)) {
        throw std::runtime_error("couldn't initialize the gstreamer library");
    }

    m_playContext = new GstreamerPlayContext();

    m_playContext->setParentData(this);

    // set up other variables
    m_initialized = true;
}

/*------------------------------------------------------------------------------
 *  De-initialize the Gstreamer Player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: deInitialize(void)                       throw ()
{
    DEBUG_FUNC_INFO

    if (m_initialized) {
        m_playContext->closeContext();
        delete m_playContext;
        m_playContext = NULL;
        m_initialized = false;
    }
}

/*------------------------------------------------------------------------------
 *  Attach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: attachListener(AudioPlayerEventListener*     eventListener)
                                                                    throw ()
{
    m_listeners.push_back(eventListener);
}

/*------------------------------------------------------------------------------
 *  Detach an event listener.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: detachListener(AudioPlayerEventListener*     eventListener)
                                                throw (std::invalid_argument)
{
    ListenerVector::iterator    it  = m_listeners.begin();
    ListenerVector::iterator    end = m_listeners.end();

    while (it != end) {
        if (*it == eventListener) {
            m_listeners.erase(it);
            return;
        }
        ++it;
    }

    throw std::invalid_argument("supplied event listener not found");
}

/*------------------------------------------------------------------------------
 *  Send the onStop event to all attached listeners.
 *----------------------------------------------------------------------------*/
gboolean
GstreamerPlayer :: fireOnStopEvent(gpointer self)                       throw ()
{
    DEBUG_BLOCK

    GstreamerPlayer* const player = (GstreamerPlayer*) self;

    ListenerVector::iterator    it  = player->m_listeners.begin();
    ListenerVector::iterator    end = player->m_listeners.end();
    while (it != end) {
        (*it)->onStop(player->m_errorMessage);
        ++it;
    }

    player->m_errorMessage.reset();

    // false == Don't call this idle function again
    return false;
}

/*------------------------------------------------------------------------------
 * Preload a file, to speed up the subsequent open() call.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: preload(const std::string   fileUrl)
                                                throw (std::invalid_argument,
                                                       std::runtime_error)
{
    DEBUG_BLOCK
    //According to the Gstreamer documentation, stream buffering happens
    //automatically when the pipeline is set to GST_STATE_PAUSED.
    //As this state is now set automatically in the open function,
    //we no longer have a need for preloading.
}

/*------------------------------------------------------------------------------
 *  Specify which file to play
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: open(const std::string   fileUri)
                                                throw (std::invalid_argument,
                                                       std::runtime_error)
{
    DEBUG_BLOCK

    if (isOpen()) {
        close();
    }

    m_smilOffset = 0L;

    debug() << "Opening URL: " << fileUri << endl;
    debug() << "Timestamp: " << *TimeConversion::now() << endl;

    m_errorMessage.reset();
    m_errorWasRaised = false;

    m_playContext->setAudioDevice(m_audioDevice);
    if (fileUri.find(std::string(".smil")) != std::string::npos) {
        m_smilHandler = new SmilHandler();
        m_smilHandler->openSmilFile(fileUri.c_str());
        AudioDescription *audioDescription = m_smilHandler->getNext();
        m_open=m_playContext->openSource(audioDescription);
    }else{
        m_open=m_playContext->openSource(fileUri.c_str());
    }

    if(!m_open){
      m_errorMessage.reset(new const Glib::ustring("GstreamerPlayer :: open failed! Please consult console output for details."));
      m_errorWasRaised = true;
      fireOnStopEvent(this);
    }
}

bool
GstreamerPlayer :: playNextSmil(void)                                    throw ()
{
    DEBUG_BLOCK
    m_currentPlayLength = m_playContext->getPosition();//this gets the length of the stream that just completed
    m_playContext->closeContext();
    if(m_smilHandler == NULL){
        return false;
    }
    AudioDescription *audioDescription = m_smilHandler->getNext();
    if(audioDescription == NULL){//no more audio entries to play
        delete m_smilHandler;
        m_smilHandler = NULL;
        return false;
    }
    if(!m_playContext->openSource(audioDescription)){
        return false;
    }
    m_smilOffset += m_currentPlayLength;
    m_playContext->playContext();
}

/*------------------------------------------------------------------------------
 *  Tell if we've been opened.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isOpen(void)                                 throw ()
{
    return m_open;
}

/*------------------------------------------------------------------------------
 *  Get the length of the current audio clip.
 *  Currently not used by the Studio, but may be used later on.
 *----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref
GstreamerPlayer :: getPlaylength(void)              throw (std::logic_error)
{
    DEBUG_BLOCK

    if (!isOpen()) {
        throw std::logic_error("player not open");
    }

    Ptr<time_duration>::Ref   length;

    gint64 ns = m_playContext->getPlayLength();

    length.reset(new time_duration(microsec(ns / 1000LL)));

    debug() << "playlength is: " << *length << endl;
    return length;
}

/*------------------------------------------------------------------------------
 *  Get the current position of the current audio clip.
 *----------------------------------------------------------------------------*/
Ptr<time_duration>::Ref
GstreamerPlayer :: getPosition(void)                throw (std::logic_error)
{
    Ptr<time_duration>::Ref   length;

    if (!isOpen()) {
        throw std::logic_error("player not open");
    }

    gint64                    ns = m_playContext->getPosition();

    length.reset(new time_duration(microseconds((m_smilOffset + ns) / 1000LL)));

    return length;
}

/*------------------------------------------------------------------------------
 *  Start playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: start(void)                      throw (std::logic_error)
{
    DEBUG_BLOCK

    if (!isOpen()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (!isPlaying()) {
        m_playContext->playContext();
    }else{
        error() << "Already playing!" << endl;
    }
}

/*------------------------------------------------------------------------------
 *  Pause the player
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: pause(void)                      throw (std::logic_error)
{
    DEBUG_BLOCK

    if (isPlaying()) {
        m_playContext->pauseContext();
    }
}

/*------------------------------------------------------------------------------
 *  Tell if we're playing
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: isPlaying(void)                  throw ()
{
    return m_playContext->isPlaying();
}

/*------------------------------------------------------------------------------
 *  Stop playing
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: stop(void)                       throw (std::logic_error)
{
    DEBUG_BLOCK

    if (!isOpen()) {
        throw std::logic_error("GstreamerPlayer not opened yet");
    }

    if (isPlaying()) {
        m_playContext->stopContext();
    }
}

/*------------------------------------------------------------------------------
 *  Close the currently opened audio file.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: close(void)                       throw (std::logic_error)
{
    DEBUG_BLOCK

    m_playContext->stopContext();
    m_playContext->closeContext();
    if(m_smilHandler != NULL){
        delete m_smilHandler;
        m_smilHandler = NULL;
    }

    m_open            = false;
}

/*------------------------------------------------------------------------------
 *  Get the volume of the player. *Unimplemented*: Feature is currently not used.
 *----------------------------------------------------------------------------*/
unsigned int
GstreamerPlayer :: getVolume(void)                                  throw ()
{
    return 0;
}

/*------------------------------------------------------------------------------
 *  Set the volume of the player. *Unimplemented*: Feature is currently not used.
 *----------------------------------------------------------------------------*/
void
GstreamerPlayer :: setVolume(unsigned int   volume)                 throw ()
{}

/*------------------------------------------------------------------------------
 *  Set the audio device.
 *----------------------------------------------------------------------------*/
bool
GstreamerPlayer :: setAudioDevice(const std::string &deviceName)
                                                                throw ()
{
    DEBUG_BLOCK

    debug() << "Using device: " << deviceName << endl;

    if (deviceName.size() == 0) {
        return false;
    }

    m_playContext->setAudioDevice(deviceName);

    return true;
}

<|endoftext|>


<commit_before>// bslmt_semaphoreimpl_darwin.cpp                                     -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bslmt_semaphoreimpl_darwin.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bslmt_semaphoreimpl_darwin_cpp,"$Id$ $CSID$")

#ifdef BSLS_PLATFORM_OS_DARWIN

#include <bslmt_lockguard.h>    // for testing only
#include <bslmt_mutex.h>        // for testing only
#include <bslmt_threadutil.h>   // for testing only

#include <bsl_string.h>
#include <bsl_sstream.h>
#include <bsl_iomanip.h>
#include <bsl_ios.h>
#include <bsl_c_errno.h>
#include <bsls_types.h>

#include <stdio.h>         // 'snprintf'
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>      // needed before sys/posix_sem.h to define
                           // 'itimerval'
#include <sys/posix_sem.h> // 'PSEMNAMLEN'

#ifndef SEM_NAME_LEN
#define SEM_NAME_LEN PSEMNAMLEN
#endif

namespace BloombergLP {

              // ----------------------------------------------
              // class SemaphoreImpl<Platform::DarwinSemaphore>
              // ----------------------------------------------

const char *
bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::s_semaphorePrefix
    = "bslmt_semaphore_";

namespace {

void
makeUniqueName(char *buffer, const char *prefix, bsls::Types::UintPtr suffix)
    // Create a sufficiently unique name for a semaphore object.  Note that the
    // name of the semaphore shouldn't exceed SEM_NAME_LEN characters (31).
{
    snprintf(buffer, SEM_NAME_LEN, "%s%04x_%04x",
                                   prefix,
                                   (getpid() & 0xffff),
                                   (suffix & 0xffff));
}

}  // close unnamed namespace

// CREATORS
bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::SemaphoreImpl(
                                                                     int count)
{
    char semaphoreName[SEM_NAME_LEN + 1];

    makeUniqueName(semaphoreName,
                   s_semaphorePrefix,
                   reinterpret_cast<bsls::Types::UintPtr>(this));

    do {
        // create a named semaphore with exclusive access
        d_sem_p = ::sem_open(semaphoreName,
                             O_CREAT | O_EXCL,
                             S_IRUSR | S_IWUSR,
                             count);
    } while (d_sem_p == SEM_FAILED && (errno == EEXIST || errno == EINTR));

    BSLS_ASSERT(d_sem_p != SEM_FAILED);

    // At this point the current thread is the sole owner of the semaphore with
    // this name.  No other thread can create a semaphore with the same name
    // until we disassociate the name from the semaphore handle.  Note that
    // even though the name is unlinked from the semaphore, we still try to use
    // sufficiently unique names because if the process is killed before it
    // unlinks the name, no other process can create a semaphore with that
    // name.
    int result = ::sem_unlink(semaphoreName);

    (void) result;
    BSLS_ASSERT(result == 0);
}

// MANIPULATORS
void bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::post(int number)
{
    for (int i = 0; i < number; i++) {
        post();
    }
}

void
bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::wait()
{
    sem_t * sem_p = d_sem_p;
    int result = 0;

    do {
        result = ::sem_wait(sem_p);
    } while (result != 0 && errno == EINTR);

    BSLS_ASSERT(result == 0);
}

}  // close enterprise namespace

#endif  // BSLS_PLATFORM_OS_DARWIN

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<commit_msg>add cast to suppress warning<commit_after>// bslmt_semaphoreimpl_darwin.cpp                                     -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bslmt_semaphoreimpl_darwin.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bslmt_semaphoreimpl_darwin_cpp,"$Id$ $CSID$")

#ifdef BSLS_PLATFORM_OS_DARWIN

#include <bslmt_lockguard.h>    // for testing only
#include <bslmt_mutex.h>        // for testing only
#include <bslmt_threadutil.h>   // for testing only

#include <bsl_string.h>
#include <bsl_sstream.h>
#include <bsl_iomanip.h>
#include <bsl_ios.h>
#include <bsl_c_errno.h>
#include <bsls_types.h>

#include <stdio.h>         // 'snprintf'
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>      // needed before sys/posix_sem.h to define
                           // 'itimerval'
#include <sys/posix_sem.h> // 'PSEMNAMLEN'

#ifndef SEM_NAME_LEN
#define SEM_NAME_LEN PSEMNAMLEN
#endif

namespace BloombergLP {

              // ----------------------------------------------
              // class SemaphoreImpl<Platform::DarwinSemaphore>
              // ----------------------------------------------

const char *
bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::s_semaphorePrefix
    = "bslmt_semaphore_";

namespace {

void
makeUniqueName(char *buffer, const char *prefix, bsls::Types::UintPtr suffix)
    // Create a sufficiently unique name for a semaphore object.  Note that the
    // name of the semaphore shouldn't exceed SEM_NAME_LEN characters (31).
{
    snprintf(buffer, SEM_NAME_LEN, "%s%04x_%04x",
                                   prefix,
                                   (getpid() & 0xffff),
                                   static_cast<unsigned>(suffix & 0xffff));
}

}  // close unnamed namespace

// CREATORS
bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::SemaphoreImpl(
                                                                     int count)
{
    char semaphoreName[SEM_NAME_LEN + 1];

    makeUniqueName(semaphoreName,
                   s_semaphorePrefix,
                   reinterpret_cast<bsls::Types::UintPtr>(this));

    do {
        // create a named semaphore with exclusive access
        d_sem_p = ::sem_open(semaphoreName,
                             O_CREAT | O_EXCL,
                             S_IRUSR | S_IWUSR,
                             count);
    } while (d_sem_p == SEM_FAILED && (errno == EEXIST || errno == EINTR));

    BSLS_ASSERT(d_sem_p != SEM_FAILED);

    // At this point the current thread is the sole owner of the semaphore with
    // this name.  No other thread can create a semaphore with the same name
    // until we disassociate the name from the semaphore handle.  Note that
    // even though the name is unlinked from the semaphore, we still try to use
    // sufficiently unique names because if the process is killed before it
    // unlinks the name, no other process can create a semaphore with that
    // name.
    int result = ::sem_unlink(semaphoreName);

    (void) result;
    BSLS_ASSERT(result == 0);
}

// MANIPULATORS
void bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::post(int number)
{
    for (int i = 0; i < number; i++) {
        post();
    }
}

void
bslmt::SemaphoreImpl<bslmt::Platform::DarwinSemaphore>::wait()
{
    sem_t * sem_p = d_sem_p;
    int result = 0;

    do {
        result = ::sem_wait(sem_p);
    } while (result != 0 && errno == EINTR);

    BSLS_ASSERT(result == 0);
}

}  // close enterprise namespace

#endif  // BSLS_PLATFORM_OS_DARWIN

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<|endoftext|>


<commit_before>/// This file contains the implementation of VNS
#include "header/vns-priv.hpp"

using namespace std;

namespace pcp {
	Solution bestSolution;
	Solution origSolution;

	bool checkValid(Solution* s);

	/// Some constants
	const int NUM_VNS = 1;
	const int SHAKE_START = 1;

	/// Implementation of VNS, see vns.hpp
	Solution vnsRun(Solution& best, Solution& orig, int unsuccessfulShake, int shakeStart, int shakeIncrement, int maxTime) {

		/// Backup the starting solutions
		bestSolution = new Solution(best);
		origSolution = new Solution(orig);

		cout<<"Best solution uses "<<bestSolution.colorsUsed<<" colors"<<endl;
		cout<<"Full solution uses "<<origSolution.colorsUsed<<" colors"<<endl;

		/// Define the neighborhoods to use
		VNS_Unit **neighbors = new VNS_Unit*[NUM_VNS];
		changeColor *ts = new changeColor;
		neighbors[0] = ts;

		time_t startTime = time(NULL);
		int no_imp_runs = 0;
		int curNeighbor = 0;
		int shakeSteps = shakeStart - shakeIncrement;
		Solution *toImprove = new Solution(&best);
		Solution *curBest = &best;

		/// Run as long as shaking still produces usefull solution
		while (true) {

			/// Run all possible neighborhood
			while (curNeighbor < NUM_VNS) {

				/// Select the new neighborhood
				VNS_Unit *neigh = neighbors[curNeighbor];
				cout<<"Running: "<< neigh->name() <<endl;

				/// Compute the minimum for this neighborhood
				Solution *improved = neigh->findLocalMin(best, orig);
				cout<<"Valid solution: "<<((checkValid(improved)) ? "true" : "false");
				cout<<endl;
				/// Replace the existing solution with the new solution if it is an
				/// improvement
				if (improved->colorsUsed < toImprove->colorsUsed) {
					delete toImprove;
					toImprove = improved;

					cout<<"Improvement found with "<<neigh->name()<<endl;

					/// Restart neighborhoods
					curNeighbor = curNeighbor == 0 ? 1 : 0;
				}

				/// Step to next neighborhood, no improvement found
				else {
					cout<<"No improvement found"<<endl;
					delete improved;
					curNeighbor++;
					cout<<"Test next neighborhood"<<endl;
				}
			} // end while neighborhood

			/// Local minimum of neighborhoods is better than current best
			/// solution
			if (toImprove->colorsUsed < best.colorsUsed) {
				cout<<"Improvement to global best solution found"<<endl;
				best = toImprove;
				toImprove = new Solution(curBest);
				no_imp_runs = 0;
				shakeSteps = shakeStart - shakeIncrement;
			}
			/// Reset local best solution to global best Solution
			else {
				toImprove = curBest;
				no_imp_runs++;

				/// Stopping condition, quit VNS
				if (no_imp_runs > unsuccessfulShake) {
					break;
				}
			}

			int shakeNeighbor = rand() % NUM_VNS;

			VNS_Unit *shaker = neighbors[shakeNeighbor];
			toImprove = shaker->shuffleSolution(*toImprove, orig, (shakeSteps += shakeIncrement));

			/// No time left, abort main loop
			if (startTime + maxTime < time(NULL)) {
				cout<<"Time's up"<<endl;
				break;
			}
		}

		return new Solution(curBest);
	}

	bool checkValid(Solution* s) {
	pair<VertexIter, VertexIter> vIter;
	int parts[s->numParts];
	typedef boost::graph_traits<Graph>::adjacency_iterator AdjIter;
	VertexPart_Map vParts = get(boost::vertex_index1_t(), *s->g);
	bool valid = true;

	for (int i = 0; i < s->numParts; i++) {
		parts[i] = 0;
	}

	for (vIter = vertices(*s->g); vIter.first != vIter.second; vIter.first++) {
		parts[vParts[*vIter.first]] = 1;

		pair<AdjIter, AdjIter> aIter;
		for (aIter = adjacent_vertices(*vIter.first, *s->g);
			  aIter.first != aIter.second; aIter.first++) {

			if (s->partition[vParts[*aIter.first]] ==
				 s->partition[vParts[*vIter.first]]) {

				valid = false;
				cerr<<"Solution is invalid"<<endl;
				cerr<<"Adjacent vertices "<<*aIter.first<<" and "<<*vIter.first;
				cerr<<" have same color "<<s->partition[vParts[*vIter.first]];
				cerr<<endl;
			}
		}
	}

	for (int i = 0; i < s->numParts; i++) {
		if (parts[i] == 0) {
			valid = false;
			cerr<<"Solution is invalid"<<endl;
			cerr<<"partition "<<i<<" seems to be missing"<<endl;
		}
	}

	return valid;
}
}

<commit_msg>Fixed intentation in vns-loop<commit_after>/// This file contains the implementation of VNS
#include "header/vns-priv.hpp"

using namespace std;

namespace pcp {
	Solution bestSolution;
	Solution origSolution;

	bool checkValid(Solution* s);

	/// Some constants
	const int NUM_VNS = 1;
	const int SHAKE_START = 1;

	/// Implementation of VNS, see vns.hpp
	Solution vnsRun(Solution& best, Solution& orig, int unsuccessfulShake, int shakeStart, int shakeIncrement, int maxTime) {

		/// Backup the starting solutions
		bestSolution = new Solution(best);
		origSolution = new Solution(orig);

		cout<<"Best solution uses "<<bestSolution.colorsUsed<<" colors"<<endl;
		cout<<"Full solution uses "<<origSolution.colorsUsed<<" colors"<<endl;

		/// Define the neighborhoods to use
		VNS_Unit **neighbors = new VNS_Unit*[NUM_VNS];
		changeColor *ts = new changeColor;
		neighbors[0] = ts;

		time_t startTime = time(NULL);
		int no_imp_runs = 0;
		int curNeighbor = 0;
		int shakeSteps = shakeStart - shakeIncrement;
		Solution *toImprove = new Solution(&best);
		Solution *curBest = &best;

		/// Run as long as shaking still produces usefull solution
		while (true) {

			/// Run all possible neighborhood
			while (curNeighbor < NUM_VNS) {

				/// Select the new neighborhood
				VNS_Unit *neigh = neighbors[curNeighbor];
				cout<<"Running: "<< neigh->name() <<endl;

				/// Compute the minimum for this neighborhood
				Solution *improved = neigh->findLocalMin(best, orig);
				cout<<"Valid solution: "<<((checkValid(improved)) ? "true" : "false");
				cout<<endl;
				/// Replace the existing solution with the new solution if it is an
				/// improvement
				if (improved->colorsUsed < toImprove->colorsUsed) {
					delete toImprove;
					toImprove = improved;

					cout<<"Improvement found with "<<neigh->name()<<endl;

					/// Restart neighborhoods
					curNeighbor = curNeighbor == 0 ? 1 : 0;
				}

				/// Step to next neighborhood, no improvement found
				else {
					cout<<"No improvement found"<<endl;
					delete improved;
					curNeighbor++;
					cout<<"Test next neighborhood"<<endl;
				}
			} // end while neighborhood

			/// Local minimum of neighborhoods is better than current best
			/// solution
			if (toImprove->colorsUsed < best.colorsUsed) {
				cout<<"Improvement to global best solution found"<<endl;
				best = toImprove;
				toImprove = new Solution(curBest);
				no_imp_runs = 0;
				shakeSteps = shakeStart - shakeIncrement;
			}
			/// Reset local best solution to global best Solution
			else {
				toImprove = curBest;
				no_imp_runs++;

				/// Stopping condition, quit VNS
				if (no_imp_runs > unsuccessfulShake) {
					break;
				}
			}

			int shakeNeighbor = rand() % NUM_VNS;

			VNS_Unit *shaker = neighbors[shakeNeighbor];
			toImprove = shaker->shuffleSolution(*toImprove, orig, (shakeSteps += shakeIncrement));

			/// No time left, abort main loop
			if (startTime + maxTime < time(NULL)) {
				cout<<"Time's up"<<endl;
				break;
			}
		}

		return new Solution(curBest);
	}

	bool checkValid(Solution* s) {
		pair<VertexIter, VertexIter> vIter;
		int parts[s->numParts];
		typedef boost::graph_traits<Graph>::adjacency_iterator AdjIter;
		VertexPart_Map vParts = get(boost::vertex_index1_t(), *s->g);
		bool valid = true;

		for (int i = 0; i < s->numParts; i++) {
			parts[i] = 0;
		}

		for (vIter = vertices(*s->g); vIter.first != vIter.second; vIter.first++) {
			parts[vParts[*vIter.first]] = 1;

			pair<AdjIter, AdjIter> aIter;
			for (aIter = adjacent_vertices(*vIter.first, *s->g);
				  aIter.first != aIter.second; aIter.first++) {

				if (s->partition[vParts[*aIter.first]] ==
					 s->partition[vParts[*vIter.first]]) {

					valid = false;
					cerr<<"Solution is invalid"<<endl;
					cerr<<"Adjacent vertices "<<*aIter.first<<" and "<<*vIter.first;
					cerr<<" have same color "<<s->partition[vParts[*vIter.first]];
					cerr<<endl;
				}
			}
		}

		for (int i = 0; i < s->numParts; i++) {
			if (parts[i] == 0) {
				valid = false;
				cerr<<"Solution is invalid"<<endl;
				cerr<<"partition "<<i<<" seems to be missing"<<endl;
			}
		}

		return valid;
	}
}

<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/controls/menu/menu_config.h"

#include "build/build_config.h"

namespace views {

static MenuConfig* config_instance = NULL;

MenuConfig::MenuConfig()
    : text_color(SK_ColorBLACK),
      item_top_margin(3),
      item_bottom_margin(4),
      item_no_icon_top_margin(1),
      item_no_icon_bottom_margin(3),
      item_left_margin(4),
      label_to_arrow_padding(10),
      arrow_to_edge_padding(5),
      icon_to_label_padding(8),
      gutter_to_label(5),
      check_width(16),
      check_height(16),
      radio_width(16),
      radio_height(16),
      arrow_height(9),
      arrow_width(9),
      gutter_width(0),
      separator_height(6),
      render_gutter(false),
      show_mnemonics(false),
      scroll_arrow_height(3),
      label_to_accelerator_padding(10),
      show_accelerators(true) {
}

MenuConfig::~MenuConfig() {}

void MenuConfig::Reset() {
  delete config_instance;
  config_instance = NULL;
}

// static
const MenuConfig& MenuConfig::instance() {
  if (!config_instance)
    config_instance = Create();
  return *config_instance;
}

}  // namespace views
<commit_msg>Make menu items 40px tall when touch-optimized-ui is set.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/controls/menu/menu_config.h"

#include "base/command_line.h"
#include "build/build_config.h"
#include "ui/base/ui_base_switches.h"

namespace views {

static MenuConfig* config_instance = NULL;

MenuConfig::MenuConfig()
    : text_color(SK_ColorBLACK),
      item_top_margin(3),
      item_bottom_margin(4),
      item_no_icon_top_margin(1),
      item_no_icon_bottom_margin(3),
      item_left_margin(4),
      label_to_arrow_padding(10),
      arrow_to_edge_padding(5),
      icon_to_label_padding(8),
      gutter_to_label(5),
      check_width(16),
      check_height(16),
      radio_width(16),
      radio_height(16),
      arrow_height(9),
      arrow_width(9),
      gutter_width(0),
      separator_height(6),
      render_gutter(false),
      show_mnemonics(false),
      scroll_arrow_height(3),
      label_to_accelerator_padding(10),
      show_accelerators(true) {
  // Use 40px tall menu items when running in touch optimized mode.
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kTouchOptimizedUI)) {
    item_top_margin = item_no_icon_top_margin = 12;
    item_bottom_margin = item_no_icon_bottom_margin = 13;
  }
}

MenuConfig::~MenuConfig() {}

void MenuConfig::Reset() {
  delete config_instance;
  config_instance = NULL;
}

// static
const MenuConfig& MenuConfig::instance() {
  if (!config_instance)
    config_instance = Create();
  return *config_instance;
}

}  // namespace views
<|endoftext|>


<commit_before>#ifndef ITER_ZIP_HPP_
#define ITER_ZIP_HPP_

#include "iterbase.hpp"

#include <iterator>
#include <tuple>
#include <utility>

namespace iter {
    template <typename... RestContainers>
    class Zipped;

    template <typename... Containers>
    Zipped<Containers...> zip(Containers&&...);

    // specialization for at least 1 template argument
    template <typename Container, typename... RestContainers>
    class Zipped <Container, RestContainers...> {
        using ZipIterDeref =
            std::tuple<iterator_deref<Container>,
                iterator_deref<RestContainers>...>;

        friend Zipped zip<Container, RestContainers...>(
                Container&&, RestContainers&&...);

        template <typename... RC>
        friend class Zipped;

        private:
            Container container;
            Zipped<RestContainers...> rest_zipped;
            Zipped(Container container, RestContainers&&... rest)
                : container(std::forward<Container>(container)),
                rest_zipped{std::forward<RestContainers>(rest)...}
            { }

        public:
            class Iterator :
                public std::iterator<std::input_iterator_tag, ZipIterDeref>
        {
                private:
                    using RestIter =
                        typename Zipped<RestContainers...>::Iterator;

                    iterator_type<Container> iter;
                    RestIter rest_iter;
                public:
                    constexpr static const bool is_base_iter = false;
                    Iterator(iterator_type<Container> it, const RestIter& rest)
                        : iter{it},
                        rest_iter{rest}
                    { }

                    Iterator& operator++() {
                        ++this->iter;
                        ++this->rest_iter;
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->iter != other.iter &&
                            (RestIter::is_base_iter ||
                                this->rest_iter != other.rest_iter);
                    }

                    auto operator*() ->
                        decltype(std::tuple_cat(
                                    std::tuple<iterator_deref<Container>>{
                                        *this->iter},
                                    *this->rest_iter))
                    {
                        return std::tuple_cat(
                                std::tuple<iterator_deref<Container>>{
                                    *this->iter},
                                *this->rest_iter);
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                    std::begin(this->rest_zipped)};
            }

            Iterator end() {
                return {std::end(this->container),
                    std::end(this->rest_zipped)};
            }
    };

    template <>
    class Zipped<> {
        public:
            class Iterator
                : public std::iterator<std::input_iterator_tag, std::tuple<>>
            {
                public:
                    constexpr static const bool is_base_iter = true;

                    Iterator() { }
                    Iterator(const Iterator&) { }
                    Iterator& operator=(const Iterator&) { return *this; }

                    Iterator& operator++() {
                        return *this;
                    }

                    Iterator operator++(int) {
                        return *this;
                    }

                    // if this were to return true, there would be no need
                    // for the is_base_iter static class attribute.
                    // However, returning false causes an empty zip() call
                    // to reach the "end" immediately. Returning true here
                    // instead results in an infinite loop in the zip() case
                    bool operator!=(const Iterator&) const {
                        return false;
                    }

                    std::tuple<> operator*() {
                        return std::tuple<>{};
                    }
            };

            Iterator begin() {
                return {};
            }

            Iterator end() {
                return {};
            }
    };

    template <typename... Containers>
    Zipped<Containers...> zip(Containers&&... containers) {
        return {std::forward<Containers>(containers)...};
    }
}

#endif // #ifndef ITER_ZIP_HPP_
<commit_msg>adds zip ==<commit_after>#ifndef ITER_ZIP_HPP_
#define ITER_ZIP_HPP_

#include "iterbase.hpp"

#include <iterator>
#include <tuple>
#include <utility>

namespace iter {
    template <typename... RestContainers>
    class Zipped;

    template <typename... Containers>
    Zipped<Containers...> zip(Containers&&...);

    // specialization for at least 1 template argument
    template <typename Container, typename... RestContainers>
    class Zipped <Container, RestContainers...> {
        using ZipIterDeref =
            std::tuple<iterator_deref<Container>,
                iterator_deref<RestContainers>...>;

        friend Zipped zip<Container, RestContainers...>(
                Container&&, RestContainers&&...);

        template <typename... RC>
        friend class Zipped;

        private:
            Container container;
            Zipped<RestContainers...> rest_zipped;
            Zipped(Container container, RestContainers&&... rest)
                : container(std::forward<Container>(container)),
                rest_zipped{std::forward<RestContainers>(rest)...}
            { }

        public:
            class Iterator :
                public std::iterator<std::input_iterator_tag, ZipIterDeref>
        {
                private:
                    using RestIter =
                        typename Zipped<RestContainers...>::Iterator;

                    iterator_type<Container> iter;
                    RestIter rest_iter;
                public:
                    constexpr static const bool is_base_iter = false;
                    Iterator(iterator_type<Container> it, const RestIter& rest)
                        : iter{it},
                        rest_iter{rest}
                    { }

                    Iterator& operator++() {
                        ++this->iter;
                        ++this->rest_iter;
                        return *this;
                    }

                    Iterator operator++(int) {
                        auto ret = *this;
                        ++*this;
                        return ret;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->iter != other.iter &&
                            (RestIter::is_base_iter ||
                                this->rest_iter != other.rest_iter);
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this == other);
                    }

                    auto operator*() ->
                        decltype(std::tuple_cat(
                                    std::tuple<iterator_deref<Container>>{
                                        *this->iter},
                                    *this->rest_iter))
                    {
                        return std::tuple_cat(
                                std::tuple<iterator_deref<Container>>{
                                    *this->iter},
                                *this->rest_iter);
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                    std::begin(this->rest_zipped)};
            }

            Iterator end() {
                return {std::end(this->container),
                    std::end(this->rest_zipped)};
            }
    };

    template <>
    class Zipped<> {
        public:
            class Iterator
                : public std::iterator<std::input_iterator_tag, std::tuple<>>
            {
                public:
                    constexpr static const bool is_base_iter = true;

                    Iterator() { }
                    Iterator(const Iterator&) { }
                    Iterator& operator=(const Iterator&) { return *this; }

                    Iterator& operator++() {
                        return *this;
                    }

                    Iterator operator++(int) {
                        return *this;
                    }

                    // if this were to return true, there would be no need
                    // for the is_base_iter static class attribute.
                    // However, returning false causes an empty zip() call
                    // to reach the "end" immediately. Returning true here
                    // instead results in an infinite loop in the zip() case
                    bool operator!=(const Iterator&) const {
                        return false;
                    }

                    bool operator==(const Iterator& other) const {
                        return !(*this != other);
                    }

                    std::tuple<> operator*() {
                        return std::tuple<>{};
                    }
            };

            Iterator begin() {
                return {};
            }

            Iterator end() {
                return {};
            }
    };

    template <typename... Containers>
    Zipped<Containers...> zip(Containers&&... containers) {
        return {std::forward<Containers>(containers)...};
    }
}

#endif // #ifndef ITER_ZIP_HPP_
<|endoftext|>


<commit_before>#include <ros/ros.h>

#include <vector>
#include <string>

#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>

#include "moveit_recorder/utils.h"
#include "moveit_recorder/experiment_utils.h"
#include "moveit_recorder/trajectory_video_lookup.h"

int main(int argc, char** argv)
{
  ros::init(argc, argv, "split_screen_creator");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("regex", boost::program_options::value<std::string>(), "Regex of named videos to make 4x4 split screen with")
    ("save_dir",boost::program_options::value<std::string>(), "Directory for videos");
  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help") || argc == 1) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }

  try
  {
    std::string save_dir = utils::get_option(vm, "save_dir", "");
    boost::regex vid_regex(utils::get_option(vm, "regex", "view."));
    boost::filesystem::path save_directory(save_dir);

    // read the bag file to get the file names
    ROS_INFO("Opening bag at %s", save_directory.string().c_str());
    TrajectoryVideoLookup video_lookup_table;
    video_lookup_table.loadFromBag( save_directory.string() );

    // create split screen from regex matched videos
    TrajectoryVideoLookup::iterator traj_it = video_lookup_table.begin();
    for(; traj_it!=video_lookup_table.end();++traj_it)
    {
      std::vector<std::string> videos;
      TrajectoryVideoLookupEntry::iterator video_it = traj_it->second.begin();
      for(int v=0; v<4; v++)
      {
        boost::cmatch matches;
        if(boost::regex_match( video_it->name.c_str(), matches, vid_regex ))
        {
          videos.push_back( video_it->file );
          video_it++;
        }
        if(video_it==traj_it->second.end())
          video_it=traj_it->second.begin();
      }
      if(videos.size()!=4)
        ROS_WARN("No videos matching the regex, unable to create split screen video for trajectory id=\"%s\"",traj_it->first.c_str());
      else
      {
        std::string combined = (save_directory / boost::str(boost::format("%s_%s.%s")  % traj_it->first
                                                                                % "split"
                                                                                % "ogv")).string();
        std::string combine_command = boost::str(boost::format("ffmpeg -i %s -i %s -i %s -i %s -filter_complex \'[0:v]scale=iw/2:ih/2[rescale1];[1:v]scale=iw/2:ih/2[rescale2];[2:v]scale=iw/2:ih/2[rescale3];[3:v]scale=iw/2:ih/2[rescale4];[rescale1]pad=2*iw:2*ih[topleft];[topleft][rescale2]overlay=W/2:0[topright];[topright][rescale3]overlay=0:H/2[bottomleft];[bottomleft][rescale4]overlay=W/2:H/2[final]\' -map [final] -b 10000k %s") %videos[0] %videos[1] %videos[2] %videos[3] %combined);

        std::string response = utils::system::runCommand(combine_command);

        video_lookup_table.putVideoFile(traj_it->first, "split", combined);
      }
    }
    video_lookup_table.saveToBag( save_directory.string() );
  }
  catch(...)
  {
    std::cout << "Failure!" << std::endl;
  }

  ROS_INFO("Finished creating splitscreen videos.");
  ros::shutdown();

  return 0;
}
<commit_msg>added name prefix argument to node to specify name for resulting video<commit_after>#include <ros/ros.h>

#include <vector>
#include <string>

#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>

#include "moveit_recorder/utils.h"
#include "moveit_recorder/experiment_utils.h"
#include "moveit_recorder/trajectory_video_lookup.h"

int main(int argc, char** argv)
{
  ros::init(argc, argv, "split_screen_creator");
  ros::NodeHandle node_handle;
  ros::AsyncSpinner spinner(1);
  spinner.start();

  boost::program_options::options_description desc;
  desc.add_options()
    ("help", "Show help message")
    ("prefix", boost::program_options::value<std::string>(), "Prefix of 2x2 merged video")
    ("regex", boost::program_options::value<std::string>(), "Regex of named videos to make 2x2 split screen with")
    ("save_dir",boost::program_options::value<std::string>(), "Directory for videos");
  boost::program_options::variables_map vm;
  boost::program_options::parsed_options po = boost::program_options::parse_command_line(argc, argv, desc);
  boost::program_options::store(po, vm);
  boost::program_options::notify(vm);

  if (vm.count("help") || argc == 1) // show help if no parameters passed
  {
    std::cout << desc << std::endl;
    return 1;
  }

  try
  {
    std::string splitscreen_prefix = utils::get_option(vm, "prefix", "split");
    std::string save_dir = utils::get_option(vm, "save_dir", "");
    boost::regex vid_regex(utils::get_option(vm, "regex", "view."));
    boost::filesystem::path save_directory(save_dir);

    // read the bag file to get the file names
    ROS_INFO("Opening bag at %s", save_directory.string().c_str());
    TrajectoryVideoLookup video_lookup_table;
    video_lookup_table.loadFromBag( save_directory.string() );

    // create split screen from regex matched videos
    TrajectoryVideoLookup::iterator traj_it = video_lookup_table.begin();
    for(; traj_it!=video_lookup_table.end();++traj_it)
    {
      std::vector<std::string> videos;
      TrajectoryVideoLookupEntry::iterator video_it = traj_it->second.begin();
      for(; video_it!=traj_it->second.end(); ++video_it)
      {
        boost::cmatch matches;
        if(boost::regex_match( video_it->name.c_str(), matches, vid_regex ))
          videos.push_back( video_it->file );
      }
      if(videos.size()!=4)
        ROS_WARN("No videos matching the regex, unable to create split screen video for trajectory id=\"%s\"",traj_it->first.c_str());
      else
      {
        std::string combined = (save_directory / boost::str(boost::format("%s-%s.%s")  % traj_it->first
                                                                                % splitscreen_prefix
                                                                                % "ogv")).string();
        std::string combine_command = boost::str(boost::format("ffmpeg -i %s -i %s -i %s -i %s -filter_complex \'[0:v]scale=iw/2:ih/2[rescale1];[1:v]scale=iw/2:ih/2[rescale2];[2:v]scale=iw/2:ih/2[rescale3];[3:v]scale=iw/2:ih/2[rescale4];[rescale1]pad=2*iw:2*ih[topleft];[topleft][rescale2]overlay=W/2:0[topright];[topright][rescale3]overlay=0:H/2[bottomleft];[bottomleft][rescale4]overlay=W/2:H/2[final]\' -map [final] -b 10000k %s") %videos[0] %videos[1] %videos[2] %videos[3] %combined);

        std::string response = utils::system::runCommand(combine_command);

        video_lookup_table.putVideoFile(traj_it->first, splitscreen_prefix, combined);
      }
    }
    video_lookup_table.saveToBag( save_directory.string() );
  }
  catch(...)
  {
    std::cout << "Failure!" << std::endl;
  }

  ROS_INFO("Finished creating splitscreen videos.");
  ros::shutdown();

  return 0;
}
<|endoftext|>


<commit_before>#include "SkCGUtils.h"
#include "SkBitmap.h"
#include "SkColorPriv.h"

static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
    delete bitmap;
}

#define HAS_ARGB_SHIFTS(a, r, g, b) \
    (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \
    && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))

static SkBitmap* prepareForImageRef(const SkBitmap& bm,
                                    size_t* bitsPerComponent,
                                    CGBitmapInfo* info) {
    bool upscaleTo32 = false;

    switch (bm.config()) {
        case SkBitmap::kRGB_565_Config:
            upscaleTo32 = true;
            // fall through
        case SkBitmap::kARGB_8888_Config:
            *bitsPerComponent = 8;
#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 0, 8, 16) \
 || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(0, 24, 16, 8)
            *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
#elif defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) \
   || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
            // Matches the CGBitmapInfo that Apple recommends for best
            // performance, used by google chrome.
            *info = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst;
#else
// ...add more formats as required...
#warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \
            This will probably not work.
            // Legacy behavior. Perhaps turn this into an error at some
            // point.
            *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
#endif
            break;
#if 0
        case SkBitmap::kRGB_565_Config:
            // doesn't see quite right. Are they thinking 1555?
            *bitsPerComponent = 5;
            *info = kCGBitmapByteOrder16Little;
            break;
#endif
        case SkBitmap::kARGB_4444_Config:
            *bitsPerComponent = 4;
            *info = kCGBitmapByteOrder16Little | kCGImageAlphaPremultipliedLast;
            break;
        default:
            return NULL;
    }

    SkBitmap* copy;
    if (upscaleTo32) {
        copy = new SkBitmap;
        // here we make a ceep copy of the pixels, since CG won't take our
        // 565 directly
        bm.copyTo(copy, SkBitmap::kARGB_8888_Config);
    } else {
        copy = new SkBitmap(bm);
    }
    return copy;
}

#undef HAS_ARGB_SHIFTS

CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
                                            CGColorSpaceRef colorSpace) {
    size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
    CGBitmapInfo info       SK_INIT_TO_AVOID_WARNING;

    SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
    if (NULL == bitmap) {
        return NULL;
    }

    const int w = bitmap->width();
    const int h = bitmap->height();
    const size_t s = bitmap->getSize();

    // our provider "owns" the bitmap*, and will take care of deleting it
	// we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
	// proc, which will in turn unlock the pixels
	bitmap->lockPixels();
    CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
															 SkBitmap_ReleaseInfo);

    bool releaseColorSpace = false;
    if (NULL == colorSpace) {
        colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
        releaseColorSpace = true;
    }

    CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
                                   bitmap->bytesPerPixel() * 8,
                                   bitmap->rowBytes(), colorSpace, info, dataRef,
                                   NULL, false, kCGRenderingIntentDefault);

    if (releaseColorSpace) {
        CGColorSpaceRelease(colorSpace);
    }
    CGDataProviderRelease(dataRef);
    return ref;
}

void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
    CGImageRef img = SkCreateCGImageRef(bm);

    if (img) {
        CGRect r = CGRectMake(0, 0, bm.width(), bm.height());

        CGContextSaveGState(cg);
        CGContextTranslateCTM(cg, x, r.size.height + y);
        CGContextScaleCTM(cg, 1, -1);

        CGContextDrawImage(cg, r, img);

        CGContextRestoreGState(cg);

        CGImageRelease(img);
    }
}

<commit_msg>revert to DeviceRGB colorspace by default, which was changed accidentially in rev. 637<commit_after>#include "SkCGUtils.h"
#include "SkBitmap.h"
#include "SkColorPriv.h"

static void SkBitmap_ReleaseInfo(void* info, const void* pixelData, size_t size) {
    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(info);
    delete bitmap;
}

#define HAS_ARGB_SHIFTS(a, r, g, b) \
    (SK_A32_SHIFT == (a) && SK_R32_SHIFT == (r) \
    && SK_G32_SHIFT == (g) && SK_B32_SHIFT == (b))

static SkBitmap* prepareForImageRef(const SkBitmap& bm,
                                    size_t* bitsPerComponent,
                                    CGBitmapInfo* info) {
    bool upscaleTo32 = false;

    switch (bm.config()) {
        case SkBitmap::kRGB_565_Config:
            upscaleTo32 = true;
            // fall through
        case SkBitmap::kARGB_8888_Config:
            *bitsPerComponent = 8;
#if defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 0, 8, 16) \
 || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(0, 24, 16, 8)
            *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
#elif defined(SK_CPU_LENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0) \
   || defined(SK_CPU_BENDIAN) && HAS_ARGB_SHIFTS(24, 16, 8, 0)
            // Matches the CGBitmapInfo that Apple recommends for best
            // performance, used by google chrome.
            *info = kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst;
#else
// ...add more formats as required...
#warning Cannot convert SkBitmap to CGImageRef with these shiftmasks. \
            This will probably not work.
            // Legacy behavior. Perhaps turn this into an error at some
            // point.
            *info = kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast;
#endif
            break;
#if 0
        case SkBitmap::kRGB_565_Config:
            // doesn't see quite right. Are they thinking 1555?
            *bitsPerComponent = 5;
            *info = kCGBitmapByteOrder16Little;
            break;
#endif
        case SkBitmap::kARGB_4444_Config:
            *bitsPerComponent = 4;
            *info = kCGBitmapByteOrder16Little | kCGImageAlphaPremultipliedLast;
            break;
        default:
            return NULL;
    }

    SkBitmap* copy;
    if (upscaleTo32) {
        copy = new SkBitmap;
        // here we make a ceep copy of the pixels, since CG won't take our
        // 565 directly
        bm.copyTo(copy, SkBitmap::kARGB_8888_Config);
    } else {
        copy = new SkBitmap(bm);
    }
    return copy;
}

#undef HAS_ARGB_SHIFTS

CGImageRef SkCreateCGImageRefWithColorspace(const SkBitmap& bm,
                                            CGColorSpaceRef colorSpace) {
    size_t bitsPerComponent SK_INIT_TO_AVOID_WARNING;
    CGBitmapInfo info       SK_INIT_TO_AVOID_WARNING;

    SkBitmap* bitmap = prepareForImageRef(bm, &bitsPerComponent, &info);
    if (NULL == bitmap) {
        return NULL;
    }

    const int w = bitmap->width();
    const int h = bitmap->height();
    const size_t s = bitmap->getSize();

    // our provider "owns" the bitmap*, and will take care of deleting it
	// we initially lock it, so we can access the pixels. The bitmap will be deleted in the release
	// proc, which will in turn unlock the pixels
	bitmap->lockPixels();
    CGDataProviderRef dataRef = CGDataProviderCreateWithData(bitmap, bitmap->getPixels(), s,
															 SkBitmap_ReleaseInfo);

    bool releaseColorSpace = false;
    if (NULL == colorSpace) {
        colorSpace = CGColorSpaceCreateDeviceRGB();
        releaseColorSpace = true;
    }

    CGImageRef ref = CGImageCreate(w, h, bitsPerComponent,
                                   bitmap->bytesPerPixel() * 8,
                                   bitmap->rowBytes(), colorSpace, info, dataRef,
                                   NULL, false, kCGRenderingIntentDefault);

    if (releaseColorSpace) {
        CGColorSpaceRelease(colorSpace);
    }
    CGDataProviderRelease(dataRef);
    return ref;
}

void SkCGDrawBitmap(CGContextRef cg, const SkBitmap& bm, float x, float y) {
    CGImageRef img = SkCreateCGImageRef(bm);

    if (img) {
        CGRect r = CGRectMake(0, 0, bm.width(), bm.height());

        CGContextSaveGState(cg);
        CGContextTranslateCTM(cg, x, r.size.height + y);
        CGContextScaleCTM(cg, 1, -1);

        CGContextDrawImage(cg, r, img);

        CGContextRestoreGState(cg);

        CGImageRelease(img);
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef _WIN32
#include "iceoryx_utils/internal/posix_wrapper/access_control.hpp"
#include "iceoryx_utils/platform/pwd.hpp"
#include "iceoryx_utils/platform/stat.hpp"
#include "test.hpp"

#include <stdlib.h>

using namespace ::testing;
using namespace iox::posix;

constexpr const char* TestFileName = "/tmp/AclTestFile.tmp";

class AccessController_test : public Test
{
  public:
    AccessController_test()
    {
    }

    void SetUp()
    {
        internal::CaptureStderr();
        m_fileStream = fopen(TestFileName, "w");
        m_fileDescriptor = fileno(m_fileStream);
    }

    void TearDown()
    {
        fclose(m_fileStream);
        std::remove(TestFileName);

        std::string output = internal::GetCapturedStderr();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    ~AccessController_test()
    {
    }

    iox::posix::AccessController m_accessController;
    FILE* m_fileStream;
    int m_fileDescriptor;
};

TEST_F(AccessController_test, writeStandardPermissions)
{
    // should fail beacuse no access rights have been specified yet
    bool result = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_FALSE(result);

    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);

    // should fail because group and others is missing
    result = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_FALSE(result);

    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::NONE);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::READ);

    // should succeed now
    result = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_TRUE(result);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    acl_t localACL = acl_from_text("u::rw,g::-,o::r");

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, writeSpecialUserPermissions)
{
    bool entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_USER,
                                                            AccessController::Permission::READWRITE);
    // no name specified
    EXPECT_FALSE(entryAdded);

    std::string currentUserName(getpwuid(geteuid())->pw_name);

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_USER, AccessController::Permission::READWRITE, currentUserName);
    EXPECT_TRUE(entryAdded);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    // standard permissions not yet defined
    EXPECT_FALSE(entriesWrittenToFile);

    // add standard permissions
    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);
    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_TRUE(entriesWrittenToFile);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    std::string localACLShortText = "u:" + currentUserName + ":rw,u::rw,g::r,o::-,m::rw";
    acl_t localACL = acl_from_text(localACLShortText.c_str());

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, writeSpecialGroupPermissions)
{
    bool entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_GROUP,
                                                            AccessController::Permission::READWRITE);
    // no name specified
    EXPECT_FALSE(entryAdded);

    std::string groupName = "root";

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupName);
    EXPECT_TRUE(entryAdded);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    // standard permissions not yet defined
    EXPECT_FALSE(entriesWrittenToFile);

    // add standard permissions
    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);
    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_TRUE(entriesWrittenToFile);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    acl_t localACL = acl_from_text("g:root:rw,u::rw,g::r,o::-,m::rw");

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, writeSpecialPermissionsWithID)
{
    std::string currentUserName(getpwuid(geteuid())->pw_name);
    uid_t currentUserId(getpwuid(geteuid())->pw_uid);
    gid_t groupId = 0; // root

    bool entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_USER, AccessController::Permission::READWRITE, currentUserId);

    EXPECT_TRUE(entryAdded);

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupId);

    EXPECT_TRUE(entryAdded);

    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);
    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);

    EXPECT_TRUE(entriesWrittenToFile);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    std::string localACLShortText = "u:" + currentUserName + ":rw,u::rw,g:root:rw,g::r,o::-,m::rw";
    acl_t localACL = acl_from_text(localACLShortText.c_str());

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, addNameInWrongPlace)
{
    std::string currentUserName(getpwuid(geteuid())->pw_name);

    // this is not allowed as the default user should not be named explicitly
    m_accessController.addPermissionEntry(
        AccessController::Category::USER, AccessController::Permission::READWRITE, currentUserName);

    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    bool writtenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_FALSE(writtenToFile);
}

TEST_F(AccessController_test, addManyPermissions)
{
    std::string groupName = "root";

    bool entryAdded;
    for (int i = 0; i < AccessController::MaxNumOfPermissions; ++i)
    {
        entryAdded = m_accessController.addPermissionEntry(
            AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupName);

        ASSERT_TRUE(entryAdded);
    }

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupName);

    EXPECT_FALSE(entryAdded);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);

    // the same specific group has been entered several times
    EXPECT_FALSE(entriesWrittenToFile);
}

TEST_F(AccessController_test, addStrangeNames)
{
    bool entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_USER,
                                                            AccessController::Permission::READWRITE,
                                                            "VeryUnlikelyThatThisUserExistsOnThisMachine123456");
    // non-existing user name specified
    EXPECT_FALSE(entryAdded);

    entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_GROUP,
                                                       AccessController::Permission::READWRITE,
                                                       "NeverEverEverSuchAGroupNameExisted");
    // non-existing group name specified
    EXPECT_FALSE(entryAdded);
}
#endif
<commit_msg>iox-#32 disabling acl tests since they are not supported<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#if !defined(_WIN32) && !defined(__APPLE__)
#include "iceoryx_utils/internal/posix_wrapper/access_control.hpp"
#include "iceoryx_utils/platform/pwd.hpp"
#include "iceoryx_utils/platform/stat.hpp"
#include "test.hpp"

#include <stdlib.h>

using namespace ::testing;
using namespace iox::posix;

constexpr const char* TestFileName = "/tmp/AclTestFile.tmp";

class AccessController_test : public Test
{
  public:
    AccessController_test()
    {
    }

    void SetUp()
    {
        internal::CaptureStderr();
        m_fileStream = fopen(TestFileName, "w");
        m_fileDescriptor = fileno(m_fileStream);
    }

    void TearDown()
    {
        fclose(m_fileStream);
        std::remove(TestFileName);

        std::string output = internal::GetCapturedStderr();
        if (Test::HasFailure())
        {
            std::cout << output << std::endl;
        }
    }

    ~AccessController_test()
    {
    }

    iox::posix::AccessController m_accessController;
    FILE* m_fileStream;
    int m_fileDescriptor;
};

TEST_F(AccessController_test, writeStandardPermissions)
{
    // should fail beacuse no access rights have been specified yet
    bool result = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_FALSE(result);

    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);

    // should fail because group and others is missing
    result = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_FALSE(result);

    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::NONE);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::READ);

    // should succeed now
    result = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_TRUE(result);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    acl_t localACL = acl_from_text("u::rw,g::-,o::r");

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, writeSpecialUserPermissions)
{
    bool entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_USER,
                                                            AccessController::Permission::READWRITE);
    // no name specified
    EXPECT_FALSE(entryAdded);

    std::string currentUserName(getpwuid(geteuid())->pw_name);

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_USER, AccessController::Permission::READWRITE, currentUserName);
    EXPECT_TRUE(entryAdded);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    // standard permissions not yet defined
    EXPECT_FALSE(entriesWrittenToFile);

    // add standard permissions
    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);
    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_TRUE(entriesWrittenToFile);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    std::string localACLShortText = "u:" + currentUserName + ":rw,u::rw,g::r,o::-,m::rw";
    acl_t localACL = acl_from_text(localACLShortText.c_str());

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, writeSpecialGroupPermissions)
{
    bool entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_GROUP,
                                                            AccessController::Permission::READWRITE);
    // no name specified
    EXPECT_FALSE(entryAdded);

    std::string groupName = "root";

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupName);
    EXPECT_TRUE(entryAdded);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    // standard permissions not yet defined
    EXPECT_FALSE(entriesWrittenToFile);

    // add standard permissions
    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);
    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_TRUE(entriesWrittenToFile);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    acl_t localACL = acl_from_text("g:root:rw,u::rw,g::r,o::-,m::rw");

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, writeSpecialPermissionsWithID)
{
    std::string currentUserName(getpwuid(geteuid())->pw_name);
    uid_t currentUserId(getpwuid(geteuid())->pw_uid);
    gid_t groupId = 0; // root

    bool entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_USER, AccessController::Permission::READWRITE, currentUserId);

    EXPECT_TRUE(entryAdded);

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupId);

    EXPECT_TRUE(entryAdded);

    m_accessController.addPermissionEntry(AccessController::Category::USER, AccessController::Permission::READWRITE);
    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);

    EXPECT_TRUE(entriesWrittenToFile);

    acl_t fileACL = acl_get_fd(m_fileDescriptor);
    std::string localACLShortText = "u:" + currentUserName + ":rw,u::rw,g:root:rw,g::r,o::-,m::rw";
    acl_t localACL = acl_from_text(localACLShortText.c_str());

    std::string fileACLText(acl_to_text(fileACL, nullptr));
    std::string localACLText(acl_to_text(localACL, nullptr));

    EXPECT_EQ(fileACLText, localACLText);

    acl_free(fileACL);
    acl_free(localACL);
}

TEST_F(AccessController_test, addNameInWrongPlace)
{
    std::string currentUserName(getpwuid(geteuid())->pw_name);

    // this is not allowed as the default user should not be named explicitly
    m_accessController.addPermissionEntry(
        AccessController::Category::USER, AccessController::Permission::READWRITE, currentUserName);

    m_accessController.addPermissionEntry(AccessController::Category::GROUP, AccessController::Permission::READ);
    m_accessController.addPermissionEntry(AccessController::Category::OTHERS, AccessController::Permission::NONE);

    bool writtenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);
    EXPECT_FALSE(writtenToFile);
}

TEST_F(AccessController_test, addManyPermissions)
{
    std::string groupName = "root";

    bool entryAdded;
    for (int i = 0; i < AccessController::MaxNumOfPermissions; ++i)
    {
        entryAdded = m_accessController.addPermissionEntry(
            AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupName);

        ASSERT_TRUE(entryAdded);
    }

    entryAdded = m_accessController.addPermissionEntry(
        AccessController::Category::SPECIFIC_GROUP, AccessController::Permission::READWRITE, groupName);

    EXPECT_FALSE(entryAdded);

    bool entriesWrittenToFile = m_accessController.writePermissionsToFile(m_fileDescriptor);

    // the same specific group has been entered several times
    EXPECT_FALSE(entriesWrittenToFile);
}

TEST_F(AccessController_test, addStrangeNames)
{
    bool entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_USER,
                                                            AccessController::Permission::READWRITE,
                                                            "VeryUnlikelyThatThisUserExistsOnThisMachine123456");
    // non-existing user name specified
    EXPECT_FALSE(entryAdded);

    entryAdded = m_accessController.addPermissionEntry(AccessController::Category::SPECIFIC_GROUP,
                                                       AccessController::Permission::READWRITE,
                                                       "NeverEverEverSuchAGroupNameExisted");
    // non-existing group name specified
    EXPECT_FALSE(entryAdded);
}
#endif
<|endoftext|>