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

#include <cppuhelper/compbase1.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <cppuhelper/basemutex.hxx>
#include <com/sun/star/i18n/XCharacterClassification.hpp>
#include <unotest/bootstrapfixturebase.hxx>

#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>

#include <string.h>

using namespace ::com::sun::star;

class TestCharacterClassification : public test::BootstrapFixtureBase
{
public:
    virtual void setUp();
    virtual void tearDown();

    void testTitleCase();

    CPPUNIT_TEST_SUITE(TestCharacterClassification);
    CPPUNIT_TEST(testTitleCase);
    CPPUNIT_TEST_SUITE_END();
private:
    uno::Reference<i18n::XCharacterClassification> m_xCC;
};

//A test to ensure that our Title Case functionality is working
//http://lists.freedesktop.org/archives/libreoffice/2012-June/032767.html
//https://issues.apache.org/ooo/show_bug.cgi?id=30863
void TestCharacterClassification::testTitleCase()
{
    lang::Locale aLocale;
    aLocale.Language = OUString("en");
    aLocale.Country = OUString("US");

    {
        //basic example
        OUString sTest("Some text");
        OUString sTitleCase = m_xCC->toTitle(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be title", sTitleCase == "Some Text");
        OUString sUpperCase = m_xCC->toUpper(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be upper", sUpperCase == "SOME TEXT");
        OUString sLowerCase = m_xCC->toLower(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be lower ", sLowerCase == "some text");
    }

    {
        //tricky one
        const sal_Unicode LATINSMALLLETTERDZ[] = { 0x01F3 };
        OUString aTest(LATINSMALLLETTERDZ, SAL_N_ELEMENTS(LATINSMALLLETTERDZ));
        OUString sTitleCase = m_xCC->toTitle(aTest, 0, aTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be title", sTitleCase.getLength() == 1 && sTitleCase[0] == 0x01F2);
        OUString sUpperCase = m_xCC->toUpper(aTest, 0, aTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be upper", sUpperCase.getLength() == 1 && sUpperCase[0] == 0x01F1);
        OUString sLowerCase = m_xCC->toLower(aTest, 0, aTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be lower ", sLowerCase.getLength() == 1 && sLowerCase[0] == 0x01F3);
    }
}

void TestCharacterClassification::setUp()
{
    BootstrapFixtureBase::setUp();
    m_xCC = uno::Reference< i18n::XCharacterClassification >(m_xSFactory->createInstance(
        "com.sun.star.i18n.CharacterClassification"), uno::UNO_QUERY_THROW);
}

void TestCharacterClassification::tearDown()
{
    BootstrapFixtureBase::tearDown();
    m_xCC.clear();
}

CPPUNIT_TEST_SUITE_REGISTRATION(TestCharacterClassification);

CPPUNIT_PLUGIN_IMPLEMENT();

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

#include <cppuhelper/compbase1.hxx>
#include <cppuhelper/bootstrap.hxx>
#include <cppuhelper/basemutex.hxx>
#include <com/sun/star/i18n/XCharacterClassification.hpp>
#include <unotest/bootstrapfixturebase.hxx>

#include <rtl/strbuf.hxx>
#include <rtl/ustrbuf.hxx>

#include <string.h>

using namespace ::com::sun::star;

class TestCharacterClassification : public test::BootstrapFixtureBase
{
public:
    virtual void setUp();
    virtual void tearDown();

    void testTitleCase();
    void testStringType();

    CPPUNIT_TEST_SUITE(TestCharacterClassification);
    CPPUNIT_TEST(testTitleCase);
    CPPUNIT_TEST(testStringType);
    CPPUNIT_TEST_SUITE_END();
private:
    uno::Reference<i18n::XCharacterClassification> m_xCC;
};

//A test to ensure that our Title Case functionality is working
//http://lists.freedesktop.org/archives/libreoffice/2012-June/032767.html
//https://issues.apache.org/ooo/show_bug.cgi?id=30863
void TestCharacterClassification::testTitleCase()
{
    lang::Locale aLocale;
    aLocale.Language = OUString("en");
    aLocale.Country = OUString("US");

    {
        //basic example
        OUString sTest("Some text");
        OUString sTitleCase = m_xCC->toTitle(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be title", sTitleCase == "Some Text");
        OUString sUpperCase = m_xCC->toUpper(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be upper", sUpperCase == "SOME TEXT");
        OUString sLowerCase = m_xCC->toLower(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be lower ", sLowerCase == "some text");
    }

    {
        //tricky one
        const sal_Unicode LATINSMALLLETTERDZ[] = { 0x01F3 };
        OUString aTest(LATINSMALLLETTERDZ, SAL_N_ELEMENTS(LATINSMALLLETTERDZ));
        OUString sTitleCase = m_xCC->toTitle(aTest, 0, aTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be title", sTitleCase.getLength() == 1 && sTitleCase[0] == 0x01F2);
        OUString sUpperCase = m_xCC->toUpper(aTest, 0, aTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be upper", sUpperCase.getLength() == 1 && sUpperCase[0] == 0x01F1);
        OUString sLowerCase = m_xCC->toLower(aTest, 0, aTest.getLength(), aLocale);
        CPPUNIT_ASSERT_MESSAGE("Should be lower ", sLowerCase.getLength() == 1 && sLowerCase[0] == 0x01F3);
    }
}

//https://bugs.freedesktop.org/show_bug.cgi?id=69641
void TestCharacterClassification::testStringType()
{
    lang::Locale aLocale;
    aLocale.Language = OUString("en");
    aLocale.Country = OUString("US");

    {
        //simple case
        OUString sTest("Some text");
        sal_Int32 nResult = m_xCC->getStringType(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_EQUAL(nResult, sal_Int32(230));
    }

    {
        //tricky case
        const sal_Unicode MATHEMATICAL_ITALIC_SMALL_THETA[] = { 0xD835, 0xDF03 };
        OUString sTest(MATHEMATICAL_ITALIC_SMALL_THETA, SAL_N_ELEMENTS(MATHEMATICAL_ITALIC_SMALL_THETA));
        sal_Int32 nResult = m_xCC->getStringType(sTest, 0, sTest.getLength(), aLocale);
        CPPUNIT_ASSERT_EQUAL(nResult, sal_Int32(228));
    }

}

void TestCharacterClassification::setUp()
{
    BootstrapFixtureBase::setUp();
    m_xCC = uno::Reference< i18n::XCharacterClassification >(m_xSFactory->createInstance(
        "com.sun.star.i18n.CharacterClassification"), uno::UNO_QUERY_THROW);
}

void TestCharacterClassification::tearDown()
{
    BootstrapFixtureBase::tearDown();
    m_xCC.clear();
}

CPPUNIT_TEST_SUITE_REGISTRATION(TestCharacterClassification);

CPPUNIT_PLUGIN_IMPLEMENT();

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


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

// prevent internal compiler error with MSVC6SP3
#include <utility>

#define TRANSLITERATION_Size_ja_JP
#include <transliteration_Ignore.hxx>
#define TRANSLITERATION_smallToLarge_ja_JP
#define TRANSLITERATION_largeToSmall_ja_JP
#include <transliteration_OneToOne.hxx>

using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace rtl;

namespace com { namespace sun { namespace star { namespace i18n {

OUString SAL_CALL
ignoreSize_ja_JP::folding( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset )
  throw(RuntimeException)
{
    smallToLarge_ja_JP t1;
    return t1.transliterate(inStr, startPos, nCount, offset);
}

Sequence< OUString > SAL_CALL
ignoreSize_ja_JP::transliterateRange( const OUString& str1, const OUString& str2 )
  throw(RuntimeException)
{
    smallToLarge_ja_JP t1;
    largeToSmall_ja_JP t2;

    return transliteration_Ignore::transliterateRange(str1, str2, t1, t2);
}

sal_Unicode SAL_CALL
ignoreSize_ja_JP::transliterateChar2Char( sal_Unicode inChar) throw(RuntimeException, MultipleCharsOutputException)
{
    smallToLarge_ja_JP t1;
    return t1.transliterateChar2Char(inChar);
}

} } } }
<commit_msg>INTEGRATION: CWS ooo19126 (1.7.190); FILE MERGED 2005/09/05 17:47:57 rt 1.7.190.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ignoreSize_ja_JP.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 17:30:33 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// prevent internal compiler error with MSVC6SP3
#include <utility>

#define TRANSLITERATION_Size_ja_JP
#include <transliteration_Ignore.hxx>
#define TRANSLITERATION_smallToLarge_ja_JP
#define TRANSLITERATION_largeToSmall_ja_JP
#include <transliteration_OneToOne.hxx>

using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace rtl;

namespace com { namespace sun { namespace star { namespace i18n {

OUString SAL_CALL
ignoreSize_ja_JP::folding( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset )
  throw(RuntimeException)
{
    smallToLarge_ja_JP t1;
    return t1.transliterate(inStr, startPos, nCount, offset);
}

Sequence< OUString > SAL_CALL
ignoreSize_ja_JP::transliterateRange( const OUString& str1, const OUString& str2 )
  throw(RuntimeException)
{
    smallToLarge_ja_JP t1;
    largeToSmall_ja_JP t2;

    return transliteration_Ignore::transliterateRange(str1, str2, t1, t2);
}

sal_Unicode SAL_CALL
ignoreSize_ja_JP::transliterateChar2Char( sal_Unicode inChar) throw(RuntimeException, MultipleCharsOutputException)
{
    smallToLarge_ja_JP t1;
    return t1.transliterateChar2Char(inChar);
}

} } } }
<|endoftext|>


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

#include "iceoryx_utils/internal/posix_wrapper/message_queue.hpp"
#include "iceoryx_utils/cxx/smart_c.hpp"
#include "iceoryx_utils/platform/fcntl.hpp"
#include "iceoryx_utils/platform/platform_correction.hpp"

#include <chrono>
#include <cstdlib>
#include <string>

namespace iox
{
namespace posix
{
MessageQueue::MessageQueue()
{
    this->m_isInitialized = false;
    this->m_errorValue = IpcChannelError::NOT_INITIALIZED;
}

MessageQueue::MessageQueue(const IpcChannelName_t& name,
                           const IpcChannelMode mode,
                           const IpcChannelSide channelSide,
                           const size_t maxMsgSize,
                           const uint64_t maxMsgNumber)
    : m_channelSide(channelSide)
{
    sanitizeIpcChannelName(name)
        .and_then([this](IpcChannelName_t& name) { m_name = std::move(name); })
        .or_else([this](IpcChannelError) {
            this->m_isInitialized = false;
            this->m_errorValue = IpcChannelError::INVALID_CHANNEL_NAME;
        });

    if (maxMsgSize > MAX_MESSAGE_SIZE)
    {
        this->m_isInitialized = false;
        this->m_errorValue = IpcChannelError::MAX_MESSAGE_SIZE_EXCEEDED;
    }
    else
    {
        if (channelSide == IpcChannelSide::SERVER)
        {
            auto mqCall = cxx::makeSmartC(
                mq_unlink, cxx::ReturnMode::PRE_DEFINED_ERROR_CODE, {ERROR_CODE}, {ENOENT}, m_name.c_str());
            if (!mqCall.hasErrors())
            {
                if (mqCall.getErrNum() != ENOENT)
                {
                    std::cout << "MQ still there, doing an unlink of " << m_name << std::endl;
                }
            }
        }
        // fields have a different order in QNX,
        // so we need to initialize by name
        m_attributes.mq_flags = (mode == IpcChannelMode::NON_BLOCKING) ? O_NONBLOCK : 0;
        m_attributes.mq_maxmsg = static_cast<long>(maxMsgNumber);
        m_attributes.mq_msgsize = static_cast<long>(maxMsgSize);
        m_attributes.mq_curmsgs = 0L;
#ifdef __QNX__
        m_attributes.mq_recvwait = 0L;
        m_attributes.mq_sendwait = 0L;
#endif
        auto openResult = open(m_name, mode, channelSide);
        if (!openResult.has_error())
        {
            this->m_isInitialized = true;
            this->m_errorValue = IpcChannelError::UNDEFINED;
            this->m_mqDescriptor = openResult.value();
        }
        else
        {
            this->m_isInitialized = false;
            this->m_errorValue = openResult.get_error();
        }
    }
}

MessageQueue::MessageQueue(MessageQueue&& other)
{
    *this = std::move(other);
}

MessageQueue::~MessageQueue()
{
    if (destroy().has_error())
    {
        std::cerr << "unable to cleanup message queue \"" << m_name << "\" in the destructor" << std::endl;
    }
}

MessageQueue& MessageQueue::operator=(MessageQueue&& other)
{
    if (this != &other)
    {
        if (destroy().has_error())
        {
            std::cerr << "unable to cleanup message queue \"" << m_name
                      << "\" during move operation - resource leaks are possible!" << std::endl;
        }
        CreationPattern_t::operator=(std::move(other));

        m_name = std::move(other.m_name);
        m_attributes = std::move(other.m_attributes);
        m_mqDescriptor = std::move(other.m_mqDescriptor);
        m_channelSide = std::move(other.m_channelSide);
        other.m_mqDescriptor = INVALID_DESCRIPTOR;
    }

    return *this;
}

cxx::expected<bool, IpcChannelError> MessageQueue::unlinkIfExists(const IpcChannelName_t& name)
{
    IpcChannelName_t l_name;
    if (sanitizeIpcChannelName(name).and_then([&](IpcChannelName_t& name) { l_name = std::move(name); }).has_error())
    {
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }

    auto mqCall =
        cxx::makeSmartC(mq_unlink, cxx::ReturnMode::PRE_DEFINED_ERROR_CODE, {ERROR_CODE}, {ENOENT}, l_name.c_str());

    if (!mqCall.hasErrors())
    {
        // ENOENT is set if the message queue could not be unlinked
        return cxx::success<bool>(mqCall.getErrNum() != ENOENT);
    }
    else
    {
        return createErrorFromErrnum(l_name, mqCall.getErrNum());
    }
}

cxx::expected<IpcChannelError> MessageQueue::destroy()
{
    if (m_mqDescriptor != INVALID_DESCRIPTOR)
    {
        auto closeCall = close();
        if (closeCall.has_error())
        {
            m_mqDescriptor = INVALID_DESCRIPTOR;
            return closeCall;
        }
        auto unlinkCall = unlink();
        if (unlinkCall.has_error())
        {
            m_mqDescriptor = INVALID_DESCRIPTOR;
            return unlinkCall;
        }
    }

    m_mqDescriptor = INVALID_DESCRIPTOR;
    m_isInitialized = false;
    return cxx::success<void>();
}

cxx::expected<IpcChannelError> MessageQueue::send(const std::string& msg) const
{
    const size_t messageSize = static_cast<size_t>(msg.size()) + NULL_TERMINATOR_SIZE;
    if (messageSize > static_cast<size_t>(m_attributes.mq_msgsize))
    {
        return cxx::error<IpcChannelError>(IpcChannelError::MESSAGE_TOO_LONG);
    }

    auto mqCall = cxx::makeSmartC(mq_send,
                                  cxx::ReturnMode::PRE_DEFINED_ERROR_CODE,
                                  {ERROR_CODE},
                                  {},
                                  m_mqDescriptor,
                                  msg.c_str(),
                                  messageSize,
                                  1U);

    if (mqCall.hasErrors())
    {
        return createErrorFromErrnum(mqCall.getErrNum());
    }

    return cxx::success<void>();
}

cxx::expected<std::string, IpcChannelError> MessageQueue::receive() const
{
    char message[MAX_MESSAGE_SIZE];
    auto mqCall = cxx::makeSmartC(mq_receive,
                                  cxx::ReturnMode::PRE_DEFINED_ERROR_CODE,
                                  {static_cast<ssize_t>(ERROR_CODE)},
                                  {},
                                  m_mqDescriptor,
                                  message,
                                  MAX_MESSAGE_SIZE,
                                  nullptr);

    if (mqCall.hasErrors())
    {
        return createErrorFromErrnum(mqCall.getErrNum());
    }

    return cxx::success<std::string>(std::string(&(message[0])));
}

cxx::expected<int32_t, IpcChannelError>
MessageQueue::open(const IpcChannelName_t& name, const IpcChannelMode mode, const IpcChannelSide channelSide)
{
    IpcChannelName_t l_name;
    if (sanitizeIpcChannelName(name).and_then([&](IpcChannelName_t& name) { l_name = std::move(name); }).has_error())
    {
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }

    int32_t openFlags = O_RDWR;
    openFlags |= (mode == IpcChannelMode::NON_BLOCKING) ? O_NONBLOCK : 0;
    if (channelSide == IpcChannelSide::SERVER)
    {
        openFlags |= O_CREAT;
    }

    // the mask will be applied to the permissions, therefore we need to set it to 0
    mode_t umaskSaved = umask(0);

    auto mqCall = cxx::makeSmartC(mq_open,
                                  cxx::ReturnMode::PRE_DEFINED_ERROR_CODE,
                                  {ERROR_CODE},
                                  {ENOENT},
                                  l_name.c_str(),
                                  openFlags,
                                  m_filemode,
                                  &m_attributes);

    umask(umaskSaved);

    if (!mqCall.hasErrors())
    {
        if (mqCall.getErrNum() == 0)
        {
            return cxx::success<int32_t>(mqCall.getReturnValue());
        }
        else if (mqCall.getErrNum() == ENOENT)
        {
            return cxx::error<IpcChannelError>(IpcChannelError::NO_SUCH_CHANNEL);
        }
        else
        {
            return createErrorFromErrnum(mqCall.getErrNum());
        }
    }
    else
    {
        return createErrorFromErrnum(mqCall.getErrNum());
    }
}

cxx::expected<IpcChannelError> MessageQueue::close()
{
    auto mqCall = cxx::makeSmartC(mq_close, cxx::ReturnMode::PRE_DEFINED_ERROR_CODE, {ERROR_CODE}, {}, m_mqDescriptor);

    if (mqCall.hasErrors())
    {
        return createErrorFromErrnum(mqCall.getErrNum());
    }

    return cxx::success<void>();
}

cxx::expected<IpcChannelError> MessageQueue::unlink()
{
    if (m_channelSide == IpcChannelSide::CLIENT)
    {
        return cxx::success<void>();
    }
    else
    {
        auto mqCall =
            cxx::makeSmartC(mq_unlink, cxx::ReturnMode::PRE_DEFINED_ERROR_CODE, {ERROR_CODE}, {}, m_name.c_str());
        if (mqCall.hasErrors())
        {
            return createErrorFromErrnum(mqCall.getErrNum());
        }

        return cxx::success<void>();
    }
}

cxx::expected<std::string, IpcChannelError> MessageQueue::timedReceive(const units::Duration& timeout) const
{
    timespec timeOut = timeout.timespec(units::TimeSpecReference::Epoch);
    char message[MAX_MESSAGE_SIZE];

    auto mqCall = cxx::makeSmartC(mq_timedreceive,
                                  cxx::ReturnMode::PRE_DEFINED_ERROR_CODE,
                                  {static_cast<ssize_t>(ERROR_CODE)},
                                  {TIMEOUT_ERRNO},
                                  m_mqDescriptor,
                                  message,
                                  MAX_MESSAGE_SIZE,
                                  nullptr,
                                  &timeOut);

    if (mqCall.hasErrors())
    {
        return createErrorFromErrnum(mqCall.getErrNum());
    }
    else if (mqCall.getErrNum() == TIMEOUT_ERRNO)
    {
        return createErrorFromErrnum(ETIMEDOUT);
    }

    return cxx::success<std::string>(std::string(&(message[0])));
}

cxx::expected<IpcChannelError> MessageQueue::timedSend(const std::string& msg, const units::Duration& timeout) const
{
    const size_t messageSize = static_cast<size_t>(msg.size()) + NULL_TERMINATOR_SIZE;
    if (messageSize > static_cast<size_t>(m_attributes.mq_msgsize))
    {
        std::cerr << "the message \"" << msg << "\" which should be sent to the message queue \"" << m_name
                  << "\" is too long" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::MESSAGE_TOO_LONG);
    }

    timespec timeOut = timeout.timespec(units::TimeSpecReference::Epoch);

    auto mqCall = cxx::makeSmartC(mq_timedsend,
                                  cxx::ReturnMode::PRE_DEFINED_ERROR_CODE,
                                  {ERROR_CODE},
                                  {TIMEOUT_ERRNO},
                                  m_mqDescriptor,
                                  msg.c_str(),
                                  messageSize,
                                  1U,
                                  &timeOut);

    if (mqCall.hasErrors())
    {
        return createErrorFromErrnum(mqCall.getErrNum());
    }
    else if (mqCall.getErrNum() == TIMEOUT_ERRNO)
    {
        return createErrorFromErrnum(ETIMEDOUT);
    }

    return cxx::success<void>();
}

cxx::expected<bool, IpcChannelError> MessageQueue::isOutdated()
{
    struct stat sb;
    auto fstatCall = cxx::makeSmartC(fstat, cxx::ReturnMode::PRE_DEFINED_ERROR_CODE, {-1}, {}, m_mqDescriptor, &sb);
    if (fstatCall.hasErrors())
    {
        return createErrorFromErrnum(fstatCall.getErrNum());
    }
    return cxx::success<bool>(sb.st_nlink == 0);
}

cxx::error<IpcChannelError> MessageQueue::createErrorFromErrnum(const int32_t errnum) const
{
    return createErrorFromErrnum(m_name, errnum);
}

cxx::error<IpcChannelError> MessageQueue::createErrorFromErrnum(const IpcChannelName_t& name, const int32_t errnum)
{
    switch (errnum)
    {
    case EACCES:
    {
        std::cerr << "access denied to message queue \"" << name << "\"" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::ACCESS_DENIED);
    }
    case EAGAIN:
    {
        std::cerr << "the message queue \"" << name << "\" is full" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::CHANNEL_FULL);
    }
    case ETIMEDOUT:
    {
        // no error message needed since this is a normal use case
        return cxx::error<IpcChannelError>(IpcChannelError::TIMEOUT);
    }
    case EEXIST:
    {
        std::cerr << "message queue \"" << name << "\" already exists" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::CHANNEL_ALREADY_EXISTS);
    }
    case EINVAL:
    {
        std::cerr << "provided invalid arguments for message queue \"" << name << "\"" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_ARGUMENTS);
    }
    case ENOENT:
    {
        std::cerr << "message queue \"" << name << "\" does not exist" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::NO_SUCH_CHANNEL);
    }
    case ENAMETOOLONG:
    {
        std::cerr << "message queue name \"" << name << "\" is too long" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }
    default:
    {
        std::cerr << "internal logic error in message queue \"" << name << "\" occurred [errno: " << errnum << ": "
                  << strerror(errnum) << "]" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::INTERNAL_LOGIC_ERROR);
    }
    }
}

cxx::expected<IpcChannelName_t, IpcChannelError>
MessageQueue::sanitizeIpcChannelName(const IpcChannelName_t& name) noexcept
{
    /// @todo the check for the longest valid queue name is missing
    /// the name for the mqeue is limited by MAX_PATH
    /// The mq_open call is wrapped by smartC to throw then an ENAMETOOLONG error
    /// See: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html
    if (name.empty() || name.size() < SHORTEST_VALID_QUEUE_NAME)
    {
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }
    else if (name.c_str()[0] != '/')
    {
        return cxx::success<IpcChannelName_t>(IpcChannelName_t("/").append(iox::cxx::TruncateToCapacity, name));
    }
    else
    {
        return cxx::success<IpcChannelName_t>(name);
    }
}

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

#include "iceoryx_utils/internal/posix_wrapper/message_queue.hpp"
#include "iceoryx_utils/platform/fcntl.hpp"
#include "iceoryx_utils/platform/platform_correction.hpp"
#include "iceoryx_utils/posix_wrapper/posix_call.hpp"

#include <chrono>
#include <cstdlib>
#include <string>

namespace iox
{
namespace posix
{
MessageQueue::MessageQueue()
{
    this->m_isInitialized = false;
    this->m_errorValue = IpcChannelError::NOT_INITIALIZED;
}

MessageQueue::MessageQueue(const IpcChannelName_t& name,
                           const IpcChannelMode mode,
                           const IpcChannelSide channelSide,
                           const size_t maxMsgSize,
                           const uint64_t maxMsgNumber)
    : m_channelSide(channelSide)
{
    sanitizeIpcChannelName(name)
        .and_then([this](IpcChannelName_t& name) { m_name = std::move(name); })
        .or_else([this](IpcChannelError) {
            this->m_isInitialized = false;
            this->m_errorValue = IpcChannelError::INVALID_CHANNEL_NAME;
        });

    if (maxMsgSize > MAX_MESSAGE_SIZE)
    {
        this->m_isInitialized = false;
        this->m_errorValue = IpcChannelError::MAX_MESSAGE_SIZE_EXCEEDED;
    }
    else
    {
        if (channelSide == IpcChannelSide::SERVER)
        {
            posixCall(mq_unlink)(m_name.c_str())
                .failureReturnValue(ERROR_CODE)
                .evaluateWithIgnoredErrnos(ENOENT)
                .and_then([this](auto& r) {
                    if (r.errnum != ENOENT)
                    {
                        std::cout << "MQ still there, doing an unlink of " << m_name << std::endl;
                    }
                });
        }
        // fields have a different order in QNX,
        // so we need to initialize by name
        m_attributes.mq_flags = (mode == IpcChannelMode::NON_BLOCKING) ? O_NONBLOCK : 0;
        m_attributes.mq_maxmsg = static_cast<long>(maxMsgNumber);
        m_attributes.mq_msgsize = static_cast<long>(maxMsgSize);
        m_attributes.mq_curmsgs = 0L;
#ifdef __QNX__
        m_attributes.mq_recvwait = 0L;
        m_attributes.mq_sendwait = 0L;
#endif
        auto openResult = open(m_name, mode, channelSide);
        if (!openResult.has_error())
        {
            this->m_isInitialized = true;
            this->m_errorValue = IpcChannelError::UNDEFINED;
            this->m_mqDescriptor = openResult.value();
        }
        else
        {
            this->m_isInitialized = false;
            this->m_errorValue = openResult.get_error();
        }
    }
}

MessageQueue::MessageQueue(MessageQueue&& other)
{
    *this = std::move(other);
}

MessageQueue::~MessageQueue()
{
    if (destroy().has_error())
    {
        std::cerr << "unable to cleanup message queue \"" << m_name << "\" in the destructor" << std::endl;
    }
}

MessageQueue& MessageQueue::operator=(MessageQueue&& other)
{
    if (this != &other)
    {
        if (destroy().has_error())
        {
            std::cerr << "unable to cleanup message queue \"" << m_name
                      << "\" during move operation - resource leaks are possible!" << std::endl;
        }
        CreationPattern_t::operator=(std::move(other));

        m_name = std::move(other.m_name);
        m_attributes = std::move(other.m_attributes);
        m_mqDescriptor = std::move(other.m_mqDescriptor);
        m_channelSide = std::move(other.m_channelSide);
        other.m_mqDescriptor = INVALID_DESCRIPTOR;
    }

    return *this;
}

cxx::expected<bool, IpcChannelError> MessageQueue::unlinkIfExists(const IpcChannelName_t& name)
{
    IpcChannelName_t l_name;
    if (sanitizeIpcChannelName(name).and_then([&](IpcChannelName_t& name) { l_name = std::move(name); }).has_error())
    {
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }

    auto mqCall = posixCall(mq_unlink)(l_name.c_str()).failureReturnValue(ERROR_CODE).evaluateWithIgnoredErrnos(ENOENT);

    if (mqCall.has_error())
    {
        return createErrorFromErrnum(l_name, mqCall.get_error().errnum);
    }
    return cxx::success<bool>(mqCall->errnum != ENOENT);
}

cxx::expected<IpcChannelError> MessageQueue::destroy()
{
    if (m_mqDescriptor != INVALID_DESCRIPTOR)
    {
        auto closeCall = close();
        if (closeCall.has_error())
        {
            m_mqDescriptor = INVALID_DESCRIPTOR;
            return closeCall;
        }
        auto unlinkCall = unlink();
        if (unlinkCall.has_error())
        {
            m_mqDescriptor = INVALID_DESCRIPTOR;
            return unlinkCall;
        }
    }

    m_mqDescriptor = INVALID_DESCRIPTOR;
    m_isInitialized = false;
    return cxx::success<void>();
}

cxx::expected<IpcChannelError> MessageQueue::send(const std::string& msg) const
{
    const size_t messageSize = static_cast<size_t>(msg.size()) + NULL_TERMINATOR_SIZE;
    if (messageSize > static_cast<size_t>(m_attributes.mq_msgsize))
    {
        return cxx::error<IpcChannelError>(IpcChannelError::MESSAGE_TOO_LONG);
    }

    auto mqCall =
        posixCall(mq_send)(m_mqDescriptor, msg.c_str(), messageSize, 1U).failureReturnValue(ERROR_CODE).evaluate();

    if (mqCall.has_error())
    {
        return createErrorFromErrnum(mqCall.get_error().errnum);
    }

    return cxx::success<void>();
}

cxx::expected<std::string, IpcChannelError> MessageQueue::receive() const
{
    char message[MAX_MESSAGE_SIZE];

    auto mqCall = posixCall(mq_receive)(m_mqDescriptor, message, MAX_MESSAGE_SIZE, nullptr)
                      .failureReturnValue(ERROR_CODE)
                      .evaluate();

    if (mqCall.has_error())
    {
        return createErrorFromErrnum(mqCall.get_error().errnum);
    }

    return cxx::success<std::string>(std::string(&(message[0])));
}

cxx::expected<int32_t, IpcChannelError>
MessageQueue::open(const IpcChannelName_t& name, const IpcChannelMode mode, const IpcChannelSide channelSide)
{
    IpcChannelName_t l_name;
    if (sanitizeIpcChannelName(name).and_then([&](IpcChannelName_t& name) { l_name = std::move(name); }).has_error())
    {
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }

    int32_t openFlags = O_RDWR;
    openFlags |= (mode == IpcChannelMode::NON_BLOCKING) ? O_NONBLOCK : 0;
    if (channelSide == IpcChannelSide::SERVER)
    {
        openFlags |= O_CREAT;
    }

    // the mask will be applied to the permissions, therefore we need to set it to 0
    mode_t umaskSaved = umask(0);

    // mq_open uses c variadic arguments therefore we have to use a lambda
    auto mq_open_lambda = [](const char* name, int oflag, mode_t mode, struct mq_attr* attr) -> mqd_t {
        return mq_open(name, oflag, mode, attr);
    };
    mqd_t (*mq_open_call)(const char*, int, mode_t, struct mq_attr*) = mq_open_lambda;

    auto mqCall = posixCall(mq_open_call)(l_name.c_str(), openFlags, m_filemode, &m_attributes)
                      .failureReturnValue(ERROR_CODE)
                      .evaluateWithIgnoredErrnos(ENOENT);

    umask(umaskSaved);

    if (!mqCall.has_error())
    {
        if (mqCall->errnum == 0)
        {
            return cxx::success<int32_t>(mqCall->value);
        }
        else if (mqCall->errnum == ENOENT)
        {
            return cxx::error<IpcChannelError>(IpcChannelError::NO_SUCH_CHANNEL);
        }
    }

    return createErrorFromErrnum(mqCall.get_error().errnum);
}

cxx::expected<IpcChannelError> MessageQueue::close()
{
    auto mqCall = posixCall(mq_close)(m_mqDescriptor).failureReturnValue(ERROR_CODE).evaluate();

    if (mqCall.has_error())
    {
        return createErrorFromErrnum(mqCall.get_error().errnum);
    }

    return cxx::success<void>();
}

cxx::expected<IpcChannelError> MessageQueue::unlink()
{
    if (m_channelSide == IpcChannelSide::CLIENT)
    {
        return cxx::success<void>();
    }
    else
    {
        auto mqCall = posixCall(mq_unlink)(m_name.c_str()).failureReturnValue(ERROR_CODE).evaluate();
        if (mqCall.has_error())
        {
            return createErrorFromErrnum(mqCall.get_error().errnum);
        }

        return cxx::success<void>();
    }
}

cxx::expected<std::string, IpcChannelError> MessageQueue::timedReceive(const units::Duration& timeout) const
{
    timespec timeOut = timeout.timespec(units::TimeSpecReference::Epoch);
    char message[MAX_MESSAGE_SIZE];

    auto mqCall = posixCall(mq_timedreceive)(m_mqDescriptor, message, MAX_MESSAGE_SIZE, nullptr, &timeOut)
                      .failureReturnValue(ERROR_CODE)
                      .evaluateWithIgnoredErrnos(TIMEOUT_ERRNO);

    if (mqCall.has_error())
    {
        return createErrorFromErrnum(mqCall.get_error().errnum);
    }
    else if (mqCall->errnum == TIMEOUT_ERRNO)
    {
        return createErrorFromErrnum(ETIMEDOUT);
    }

    return cxx::success<std::string>(std::string(&(message[0])));
}

cxx::expected<IpcChannelError> MessageQueue::timedSend(const std::string& msg, const units::Duration& timeout) const
{
    const size_t messageSize = static_cast<size_t>(msg.size()) + NULL_TERMINATOR_SIZE;
    if (messageSize > static_cast<size_t>(m_attributes.mq_msgsize))
    {
        std::cerr << "the message \"" << msg << "\" which should be sent to the message queue \"" << m_name
                  << "\" is too long" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::MESSAGE_TOO_LONG);
    }

    timespec timeOut = timeout.timespec(units::TimeSpecReference::Epoch);

    auto mqCall = posixCall(mq_timedsend)(m_mqDescriptor, msg.c_str(), messageSize, 1U, &timeOut)
                      .failureReturnValue(ERROR_CODE)
                      .evaluateWithIgnoredErrnos(TIMEOUT_ERRNO);

    if (mqCall.has_error())
    {
        return createErrorFromErrnum(mqCall.get_error().errnum);
    }
    else if (mqCall->errnum == TIMEOUT_ERRNO)
    {
        return createErrorFromErrnum(ETIMEDOUT);
    }

    return cxx::success<void>();
}

cxx::expected<bool, IpcChannelError> MessageQueue::isOutdated()
{
    struct stat sb;
    auto fstatCall = posixCall(fstat)(m_mqDescriptor, &sb).failureReturnValue(-1).evaluate();
    if (fstatCall.has_error())
    {
        return createErrorFromErrnum(fstatCall.get_error().errnum);
    }
    return cxx::success<bool>(sb.st_nlink == 0);
}

cxx::error<IpcChannelError> MessageQueue::createErrorFromErrnum(const int32_t errnum) const
{
    return createErrorFromErrnum(m_name, errnum);
}

cxx::error<IpcChannelError> MessageQueue::createErrorFromErrnum(const IpcChannelName_t& name, const int32_t errnum)
{
    switch (errnum)
    {
    case EACCES:
    {
        std::cerr << "access denied to message queue \"" << name << "\"" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::ACCESS_DENIED);
    }
    case EAGAIN:
    {
        std::cerr << "the message queue \"" << name << "\" is full" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::CHANNEL_FULL);
    }
    case ETIMEDOUT:
    {
        // no error message needed since this is a normal use case
        return cxx::error<IpcChannelError>(IpcChannelError::TIMEOUT);
    }
    case EEXIST:
    {
        std::cerr << "message queue \"" << name << "\" already exists" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::CHANNEL_ALREADY_EXISTS);
    }
    case EINVAL:
    {
        std::cerr << "provided invalid arguments for message queue \"" << name << "\"" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_ARGUMENTS);
    }
    case ENOENT:
    {
        std::cerr << "message queue \"" << name << "\" does not exist" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::NO_SUCH_CHANNEL);
    }
    case ENAMETOOLONG:
    {
        std::cerr << "message queue name \"" << name << "\" is too long" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }
    default:
    {
        std::cerr << "internal logic error in message queue \"" << name << "\" occurred [errno: " << errnum << ": "
                  << strerror(errnum) << "]" << std::endl;
        return cxx::error<IpcChannelError>(IpcChannelError::INTERNAL_LOGIC_ERROR);
    }
    }
}

cxx::expected<IpcChannelName_t, IpcChannelError>
MessageQueue::sanitizeIpcChannelName(const IpcChannelName_t& name) noexcept
{
    /// @todo the check for the longest valid queue name is missing
    /// the name for the mqeue is limited by MAX_PATH
    /// The mq_open call is wrapped by smartC to throw then an ENAMETOOLONG error
    /// See: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html
    if (name.empty() || name.size() < SHORTEST_VALID_QUEUE_NAME)
    {
        return cxx::error<IpcChannelError>(IpcChannelError::INVALID_CHANNEL_NAME);
    }
    else if (name.c_str()[0] != '/')
    {
        return cxx::success<IpcChannelName_t>(IpcChannelName_t("/").append(iox::cxx::TruncateToCapacity, name));
    }
    else
    {
        return cxx::success<IpcChannelName_t>(name);
    }
}

} // namespace posix
} // namespace iox
<|endoftext|>


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

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>

#include <salunx.h>
#include <X11/Xatom.h>

#ifdef USE_CDE
#include <cdeint.hxx>
#endif
#include <kdeint.hxx>
#include <saldisp.hxx>
#include <saldata.hxx>
#include <wmadaptor.hxx>

#include <svapp.hxx>
#include <dtsetenum.hxx>

#include <osl/file.h>
#include <osl/process.h>

#include <set>
#include <stdio.h>

// NETBSD has no RTLD_GLOBAL
#ifndef RTLD_GLOBAL
#define DLOPEN_MODE (RTLD_LAZY)
#else
#define DLOPEN_MODE (RTLD_GLOBAL | RTLD_LAZY)
#endif

using namespace rtl;
using namespace vcl_sal;

BOOL bSymbolLoadFailed = FALSE;

DtIntegratorList DtIntegrator::aIntegratorList;
String DtIntegrator::aHomeDir;

DtIntegrator::DtIntegrator() :
        meType( DtGeneric ),
        mnRefCount( 0 ),
        mnSystemLookCommandProcess( -1 )
{
    mpSalDisplay = GetSalData()->GetDisplay();
    mpDisplay = mpSalDisplay->GetDisplay();
    aIntegratorList.Insert( this, LIST_APPEND );
    static const char* pHome = getenv( "HOME" );
    aHomeDir = String( pHome, osl_getThreadTextEncoding() );
}

DtIntegrator::~DtIntegrator()
{
}

DtIntegrator* DtIntegrator::CreateDtIntegrator()
{
    SalDisplay* pSalDisplay = GetSalData()->GetDisplay();
    Display* pDisplay = pSalDisplay->GetDisplay();

    for( unsigned int i = 0; i < aIntegratorList.Count(); i++ )
    {
        DtIntegrator* pIntegrator = aIntegratorList.GetObject( i );
        if( pIntegrator->mpDisplay == pDisplay )
            return pIntegrator;
    }
    /*
     *  #i22061# override desktop detection
     *  if environment variable OOO_FORCE_DESKTOP is set
     *  to one of "cde" "kde" "gnome" then autodetection
     *  is overridden.
     */
    static const char* pOverride = getenv( "OOO_FORCE_DESKTOP" );
    if( pOverride && *pOverride )
    {
        OString aOver( pOverride );
#if USE_CDE
        if( aOver.equalsIgnoreAsciiCase( "cde" ) )
            return new CDEIntegrator();
#endif
        if( aOver.equalsIgnoreAsciiCase( "kde" ) )
            return new KDEIntegrator();
        if( aOver.equalsIgnoreAsciiCase( "none" ) )
            return new DtIntegrator();
    }

    Atom nDtAtom = None;

#ifdef USE_CDE
    void* pLibrary = NULL;

    // check dt type
    // CDE
    nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True );
    if( nDtAtom && ( pLibrary = dlopen( "/usr/dt/lib/libDtSvc.so", DLOPEN_MODE ) ) )
    {
        dlclose( pLibrary );
        return new CDEIntegrator();
    }
#endif

    if( pSalDisplay->getWMAdaptor()->getWindowManagerName().EqualsAscii( "KWin" ) )
        return new KDEIntegrator();

    // default: generic implementation
    return new DtIntegrator();
}

void DtIntegrator::GetSystemLook( AllSettings& rSettings )
{
}
<commit_msg>INTEGRATION: CWS ooo19126 (1.22.450); FILE MERGED 2005/09/05 14:45:42 rt 1.22.450.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dtint.cxx,v $
 *
 *  $Revision: 1.23 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 13:04:22 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>

#include <salunx.h>
#include <X11/Xatom.h>

#ifdef USE_CDE
#include <cdeint.hxx>
#endif
#include <kdeint.hxx>
#include <saldisp.hxx>
#include <saldata.hxx>
#include <wmadaptor.hxx>

#include <svapp.hxx>
#include <dtsetenum.hxx>

#include <osl/file.h>
#include <osl/process.h>

#include <set>
#include <stdio.h>

// NETBSD has no RTLD_GLOBAL
#ifndef RTLD_GLOBAL
#define DLOPEN_MODE (RTLD_LAZY)
#else
#define DLOPEN_MODE (RTLD_GLOBAL | RTLD_LAZY)
#endif

using namespace rtl;
using namespace vcl_sal;

BOOL bSymbolLoadFailed = FALSE;

DtIntegratorList DtIntegrator::aIntegratorList;
String DtIntegrator::aHomeDir;

DtIntegrator::DtIntegrator() :
        meType( DtGeneric ),
        mnRefCount( 0 ),
        mnSystemLookCommandProcess( -1 )
{
    mpSalDisplay = GetSalData()->GetDisplay();
    mpDisplay = mpSalDisplay->GetDisplay();
    aIntegratorList.Insert( this, LIST_APPEND );
    static const char* pHome = getenv( "HOME" );
    aHomeDir = String( pHome, osl_getThreadTextEncoding() );
}

DtIntegrator::~DtIntegrator()
{
}

DtIntegrator* DtIntegrator::CreateDtIntegrator()
{
    SalDisplay* pSalDisplay = GetSalData()->GetDisplay();
    Display* pDisplay = pSalDisplay->GetDisplay();

    for( unsigned int i = 0; i < aIntegratorList.Count(); i++ )
    {
        DtIntegrator* pIntegrator = aIntegratorList.GetObject( i );
        if( pIntegrator->mpDisplay == pDisplay )
            return pIntegrator;
    }
    /*
     *  #i22061# override desktop detection
     *  if environment variable OOO_FORCE_DESKTOP is set
     *  to one of "cde" "kde" "gnome" then autodetection
     *  is overridden.
     */
    static const char* pOverride = getenv( "OOO_FORCE_DESKTOP" );
    if( pOverride && *pOverride )
    {
        OString aOver( pOverride );
#if USE_CDE
        if( aOver.equalsIgnoreAsciiCase( "cde" ) )
            return new CDEIntegrator();
#endif
        if( aOver.equalsIgnoreAsciiCase( "kde" ) )
            return new KDEIntegrator();
        if( aOver.equalsIgnoreAsciiCase( "none" ) )
            return new DtIntegrator();
    }

    Atom nDtAtom = None;

#ifdef USE_CDE
    void* pLibrary = NULL;

    // check dt type
    // CDE
    nDtAtom = XInternAtom( pDisplay, "_DT_WM_READY", True );
    if( nDtAtom && ( pLibrary = dlopen( "/usr/dt/lib/libDtSvc.so", DLOPEN_MODE ) ) )
    {
        dlclose( pLibrary );
        return new CDEIntegrator();
    }
#endif

    if( pSalDisplay->getWMAdaptor()->getWindowManagerName().EqualsAscii( "KWin" ) )
        return new KDEIntegrator();

    // default: generic implementation
    return new DtIntegrator();
}

void DtIntegrator::GetSystemLook( AllSettings& rSettings )
{
}
<|endoftext|>


<commit_before>#include "BlueFilter.h"

COMPONENT_ENTRY(BlueFilter)

BlueFilter::BlueFilter(AudioUnit component)
	: AUEffectBase(component)
{
	TTDSPInit();

	CreateElements();
	Globals()->UseIndexedParameters(kNumberOfParameters);

	SetParameter(kParam_One, kDefaultValue_ParamOne);
	SetAFactoryPresetAsCurrent(kPresets[kPreset_Default]);	// TODO: for some reason, this doesn't seem to be applied...

	#if AU_DEBUG_DISPATCHER
	mDebugDispatcher = new AUDebugDispatcher(this);
	#endif
}

OSStatus BlueFilter::GetParameterValueStrings(AudioUnitScope inScope, AudioUnitParameterID inParameterID, CFArrayRef* outStrings)
{
    return kAudioUnitErr_InvalidProperty;
}

OSStatus BlueFilter::GetParameterInfo(AudioUnitScope inScope, AudioUnitParameterID inParameterID, AudioUnitParameterInfo &outParameterInfo)
{
	OSStatus result = noErr;

	outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
						|	 kAudioUnitParameterFlag_IsReadable;

    if(inScope == kAudioUnitScope_Global){
        switch(inParameterID){
            case kParam_One:
                AUBase::FillInParameterName(outParameterInfo, kParameterOneName, false);
                outParameterInfo.unit = kAudioUnitParameterUnit_Hertz;
                outParameterInfo.minValue = 1.0;
                outParameterInfo.maxValue = 20000.0;
                outParameterInfo.defaultValue = kDefaultValue_ParamOne;
                break;
            default:
                result = kAudioUnitErr_InvalidParameter;
                break;
		}
	}
	else
        result = kAudioUnitErr_InvalidParameter;

	return result;
}

OSStatus BlueFilter::GetPropertyInfo(	AudioUnitPropertyID	inID,
										AudioUnitScope		inScope,
										AudioUnitElement	inElement,
										UInt32&				outDataSize,
										Boolean&			outWritable)
{
	return AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}

OSStatus BlueFilter::GetProperty(	AudioUnitPropertyID inID,
									AudioUnitScope 		inScope,
									AudioUnitElement 	inElement,
									void*				outData )
{
	return AUEffectBase::GetProperty (inID, inScope, inElement, outData);
}

ComponentResult BlueFilter::GetPresets(CFArrayRef* outData) const
{
    if(outData == NULL)
		return noErr;

    CFMutableArrayRef presetsArray = CFArrayCreateMutable(NULL, kNumberPresets, NULL);

    for(int i=0; i<kNumberPresets; ++i)
        CFArrayAppendValue(presetsArray, &kPresets [i]);

    *outData = (CFArrayRef)presetsArray;
    return noErr;
}

OSStatus BlueFilter::NewFactoryPresetSet(const AUPreset &inNewFactoryPreset)
{
    SInt32 chosenPreset = inNewFactoryPreset.presetNumber;

    if(chosenPreset == kPreset_Low || chosenPreset == kPreset_High){
        for(int i = 0; i < kNumberPresets; ++i){
            if(chosenPreset == kPresets[i].presetNumber){
                switch(chosenPreset){
                    case kPreset_Low:
                        SetParameter(kParam_One, kParameter_Preset_Low);
                        break;
                    case kPreset_High:
						SetParameter(kParam_One, kParameter_Preset_High);
                        break;
                }
                SetAFactoryPresetAsCurrent(kPresets[i]);
                return noErr;
            }
        }
    }
    return kAudioUnitErr_InvalidProperty;
}

#pragma mark -
#pragma mark BlueFilter Effect Kernel

void BlueFilter::BlueFilterKernel::Reset()
{
	;// do whatever work is necessary to return the audio unit to its pristine, initialized state.
}

// Process 1 channel of audio, the AU will manage the number of parallel channels by creating multiple kernel instances
void BlueFilter::BlueFilterKernel::Process(	const	Float32*	inSourceP,
													Float32*	inDestP,
                                                    UInt32 		inFramesToProcess,
                                                    UInt32		inNumChannels, // for version 2 AudioUnits inNumChannels is always 1
                                                    bool		&ioSilence )
{
	mInput->setVector(0, inFramesToProcess, (TTFloat32*)inSourceP);
	mOutput->setVectorSizeWithInt(inFramesToProcess);
	mOutput->alloc();

	mButter->setAttributeValue(TT("frequency"),  GetParameter(kParam_One));
	mButter->process(mInput, mOutput);

	mOutput->getVector(0, inFramesToProcess, (TTFloat32*)inDestP);
}

<commit_msg>limiting min. Frequency value to 10 Hz<commit_after>#include "BlueFilter.h"

COMPONENT_ENTRY(BlueFilter)

BlueFilter::BlueFilter(AudioUnit component)
	: AUEffectBase(component)
{
	TTDSPInit();

	CreateElements();
	Globals()->UseIndexedParameters(kNumberOfParameters);

	SetParameter(kParam_One, kDefaultValue_ParamOne);
	SetAFactoryPresetAsCurrent(kPresets[kPreset_Default]);	// TODO: for some reason, this doesn't seem to be applied...

	#if AU_DEBUG_DISPATCHER
	mDebugDispatcher = new AUDebugDispatcher(this);
	#endif
}

OSStatus BlueFilter::GetParameterValueStrings(AudioUnitScope inScope, AudioUnitParameterID inParameterID, CFArrayRef* outStrings)
{
    return kAudioUnitErr_InvalidProperty;
}

OSStatus BlueFilter::GetParameterInfo(AudioUnitScope inScope, AudioUnitParameterID inParameterID, AudioUnitParameterInfo &outParameterInfo)
{
	OSStatus result = noErr;

	outParameterInfo.flags = kAudioUnitParameterFlag_IsWritable
						|	 kAudioUnitParameterFlag_IsReadable;

    if(inScope == kAudioUnitScope_Global){
        switch(inParameterID){
            case kParam_One:
                AUBase::FillInParameterName(outParameterInfo, kParameterOneName, false);
                outParameterInfo.unit = kAudioUnitParameterUnit_Hertz;
                outParameterInfo.minValue = 10.0;
                outParameterInfo.maxValue = 20000.0;
                outParameterInfo.defaultValue = kDefaultValue_ParamOne;
                break;
            default:
                result = kAudioUnitErr_InvalidParameter;
                break;
		}
	}
	else
        result = kAudioUnitErr_InvalidParameter;

	return result;
}

OSStatus BlueFilter::GetPropertyInfo(	AudioUnitPropertyID	inID,
										AudioUnitScope		inScope,
										AudioUnitElement	inElement,
										UInt32&				outDataSize,
										Boolean&			outWritable)
{
	return AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}

OSStatus BlueFilter::GetProperty(	AudioUnitPropertyID inID,
									AudioUnitScope 		inScope,
									AudioUnitElement 	inElement,
									void*				outData )
{
	return AUEffectBase::GetProperty (inID, inScope, inElement, outData);
}

ComponentResult BlueFilter::GetPresets(CFArrayRef* outData) const
{
    if(outData == NULL)
		return noErr;

    CFMutableArrayRef presetsArray = CFArrayCreateMutable(NULL, kNumberPresets, NULL);

    for(int i=0; i<kNumberPresets; ++i)
        CFArrayAppendValue(presetsArray, &kPresets [i]);

    *outData = (CFArrayRef)presetsArray;
    return noErr;
}

OSStatus BlueFilter::NewFactoryPresetSet(const AUPreset &inNewFactoryPreset)
{
    SInt32 chosenPreset = inNewFactoryPreset.presetNumber;

    if(chosenPreset == kPreset_Low || chosenPreset == kPreset_High){
        for(int i = 0; i < kNumberPresets; ++i){
            if(chosenPreset == kPresets[i].presetNumber){
                switch(chosenPreset){
                    case kPreset_Low:
                        SetParameter(kParam_One, kParameter_Preset_Low);
                        break;
                    case kPreset_High:
						SetParameter(kParam_One, kParameter_Preset_High);
                        break;
                }
                SetAFactoryPresetAsCurrent(kPresets[i]);
                return noErr;
            }
        }
    }
    return kAudioUnitErr_InvalidProperty;
}

#pragma mark -
#pragma mark BlueFilter Effect Kernel

void BlueFilter::BlueFilterKernel::Reset()
{
	;// do whatever work is necessary to return the audio unit to its pristine, initialized state.
}

// Process 1 channel of audio, the AU will manage the number of parallel channels by creating multiple kernel instances
void BlueFilter::BlueFilterKernel::Process(	const	Float32*	inSourceP,
													Float32*	inDestP,
                                                    UInt32 		inFramesToProcess,
                                                    UInt32		inNumChannels, // for version 2 AudioUnits inNumChannels is always 1
                                                    bool		&ioSilence )
{
	mInput->setVector(0, inFramesToProcess, (TTFloat32*)inSourceP);
	mOutput->setVectorSizeWithInt(inFramesToProcess);
	mOutput->alloc();

	mButter->setAttributeValue(TT("frequency"),  GetParameter(kParam_One));
	mButter->process(mInput, mOutput);

	mOutput->getVector(0, inFramesToProcess, (TTFloat32*)inDestP);
}

<|endoftext|>


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

#ifndef ROS_INTROSPECTION_HPP
#define ROS_INTROSPECTION_HPP

#include <unordered_set>
#include "ros_type_introspection/stringtree_leaf.hpp"
#include "ros_type_introspection/substitution_rule.hpp"
#include "absl/types/span.h"

namespace RosIntrospection{

struct FlatMessage {

  /// Tree that the StringTreeLeaf(s) refer to.
  const StringTree* tree;

  /// List of all those parsed fields that can be represented by a builtin value different from "string".
  /// This list will be filled by the funtion buildRosFlatType.
  std::vector< std::pair<StringTreeLeaf, Variant> > value;

  /// List of all those parsed fields that can be represented by a builtin value equal to "string".
  /// This list will be filled by the funtion buildRosFlatType.
  std::vector< std::pair<StringTreeLeaf, std::string> > name;

  // Not used yet
  std::vector< std::pair<StringTreeLeaf, std::vector<uint8_t>>> blob;
};

typedef std::vector< std::pair<std::string, Variant> > RenamedValues;

class Parser{

public:
  Parser(): _global_warnings(&std::cerr), _rule_cache_dirty(true) {}

  /**
   * @brief A single message definition will (most probably) generate myltiple ROSMessage(s).
   * In fact the "child" ROSTypes are parsed as well in a recursive and hierarchical way.
   * To make an example, given as input the [geometry_msgs/Pose](http://docs.ros.org/kinetic/api/geometry_msgs/html/msg/Pose.html)
   * the result will be a ROSTypeList containing Pose, Point and Quaternion.
   *
   * @param msg_identifier name to give to the main type to be extracted.
   *
   * @param msg_definition text obtained by either:
   *                       - topic_tools::ShapeShifter::getMessageDefinition()
   *                       - rosbag::MessageInstance::getMessageDefinition()
   *                       - ros::message_traits::Definition< __your_type__ >::value()
   */
  void registerMessageDefinition(const std::string& message_identifier,
                                 const ROSType &main_type,
                                 const std::string& definition);

  /**
   * @brief registerRenamingRules is used to register the renaming rules. You MUST use registerMessageDefinition first.
   *
   * @param type    The type which must be renamed
   * @param rules   A list of rules to apply to the type.
   */
  void registerRenamingRules(const ROSType& type,
                             const std::vector<SubstitutionRule> &rules );

  /**
   * @brief getMessageInfo provides some metadata amout a registered ROSMessage.
   *
   * @param msg_identifier String ID to identify the registered message (use registerMessageDefinition first).
   * @return               Pointer to the instance or nullptr if not registered.
   */
  const ROSMessageInfo* getMessageInfo(const std::string& msg_identifier) const;

  /**
   * @brief getMessageByType provides a pointer to a ROSMessage stored in ROSMessageInfo.
   *
   * @param type   ROSType to be found
   * @param info   Instance or ROSMessageInfo that shall contain the ROSType to be found.
   * @return       Pointer to the instance or nullptr if not registered.
   */
  const ROSMessage *getMessageByType(const ROSType& type, const ROSMessageInfo &info) const;

  /**
   * @brief deserializeIntoFlatContainer takes a raw buffer of memory and extract information from it.
   *  This data is stored in two key/value vectors, FlatMessage::value and FlatMessage::name.
   * It must be noted that the key type is StringTreeLeaf. this type is not particularly user-friendly,
   * but allows a much faster post-processing.
   *
   * IMPORTANT: this approach is not meant to be used with use arrays such as maps, point clouds and images.
   * It would require a ridicoulous amount of memory and, franckly, make little sense.
   * For this reason the argument max_array_size is used.
   *
   * This funtion is almost always followed by applyNameTransform, which provide a more human-readable
   * key-value representation.
   *
   * @param msg_identifier   String ID to identify the registered message (use registerMessageDefinition first).
   * @param buffer           raw memory to be parsed.
   * @param flat_container_output  output to store the result. It is recommended to reuse the same object multiple times to
   *                               avoid memory allocations and speed up the parsing.
   * @param max_array_size   Usually we want to avoid special cases like maps and images, which contain very large arrays.
   *                         max_array_size is used to skip these arrays that are too large.
   *
   * return true if the entire message was parsed or false if parts of the message were
   * skipped because an array has (size > max_array_size)
   */
  bool deserializeIntoFlatContainer(const std::string& msg_identifier,
                                    absl::Span<uint8_t> buffer,
                                    FlatMessage* flat_container_output,
                                    const uint32_t max_array_size ) const;

  /**
   * @brief applyNameTransform is used to create a vector of type RenamedValues from
   *        the vector FlatMessage::value. Additionally, it apply the renaming rules previously
   *        registred using registerRenamingRules.
   *
   * For example if you apply this to [geometry_msgs/Pose](http://docs.ros.org/kinetic/api/geometry_msgs/html/msg/Pose.html)
   * the vector renamed_value.value will contain the following pairs (where ... is the number of that field) :
   *
   *  - Pose/Point/x = ...
   *  - Pose/Point/y = ...
   *  - Pose/Point/z = ...
   *  - Pose/Quaternion/x = ...
   *  - Pose/Quaternion/y = ...
   *  - Pose/Quaternion/z = ...
   *  - Pose.Quaternion/w = ...
   *
   * @param msg_identifier  String ID to identify the registered message (use registerMessageDefinition first).
   * @param container       Source. This instance must be created using deserializeIntoFlatContainer.
   * @param renamed_value   Destination.
   */
  void applyNameTransform(const std::string& msg_identifier,
                          const FlatMessage& container,
                          RenamedValues* renamed_value );

  typedef std::function<void(const ROSType&, absl::Span<uint8_t>&)> VisitingCallback;

  /**
   * @brief applyVisitorToBuffer is used to pass a callback that is invoked every time
   *        a chunk of memory storing an instance of ROSType = monitored_type
   *        is reached.
   *        Note that the VisitingCallback can modify the original message, but can NOT
   *        change its size. This means that strings and vectors can not be change their length.
   *
   * @param msg_identifier    String ID to identify the registered message (use registerMessageDefinition first).
   * @param monitored_type    ROSType that triggers the invokation to the callback
   * @param buffer            Original buffer, passed as mutable since it might be modified.
   * @param callback          The callback.
   */
  void applyVisitorToBuffer(const std::string& msg_identifier, const ROSType &monitored_type,
                            absl::Span<uint8_t> &buffer,
                            VisitingCallback callback) const;

  /// Change where the warning messages are displayed.
  void setWarningsStream(std::ostream* output) { _global_warnings = output; }

private:

  struct RulesCache{
    RulesCache( const SubstitutionRule& r):
      rule( &r ), pattern_head(nullptr), alias_head(nullptr)
    {}
    const SubstitutionRule* rule;
    const StringTreeNode* pattern_head;
    const StringTreeNode* alias_head;
    bool operator==(const RulesCache& other) { return  this->rule == other.rule; }
  };

  std::unordered_map<std::string, ROSMessageInfo> _registered_messages;
  std::unordered_map<ROSType,     std::unordered_set<SubstitutionRule>>   _registered_rules;
  std::unordered_map<std::string, std::vector<RulesCache>>  _rule_caches;

  void updateRuleCache();

  bool _rule_cache_dirty;

  void createTrees(ROSMessageInfo &info, const std::string &type_name) const;

  std::ostream* _global_warnings;

  std::vector<int> _alias_array_pos;
  std::vector<std::string> _formatted_string;
  std::vector<int8_t> _substituted;
};

}

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

#ifndef ROS_INTROSPECTION_HPP
#define ROS_INTROSPECTION_HPP

#include <unordered_set>
#include "ros_type_introspection/stringtree_leaf.hpp"
#include "ros_type_introspection/substitution_rule.hpp"
#include "absl/types/span.h"

namespace RosIntrospection{

struct FlatMessage {

  /// Tree that the StringTreeLeaf(s) refer to.
  const StringTree* tree;

  /// List of all those parsed fields that can be represented by a builtin value different from "string".
  /// This list will be filled by the funtion buildRosFlatType.
  std::vector< std::pair<StringTreeLeaf, Variant> > value;

  /// List of all those parsed fields that can be represented by a builtin value equal to "string".
  /// This list will be filled by the funtion buildRosFlatType.
  std::vector< std::pair<StringTreeLeaf, std::string> > name;

  // Not used yet
  std::vector< std::pair<StringTreeLeaf, std::vector<uint8_t>>> blob;
};

typedef std::vector< std::pair<std::string, Variant> > RenamedValues;

class Parser{

public:
  Parser(): _rule_cache_dirty(true), _global_warnings(&std::cerr) {}

  /**
   * @brief A single message definition will (most probably) generate myltiple ROSMessage(s).
   * In fact the "child" ROSTypes are parsed as well in a recursive and hierarchical way.
   * To make an example, given as input the [geometry_msgs/Pose](http://docs.ros.org/kinetic/api/geometry_msgs/html/msg/Pose.html)
   * the result will be a ROSTypeList containing Pose, Point and Quaternion.
   *
   * @param msg_identifier name to give to the main type to be extracted.
   *
   * @param msg_definition text obtained by either:
   *                       - topic_tools::ShapeShifter::getMessageDefinition()
   *                       - rosbag::MessageInstance::getMessageDefinition()
   *                       - ros::message_traits::Definition< __your_type__ >::value()
   */
  void registerMessageDefinition(const std::string& message_identifier,
                                 const ROSType &main_type,
                                 const std::string& definition);

  /**
   * @brief registerRenamingRules is used to register the renaming rules. You MUST use registerMessageDefinition first.
   *
   * @param type    The type which must be renamed
   * @param rules   A list of rules to apply to the type.
   */
  void registerRenamingRules(const ROSType& type,
                             const std::vector<SubstitutionRule> &rules );

  /**
   * @brief getMessageInfo provides some metadata amout a registered ROSMessage.
   *
   * @param msg_identifier String ID to identify the registered message (use registerMessageDefinition first).
   * @return               Pointer to the instance or nullptr if not registered.
   */
  const ROSMessageInfo* getMessageInfo(const std::string& msg_identifier) const;

  /**
   * @brief getMessageByType provides a pointer to a ROSMessage stored in ROSMessageInfo.
   *
   * @param type   ROSType to be found
   * @param info   Instance or ROSMessageInfo that shall contain the ROSType to be found.
   * @return       Pointer to the instance or nullptr if not registered.
   */
  const ROSMessage *getMessageByType(const ROSType& type, const ROSMessageInfo &info) const;

  /**
   * @brief deserializeIntoFlatContainer takes a raw buffer of memory and extract information from it.
   *  This data is stored in two key/value vectors, FlatMessage::value and FlatMessage::name.
   * It must be noted that the key type is StringTreeLeaf. this type is not particularly user-friendly,
   * but allows a much faster post-processing.
   *
   * IMPORTANT: this approach is not meant to be used with use arrays such as maps, point clouds and images.
   * It would require a ridicoulous amount of memory and, franckly, make little sense.
   * For this reason the argument max_array_size is used.
   *
   * This funtion is almost always followed by applyNameTransform, which provide a more human-readable
   * key-value representation.
   *
   * @param msg_identifier   String ID to identify the registered message (use registerMessageDefinition first).
   * @param buffer           raw memory to be parsed.
   * @param flat_container_output  output to store the result. It is recommended to reuse the same object multiple times to
   *                               avoid memory allocations and speed up the parsing.
   * @param max_array_size   Usually we want to avoid special cases like maps and images, which contain very large arrays.
   *                         max_array_size is used to skip these arrays that are too large.
   *
   * return true if the entire message was parsed or false if parts of the message were
   * skipped because an array has (size > max_array_size)
   */
  bool deserializeIntoFlatContainer(const std::string& msg_identifier,
                                    absl::Span<uint8_t> buffer,
                                    FlatMessage* flat_container_output,
                                    const uint32_t max_array_size ) const;

  /**
   * @brief applyNameTransform is used to create a vector of type RenamedValues from
   *        the vector FlatMessage::value. Additionally, it apply the renaming rules previously
   *        registred using registerRenamingRules.
   *
   * For example if you apply this to [geometry_msgs/Pose](http://docs.ros.org/kinetic/api/geometry_msgs/html/msg/Pose.html)
   * the vector renamed_value.value will contain the following pairs (where ... is the number of that field) :
   *
   *  - Pose/Point/x = ...
   *  - Pose/Point/y = ...
   *  - Pose/Point/z = ...
   *  - Pose/Quaternion/x = ...
   *  - Pose/Quaternion/y = ...
   *  - Pose/Quaternion/z = ...
   *  - Pose.Quaternion/w = ...
   *
   * @param msg_identifier  String ID to identify the registered message (use registerMessageDefinition first).
   * @param container       Source. This instance must be created using deserializeIntoFlatContainer.
   * @param renamed_value   Destination.
   */
  void applyNameTransform(const std::string& msg_identifier,
                          const FlatMessage& container,
                          RenamedValues* renamed_value );

  typedef std::function<void(const ROSType&, absl::Span<uint8_t>&)> VisitingCallback;

  /**
   * @brief applyVisitorToBuffer is used to pass a callback that is invoked every time
   *        a chunk of memory storing an instance of ROSType = monitored_type
   *        is reached.
   *        Note that the VisitingCallback can modify the original message, but can NOT
   *        change its size. This means that strings and vectors can not be change their length.
   *
   * @param msg_identifier    String ID to identify the registered message (use registerMessageDefinition first).
   * @param monitored_type    ROSType that triggers the invokation to the callback
   * @param buffer            Original buffer, passed as mutable since it might be modified.
   * @param callback          The callback.
   */
  void applyVisitorToBuffer(const std::string& msg_identifier, const ROSType &monitored_type,
                            absl::Span<uint8_t> &buffer,
                            VisitingCallback callback) const;

  /// Change where the warning messages are displayed.
  void setWarningsStream(std::ostream* output) { _global_warnings = output; }

private:

  struct RulesCache{
    RulesCache( const SubstitutionRule& r):
      rule( &r ), pattern_head(nullptr), alias_head(nullptr)
    {}
    const SubstitutionRule* rule;
    const StringTreeNode* pattern_head;
    const StringTreeNode* alias_head;
    bool operator==(const RulesCache& other) { return  this->rule == other.rule; }
  };

  std::unordered_map<std::string, ROSMessageInfo> _registered_messages;
  std::unordered_map<ROSType,     std::unordered_set<SubstitutionRule>>   _registered_rules;
  std::unordered_map<std::string, std::vector<RulesCache>>  _rule_caches;

  void updateRuleCache();

  bool _rule_cache_dirty;

  void createTrees(ROSMessageInfo &info, const std::string &type_name) const;

  std::ostream* _global_warnings;

  std::vector<int> _alias_array_pos;
  std::vector<std::string> _formatted_string;
  std::vector<int8_t> _substituted;
};

}

#endif // ROS_INTROSPECTION_HPP
<|endoftext|>