<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: storagehelper.cxx,v $
 * $Revision: 1.12 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_comphelper.hxx"
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XEncryptionProtectedSource.hpp>
#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/IllegalTypeException.hpp>

#include <comphelper/fileformat.h>
#include <comphelper/processfactory.hxx>
#include <comphelper/documentconstants.hxx>

#include <comphelper/storagehelper.hxx>

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

namespace comphelper {

// ----------------------------------------------------------------------
uno::Reference< lang::XSingleServiceFactory > OStorageHelper::GetStorageFactory(
                            const uno::Reference< lang::XMultiServiceFactory >& xSF )
        throw ( uno::Exception )
{
    uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory();
    if ( !xFactory.is() )
        throw uno::RuntimeException();

    uno::Reference < lang::XSingleServiceFactory > xStorageFactory(
                    xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.embed.StorageFactory" ) ),
                    uno::UNO_QUERY );

    if ( !xStorageFactory.is() )
        throw uno::RuntimeException();

    return xStorageFactory;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetTemporaryStorage(
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstance(),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL(
            const ::rtl::OUString& aURL,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[0] <<= aURL;
    aArgs[1] <<= nStorageMode;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromInputStream(
            const uno::Reference < io::XInputStream >& xStream,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= embed::ElementModes::READ;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromStream(
            const uno::Reference < io::XStream >& xStream,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= nStorageMode;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
void OStorageHelper::CopyInputToOutput(
            const uno::Reference< io::XInputStream >& xInput,
            const uno::Reference< io::XOutputStream >& xOutput )
    throw ( uno::Exception )
{
    static const sal_Int32 nConstBufferSize = 32000;

    sal_Int32 nRead;
    uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );

    do
    {
        nRead = xInput->readBytes ( aSequence, nConstBufferSize );
        if ( nRead < nConstBufferSize )
        {
            uno::Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead );
            xOutput->writeBytes ( aTempBuf );
        }
        else
            xOutput->writeBytes ( aSequence );
    }
    while ( nRead == nConstBufferSize );
}

// ----------------------------------------------------------------------
uno::Reference< io::XInputStream > OStorageHelper::GetInputStreamFromURL(
            const ::rtl::OUString& aURL,
            const uno::Reference< lang::XMultiServiceFactory >& xSF )
    throw ( uno::Exception )
{
    uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory();
    if ( !xFactory.is() )
        throw uno::RuntimeException();

    uno::Reference < ::com::sun::star::ucb::XSimpleFileAccess > xTempAccess(
            xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
            uno::UNO_QUERY );

    if ( !xTempAccess.is() )
        throw uno::RuntimeException();

    uno::Reference< io::XInputStream > xInputStream = xTempAccess->openFileRead( aURL );
    if ( !xInputStream.is() )
        throw uno::RuntimeException();

    return xInputStream;
}

// ----------------------------------------------------------------------
void OStorageHelper::SetCommonStoragePassword(
            const uno::Reference< embed::XStorage >& xStorage,
            const ::rtl::OUString& aPass )
    throw ( uno::Exception )
{
    uno::Reference< embed::XEncryptionProtectedSource > xEncrSet( xStorage, uno::UNO_QUERY );
    if ( !xEncrSet.is() )
        throw io::IOException(); // TODO

    xEncrSet->setEncryptionPassword( aPass );
}

// ----------------------------------------------------------------------
sal_Int32 OStorageHelper::GetXStorageFormat(
            const uno::Reference< embed::XStorage >& xStorage )
        throw ( uno::Exception )
{
    uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW );

    ::rtl::OUString aMediaType;
    xStorProps->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ) >>= aMediaType;

    sal_Int32 nResult = 0;

    // TODO/LATER: the filter configuration could be used to detect it later, or batter a special service
    if (
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_ASCII       ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_WEB_ASCII   ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_DRAW_ASCII         ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_IMPRESS_ASCII      ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_CALC_ASCII         ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_CHART_ASCII        ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_MATH_ASCII         )
       )
    {
        nResult = SOFFICE_FILEFORMAT_60;
    }
    else
    if (
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII        ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII     ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII       ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII     ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII        ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII     ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII       ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII     )
       )
    {
        nResult = SOFFICE_FILEFORMAT_8;
    }
    else
    {
        // the mediatype is not known
        throw beans::IllegalTypeException();
    }

    return nResult;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetTemporaryStorageOfFormat(
            const ::rtl::OUString& aFormat,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Reference< lang::XMultiServiceFactory > xFactoryToUse = xFactory.is() ? xFactory : ::comphelper::getProcessServiceFactory();
    if ( !xFactoryToUse.is() )
        throw uno::RuntimeException();

    uno::Reference< io::XStream > xTmpStream(
        xFactoryToUse->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ),
        uno::UNO_QUERY_THROW );

    return GetStorageOfFormatFromStream( aFormat, xTmpStream, embed::ElementModes::READWRITE, xFactoryToUse );
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromURL(
            const ::rtl::OUString& aFormat,
            const ::rtl::OUString& aURL,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
    aProps[0].Value <<= aFormat;

    uno::Sequence< uno::Any > aArgs( 3 );
    aArgs[0] <<= aURL;
    aArgs[1] <<= nStorageMode;
    aArgs[2] <<= aProps;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromInputStream(
            const ::rtl::OUString& aFormat,
            const uno::Reference < io::XInputStream >& xStream,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
    aProps[0].Value <<= aFormat;

    uno::Sequence< uno::Any > aArgs( 3 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= embed::ElementModes::READ;
    aArgs[2] <<= aProps;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromStream(
            const ::rtl::OUString& aFormat,
            const uno::Reference < io::XStream >& xStream,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
    aProps[0].Value <<= aFormat;

    uno::Sequence< uno::Any > aArgs( 3 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= nStorageMode;
    aArgs[2] <<= aProps;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

}

<commit_msg>INTEGRATION: CWS odfmetadata (1.12.34); FILE MERGED 2008/06/11 16:26:59 mst 1.12.34.1: - comphelper/inc/comphelper/storagehelper.hxx,   comphelper/source/misc/storagehelper.cxx:   + new static methods GetFileSystemStorageFactory, GetStorageFromURL2<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: storagehelper.cxx,v $
 * $Revision: 1.13 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_comphelper.hxx"
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XEncryptionProtectedSource.hpp>
#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/IllegalTypeException.hpp>

#include <ucbhelper/content.hxx>

#include <comphelper/fileformat.h>
#include <comphelper/processfactory.hxx>
#include <comphelper/documentconstants.hxx>

#include <comphelper/storagehelper.hxx>

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

namespace comphelper {

// ----------------------------------------------------------------------
uno::Reference< lang::XSingleServiceFactory > OStorageHelper::GetStorageFactory(
                            const uno::Reference< lang::XMultiServiceFactory >& xSF )
        throw ( uno::Exception )
{
    uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory();
    if ( !xFactory.is() )
        throw uno::RuntimeException();

    uno::Reference < lang::XSingleServiceFactory > xStorageFactory(
                    xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.embed.StorageFactory" ) ),
                    uno::UNO_QUERY );

    if ( !xStorageFactory.is() )
        throw uno::RuntimeException();

    return xStorageFactory;
}

// ----------------------------------------------------------------------
uno::Reference< lang::XSingleServiceFactory > OStorageHelper::GetFileSystemStorageFactory(
                            const uno::Reference< lang::XMultiServiceFactory >& xSF )
        throw ( uno::Exception )
{
    uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory();
    if ( !xFactory.is() )
        throw uno::RuntimeException();

    uno::Reference < lang::XSingleServiceFactory > xStorageFactory(
                    xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.embed.FileSystemStorageFactory" ) ),
                    uno::UNO_QUERY );

    if ( !xStorageFactory.is() )
        throw uno::RuntimeException();

    return xStorageFactory;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetTemporaryStorage(
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstance(),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL(
            const ::rtl::OUString& aURL,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[0] <<= aURL;
    aArgs[1] <<= nStorageMode;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL2(
            const ::rtl::OUString& aURL,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[0] <<= aURL;
    aArgs[1] <<= nStorageMode;

    uno::Reference< lang::XSingleServiceFactory > xFact;
    try {
        ::ucbhelper::Content aCntnt( aURL,
            uno::Reference< ::com::sun::star::ucb::XCommandEnvironment > () );
        if (aCntnt.isDocument()) {
            xFact = GetStorageFactory( xFactory );
        } else {
            xFact = GetFileSystemStorageFactory( xFactory );
        }
    } catch (uno::Exception &) { }

    if (!xFact.is()) throw uno::RuntimeException();

    uno::Reference< embed::XStorage > xTempStorage(
        xFact->createInstanceWithArguments( aArgs ), uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromInputStream(
            const uno::Reference < io::XInputStream >& xStream,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= embed::ElementModes::READ;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromStream(
            const uno::Reference < io::XStream >& xStream,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< uno::Any > aArgs( 2 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= nStorageMode;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
void OStorageHelper::CopyInputToOutput(
            const uno::Reference< io::XInputStream >& xInput,
            const uno::Reference< io::XOutputStream >& xOutput )
    throw ( uno::Exception )
{
    static const sal_Int32 nConstBufferSize = 32000;

    sal_Int32 nRead;
    uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize );

    do
    {
        nRead = xInput->readBytes ( aSequence, nConstBufferSize );
        if ( nRead < nConstBufferSize )
        {
            uno::Sequence < sal_Int8 > aTempBuf ( aSequence.getConstArray(), nRead );
            xOutput->writeBytes ( aTempBuf );
        }
        else
            xOutput->writeBytes ( aSequence );
    }
    while ( nRead == nConstBufferSize );
}

// ----------------------------------------------------------------------
uno::Reference< io::XInputStream > OStorageHelper::GetInputStreamFromURL(
            const ::rtl::OUString& aURL,
            const uno::Reference< lang::XMultiServiceFactory >& xSF )
    throw ( uno::Exception )
{
    uno::Reference< lang::XMultiServiceFactory > xFactory = xSF.is() ? xSF : ::comphelper::getProcessServiceFactory();
    if ( !xFactory.is() )
        throw uno::RuntimeException();

    uno::Reference < ::com::sun::star::ucb::XSimpleFileAccess > xTempAccess(
            xFactory->createInstance ( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
            uno::UNO_QUERY );

    if ( !xTempAccess.is() )
        throw uno::RuntimeException();

    uno::Reference< io::XInputStream > xInputStream = xTempAccess->openFileRead( aURL );
    if ( !xInputStream.is() )
        throw uno::RuntimeException();

    return xInputStream;
}

// ----------------------------------------------------------------------
void OStorageHelper::SetCommonStoragePassword(
            const uno::Reference< embed::XStorage >& xStorage,
            const ::rtl::OUString& aPass )
    throw ( uno::Exception )
{
    uno::Reference< embed::XEncryptionProtectedSource > xEncrSet( xStorage, uno::UNO_QUERY );
    if ( !xEncrSet.is() )
        throw io::IOException(); // TODO

    xEncrSet->setEncryptionPassword( aPass );
}

// ----------------------------------------------------------------------
sal_Int32 OStorageHelper::GetXStorageFormat(
            const uno::Reference< embed::XStorage >& xStorage )
        throw ( uno::Exception )
{
    uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW );

    ::rtl::OUString aMediaType;
    xStorProps->getPropertyValue( ::rtl::OUString::createFromAscii( "MediaType" ) ) >>= aMediaType;

    sal_Int32 nResult = 0;

    // TODO/LATER: the filter configuration could be used to detect it later, or batter a special service
    if (
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_ASCII       ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_WEB_ASCII   ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_DRAW_ASCII         ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_IMPRESS_ASCII      ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_CALC_ASCII         ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_CHART_ASCII        ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_VND_SUN_XML_MATH_ASCII         )
       )
    {
        nResult = SOFFICE_FILEFORMAT_60;
    }
    else
    if (
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII        ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII     ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_CHART_ASCII       ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII     ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART_ASCII    ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII        ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII     ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE_ASCII       ) ||
        aMediaType.equalsIgnoreAsciiCaseAscii(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII     )
       )
    {
        nResult = SOFFICE_FILEFORMAT_8;
    }
    else
    {
        // the mediatype is not known
        throw beans::IllegalTypeException();
    }

    return nResult;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetTemporaryStorageOfFormat(
            const ::rtl::OUString& aFormat,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Reference< lang::XMultiServiceFactory > xFactoryToUse = xFactory.is() ? xFactory : ::comphelper::getProcessServiceFactory();
    if ( !xFactoryToUse.is() )
        throw uno::RuntimeException();

    uno::Reference< io::XStream > xTmpStream(
        xFactoryToUse->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ),
        uno::UNO_QUERY_THROW );

    return GetStorageOfFormatFromStream( aFormat, xTmpStream, embed::ElementModes::READWRITE, xFactoryToUse );
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromURL(
            const ::rtl::OUString& aFormat,
            const ::rtl::OUString& aURL,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
    throw ( uno::Exception )
{
    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
    aProps[0].Value <<= aFormat;

    uno::Sequence< uno::Any > aArgs( 3 );
    aArgs[0] <<= aURL;
    aArgs[1] <<= nStorageMode;
    aArgs[2] <<= aProps;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromInputStream(
            const ::rtl::OUString& aFormat,
            const uno::Reference < io::XInputStream >& xStream,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
    aProps[0].Value <<= aFormat;

    uno::Sequence< uno::Any > aArgs( 3 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= embed::ElementModes::READ;
    aArgs[2] <<= aProps;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

// ----------------------------------------------------------------------
uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromStream(
            const ::rtl::OUString& aFormat,
            const uno::Reference < io::XStream >& xStream,
            sal_Int32 nStorageMode,
            const uno::Reference< lang::XMultiServiceFactory >& xFactory )
        throw ( uno::Exception )
{
    uno::Sequence< beans::PropertyValue > aProps( 1 );
    aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StorageFormat" ) );
    aProps[0].Value <<= aFormat;

    uno::Sequence< uno::Any > aArgs( 3 );
    aArgs[0] <<= xStream;
    aArgs[1] <<= nStorageMode;
    aArgs[2] <<= aProps;

    uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( xFactory )->createInstanceWithArguments( aArgs ),
                                                    uno::UNO_QUERY );
    if ( !xTempStorage.is() )
        throw uno::RuntimeException();

    return xTempStorage;
}

}

<|endoftext|>


<commit_before>#include "defines.h"
#include "ListHelper.h"

void DcxListHelper::getItemRange(const TString &tsItems, const int nItemCnt, int *iStart_range, int *iEnd_range)
{
	std::tie(*iStart_range, *iEnd_range) = getItemRange(tsItems, nItemCnt);
}

std::pair<int, int> DcxListHelper::getItemRange(const TString &tsItems, const int nItemCnt)
{
	int iStart = 0, iEnd = 0;
	if (tsItems.numtok(TEXT('-')) == 2) {
		iStart = tsItems.getfirsttok(1, TEXT('-')).to_int() - 1;
		iEnd = tsItems.getnexttok(TEXT('-')).to_int() - 1;

		if (iEnd == -1)	// special case
			iEnd = nItemCnt - 1;
	}
	else {
		iEnd = tsItems.to_int() - 1;

		if (iEnd == -1)	// special case
			iStart = iEnd = nItemCnt - 1;
		else
			iStart = iEnd;
	}
	//return std::make_pair(iStart, iEnd);
	return { iStart, iEnd };
}

bool DcxListHelper::matchItemText(const refString<TCHAR, MIRC_BUFFER_SIZE_CCH> &sItemText, const TString &search, const DcxSearchTypes &SearchType)
{
	switch (SearchType)
	{
	case DcxSearchTypes::SEARCH_R:	// regex match
		return isRegexMatch(sItemText, search.to_chr());
	case DcxSearchTypes::SEARCH_W:	// wildcard match
		return TString(sItemText.data()).iswm(search);
	case DcxSearchTypes::SEARCH_E:   // exact match
		return sItemText == search.to_chr();
	default:
		return false;
	}
}

const DcxSearchTypes DcxListHelper::StringToSearchType(const TString & tsType) noexcept
{
	const XSwitchFlags xFlags(tsType);

	return FlagsToSearchType(xFlags);
}

const DcxSearchTypes DcxListHelper::CharToSearchType(const TCHAR & cType) noexcept
{
	auto SearchType = DcxSearchTypes::SEARCH_E;

	if ((cType == TEXT('R')) || (cType == TEXT('r')))
		SearchType = DcxSearchTypes::SEARCH_R;
	else if ((cType == TEXT('W')) || (cType == TEXT('w')))
		SearchType = DcxSearchTypes::SEARCH_W;

	return SearchType;
}

const DcxSearchTypes DcxListHelper::FlagsToSearchType(const XSwitchFlags & xFlags) noexcept
{
	auto SearchType = DcxSearchTypes::SEARCH_E;	// plain text exact match delete

	if (xFlags[TEXT('w')] || xFlags[TEXT('W')])
		SearchType = DcxSearchTypes::SEARCH_W;	// wildcard delete
	else if (xFlags[TEXT('r')] || xFlags[TEXT('R')])
		SearchType = DcxSearchTypes::SEARCH_R;	// regex delete

	return SearchType;
}
<commit_msg>[general] fixed SEARCH_E failing.<commit_after>#include "defines.h"
#include "ListHelper.h"

void DcxListHelper::getItemRange(const TString &tsItems, const int nItemCnt, int *iStart_range, int *iEnd_range)
{
	std::tie(*iStart_range, *iEnd_range) = getItemRange(tsItems, nItemCnt);
}

std::pair<int, int> DcxListHelper::getItemRange(const TString &tsItems, const int nItemCnt)
{
	int iStart = 0, iEnd = 0;
	if (tsItems.numtok(TEXT('-')) == 2) {
		iStart = tsItems.getfirsttok(1, TEXT('-')).to_int() - 1;
		iEnd = tsItems.getnexttok(TEXT('-')).to_int() - 1;

		if (iEnd == -1)	// special case
			iEnd = nItemCnt - 1;
	}
	else {
		iEnd = tsItems.to_int() - 1;

		if (iEnd == -1)	// special case
			iStart = iEnd = nItemCnt - 1;
		else
			iStart = iEnd;
	}
	//return std::make_pair(iStart, iEnd);
	return { iStart, iEnd };
}

bool DcxListHelper::matchItemText(const refString<TCHAR, MIRC_BUFFER_SIZE_CCH> &sItemText, const TString &search, const DcxSearchTypes &SearchType)
{
	switch (SearchType)
	{
	case DcxSearchTypes::SEARCH_R:	// regex match
		return isRegexMatch(sItemText, search.to_chr());
	case DcxSearchTypes::SEARCH_W:	// wildcard match
		return TString(sItemText.data()).iswm(search);
	case DcxSearchTypes::SEARCH_E:   // exact match
		return search == sItemText;
	default:
		return false;
	}
}

const DcxSearchTypes DcxListHelper::StringToSearchType(const TString & tsType) noexcept
{
	const XSwitchFlags xFlags(tsType);

	return FlagsToSearchType(xFlags);
}

const DcxSearchTypes DcxListHelper::CharToSearchType(const TCHAR & cType) noexcept
{
	//auto SearchType = DcxSearchTypes::SEARCH_E;
	//if ((cType == TEXT('R')) || (cType == TEXT('r')))
	//	SearchType = DcxSearchTypes::SEARCH_R;
	//else if ((cType == TEXT('W')) || (cType == TEXT('w')))
	//	SearchType = DcxSearchTypes::SEARCH_W;
	//return SearchType;

	switch (cType)
	{
	case TEXT('R'):
	case TEXT('r'):
		return DcxSearchTypes::SEARCH_R;
	case TEXT('W'):
	case TEXT('w'):
		return DcxSearchTypes::SEARCH_W;
	default:
		return DcxSearchTypes::SEARCH_E;
	}
}

const DcxSearchTypes DcxListHelper::FlagsToSearchType(const XSwitchFlags & xFlags) noexcept
{
	auto SearchType = DcxSearchTypes::SEARCH_E;	// plain text exact match delete

	if (xFlags[TEXT('w')] || xFlags[TEXT('W')])
		SearchType = DcxSearchTypes::SEARCH_W;	// wildcard delete
	else if (xFlags[TEXT('r')] || xFlags[TEXT('R')])
		SearchType = DcxSearchTypes::SEARCH_R;	// regex delete

	return SearchType;
}
<|endoftext|>


<commit_before>#include <sys/time.h>

#include "thread_private.h"
#include "parameters.h"
#include "exception.h"

#define NUM_PAGES (40960 * nthreads)

bool align_req = false;
int align_size = PAGE_SIZE;
bool use_aio = false;

extern bool verify_read_content;

void check_read_content(char *buf, int size, off_t off)
{
	// I assume the space in the buffer is larger than 8 bytes.
	off_t aligned_off = off & (~(sizeof(off_t) - 1));
	long data[2];
	data[0] = aligned_off / sizeof(off_t);
	data[1] = aligned_off / sizeof(off_t) + 1;
	long expected = 0;
	int copy_size = size < (int) sizeof(off_t) ? size : (int) sizeof(off_t);
	memcpy(&expected, ((char *) data) + (off - aligned_off), copy_size);
	long read_value = 0;
	memcpy(&read_value, buf, copy_size);
	if(read_value != expected)
		printf("%ld %ld\n", read_value, expected);
	assert(read_value == expected);
}

void create_write_data(char *buf, int size, off_t off)
{
	off_t aligned_start = off & (~(sizeof(off_t) - 1));
	off_t aligned_end = (off + size) & (~(sizeof(off_t) - 1));
	long start_data = aligned_start / sizeof(off_t);
	long end_data = aligned_end / sizeof(off_t);

	/* If all data is in one 8-byte word. */
	if (aligned_start == aligned_end) {
		memcpy(buf, ((char *) &start_data) + (off - aligned_start), size);
		return;
	}

	int first_size =  (int)(sizeof(off_t) - (off - aligned_start));
	int last_size = (int) (off + size - aligned_end);

	if (first_size == sizeof(off_t))
		first_size = 0;
	if (first_size)
		memcpy(buf, ((char *) &start_data) + (off - aligned_start),
				first_size);
	// Make each buffer written to SSDs different, so it's hard for SSDs
	// to do some tricks on it.
	struct timeval zero = {0, 0};
	long diff = time_diff_us(zero, global_start);
	for (int i = first_size; i < aligned_end - off; i += sizeof(off_t)) {
		*((long *) (buf + i)) = (off + i) / sizeof(off_t) + diff;
	}
	if (aligned_end > aligned_start
			|| (aligned_end == aligned_start && first_size == 0)) {
		if (last_size)
			memcpy(buf + (aligned_end - off), (char *) &end_data, last_size);
	}

	check_read_content(buf, size, off);
}

class cleanup_callback: public callback
{
	rand_buf *buf;
	ssize_t read_bytes;
	int thread_id;
	thread_private *thread;
public:
	cleanup_callback(rand_buf *buf, int idx, thread_private *thread) {
		this->buf = buf;
		read_bytes = 0;
		this->thread_id = idx;
		this->thread = thread;
	}

	int invoke(io_request *rqs[], int num) {
		for (int i = 0; i < num; i++) {
			io_request *rq = rqs[i];
			extern bool verify_read_content;
			if (rq->get_access_method() == READ && verify_read_content) {
				off_t off = rq->get_offset();
				for (int i = 0; i < rq->get_num_bufs(); i++) {
					check_read_content(rq->get_buf(i), rq->get_buf_size(i), off);
					off += rq->get_buf_size(i);
				}
			}
			for (int i = 0; i < rq->get_num_bufs(); i++)
				buf->free_entry(rq->get_buf(i));
			read_bytes += rq->get_size();
		}
#ifdef STATISTICS
		thread->num_completes.inc(num);
		thread->num_pending.dec(num);
#endif
		return 0;
	}

	ssize_t get_size() {
		return read_bytes;
	}
};

ssize_t thread_private::get_read_bytes() {
	if (cb)
		return cb->get_size();
	else
		return read_bytes;
}

int thread_private::thread_init() {
	attach2cpu();
	io->init();

	extern int buf_size;
	rand_buf *buf = new rand_buf(NUM_PAGES / (nthreads
				// TODO maybe I should set the right entry size for a buffer.
				// If each access size is irregular, I'll break each access
				// into pages so each access is no larger than a page, so it
				// should workl fine.
				/ NUM_NODES) * PAGE_SIZE, buf_size);
	this->buf = buf;
	if (io->support_aio()) {
		cb = new cleanup_callback(buf, idx, this);
		io->set_callback(cb);
	}
	return 0;
}

int thread_private::run()
{
	int node_id = io->get_node_id();
	ssize_t ret = -1;
	gettimeofday(&start_time, NULL);
	io_request reqs[NUM_REQS_BY_USER];
	char *entry = NULL;
	if (!io->support_aio())
		use_aio = false;
	if (!use_aio) {
		extern int buf_size;
		entry = (char *) valloc(buf_size);
	}
	while (gen->has_next()) {
		if (use_aio) {
			int i;
			for (i = 0; i < NUM_REQS_BY_USER && gen->has_next(); ) {
				workload_t workload = gen->next();
				int access_method = workload.read ? READ : WRITE;
				off_t off = workload.off;
				int size = workload.size;
				if (align_req) {
					off = ROUND(off, align_size);
					size = ROUNDUP(off + size, align_size)
						- ROUND(off, align_size);
				}
				/*
				 * If the size of the request is larger than a page size,
				 * and the user explicitly wants to use multibuf requests.
				 */
				if (buf_type == MULTI_BUF) {
					throw unsupported_exception();
#if 0
					assert(off % PAGE_SIZE == 0);
					int num_vecs = size / PAGE_SIZE;
					reqs[i].init(off, io, access_method, node_id);
					assert(buf->get_entry_size() >= PAGE_SIZE);
					for (int k = 0; k < num_vecs; k++) {
						reqs[i].add_buf(buf->next_entry(PAGE_SIZE), PAGE_SIZE);
					}
					i++;
#endif
				}
				else if (buf_type == SINGLE_SMALL_BUF) {
again:
					while (size > 0 && i < NUM_REQS_BY_USER) {
						off_t next_off = ROUNDUP_PAGE(off + 1);
						if (next_off > off + size)
							next_off = off + size;
						char *p = buf->next_entry(next_off - off);
						if (p == NULL) {
							fprintf(stderr, "there is no empty buffer left\n");
							break;
						}
						if (access_method == WRITE && verify_read_content)
							create_write_data(p, next_off - off, off);
						reqs[i].init(p, off, next_off - off, access_method,
								io, node_id);
						size -= next_off - off;
						off = next_off;
						i++;
					}
					if (size > 0) {
						io->access(reqs, i);
#ifdef STATISTICS
						num_pending.inc(i);
#endif
						num_accesses += i;
						i = 0;
						goto again;
					}
				}
				else {
					char *p = buf->next_entry(size);
					if (p == NULL) {
						fprintf(stderr, "allocate LARGE: there is no empty buffer left\n");
						break;
					}
					if (access_method == WRITE && verify_read_content)
						create_write_data(p, size, off);
					reqs[i++].init(p, off, size, access_method, io, node_id);
				}
			}
			io->access(reqs, i);
			if (ret < 0) {
				perror("access_vector");
				exit(1);
			}
			num_accesses += i;
#ifdef STATISTICS
			int curr = num_pending.inc(i);
			if (max_num_pending < curr)
				max_num_pending = curr;
			if (num_accesses % 100 == 0) {
				num_sampling++;
				tot_num_pending += curr;
			}
#endif
		}
		else {
			workload_t workload = gen->next();
			off_t off = workload.off;
			int access_method = workload.read ? READ : WRITE;
			int entry_size = workload.size;
			if (align_req) {
				off = ROUND(off, align_size);
				entry_size = ROUNDUP(off + entry_size, align_size)
					- ROUND(off, align_size);
			}

			if (buf_type == SINGLE_SMALL_BUF) {
				while (entry_size > 0) {
					/*
					 * generate the data for writing the file,
					 * so the data in the file isn't changed.
					 */
					if (access_method == WRITE && verify_read_content) {
						create_write_data(entry, entry_size, off);
					}
					// There is at least one byte we need to access in the page.
					// By adding 1 and rounding up the offset, we'll get the next page
					// behind the current offset.
					off_t next_off = ROUNDUP_PAGE(off + 1);
					if (next_off > off + entry_size)
						next_off = off + entry_size;
					io_status status = io->access(entry, off, next_off - off,
							access_method);
					if (status == IO_OK) {
						num_accesses++;
						if (access_method == READ && verify_read_content) {
							check_read_content(entry, next_off - off, off);
						}
						read_bytes += ret;
					}
					if (status == IO_FAIL) {
						perror("access");
						exit(1);
					}
					entry_size -= next_off - off;
					off = next_off;
				}
			}
			else {
				if (access_method == WRITE && verify_read_content) {
					create_write_data(entry, entry_size, off);
				}
				io_status status = io->access(entry, off, entry_size,
						access_method);
				if (status == IO_OK) {
					num_accesses++;
					if (access_method == READ && verify_read_content) {
						check_read_content(entry, entry_size, off);
					}
					read_bytes += ret;
				}
				if (status == IO_FAIL) {
					perror("access");
					exit(1);
				}
			}
		}
	}
	io->cleanup();
	printf("thread %d exits\n", idx);
	gettimeofday(&end_time, NULL);
	return 0;
}

int thread_private::attach2cpu()
{
#if NCPUS > 0
	cpu_set_t cpuset;
	pthread_t thread = pthread_self();
	CPU_ZERO(&cpuset);
	int cpu_num = idx % NCPUS;
	CPU_SET(cpu_num, &cpuset);
	int ret = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
	if (ret != 0) {
		perror("pthread_setaffinity_np");
		exit(1);
	}
	printf("attach thread %d to CPU %d\n", idx, cpu_num);
	return ret;
#else
	return -1;
#endif
}

static void *rand_read(void *arg)
{
	thread_private *priv = (thread_private *) arg;

	// We put the thread at the specified NUMA node at the very beginning
	// to make sure all data created in this thread will be on the specified
	// node.
	int node_id = priv->get_io()->get_node_id();
	time_t curr_time = time(NULL);
	printf("run thread rand_read: pid: %d, tid: %ld, on node %d at %s",
			getpid(), gettid(), node_id, ctime(&curr_time));
	bind2node_id(node_id);

	priv->thread_init();
	priv->run();
	return NULL;
}

#ifdef USE_PROCESS
static int process_create(pid_t *pid, void (*func)(void *), void *priv)
{
	pid_t id = fork();

	if (id < 0)
		return -1;

	if (id == 0) {	// child
		func(priv);
		exit(0);
	}

	if (id > 0)
		*pid = id;
	return 0;
}

static int process_join(pid_t pid)
{
	int status;
	pid_t ret = waitpid(pid, &status, 0);
	return ret < 0 ? ret : 0;
}
#endif

int thread_private::start_thread()
{
	int ret;
#ifdef USE_PROCESS
	ret = process_create(&id, rand_read, (void *) this);
#else
	ret = pthread_create(&id, NULL, rand_read, (void *) this);
#endif
	return ret;
}

int thread_private::wait_thread_end()
{
	int ret;
#ifdef USE_PROCESS
	ret = process_join(id);
#else
	ret = pthread_join(id, NULL);
#endif
	return ret;
}
<commit_msg>Fix the test program for asynchronous interface.<commit_after>#include <sys/time.h>

#include "thread_private.h"
#include "parameters.h"
#include "exception.h"

#define NUM_PAGES (40960 * nthreads)

bool align_req = false;
int align_size = PAGE_SIZE;
bool use_aio = false;

extern bool verify_read_content;

void check_read_content(char *buf, int size, off_t off)
{
	// I assume the space in the buffer is larger than 8 bytes.
	off_t aligned_off = off & (~(sizeof(off_t) - 1));
	long data[2];
	data[0] = aligned_off / sizeof(off_t);
	data[1] = aligned_off / sizeof(off_t) + 1;
	long expected = 0;
	int copy_size = size < (int) sizeof(off_t) ? size : (int) sizeof(off_t);
	memcpy(&expected, ((char *) data) + (off - aligned_off), copy_size);
	long read_value = 0;
	memcpy(&read_value, buf, copy_size);
	if(read_value != expected)
		printf("%ld %ld\n", read_value, expected);
	assert(read_value == expected);
}

void create_write_data(char *buf, int size, off_t off)
{
	off_t aligned_start = off & (~(sizeof(off_t) - 1));
	off_t aligned_end = (off + size) & (~(sizeof(off_t) - 1));
	long start_data = aligned_start / sizeof(off_t);
	long end_data = aligned_end / sizeof(off_t);

	/* If all data is in one 8-byte word. */
	if (aligned_start == aligned_end) {
		memcpy(buf, ((char *) &start_data) + (off - aligned_start), size);
		return;
	}

	int first_size =  (int)(sizeof(off_t) - (off - aligned_start));
	int last_size = (int) (off + size - aligned_end);

	if (first_size == sizeof(off_t))
		first_size = 0;
	if (first_size)
		memcpy(buf, ((char *) &start_data) + (off - aligned_start),
				first_size);
	// Make each buffer written to SSDs different, so it's hard for SSDs
	// to do some tricks on it.
	struct timeval zero = {0, 0};
	long diff = time_diff_us(zero, global_start);
	for (int i = first_size; i < aligned_end - off; i += sizeof(off_t)) {
		*((long *) (buf + i)) = (off + i) / sizeof(off_t) + diff;
	}
	if (aligned_end > aligned_start
			|| (aligned_end == aligned_start && first_size == 0)) {
		if (last_size)
			memcpy(buf + (aligned_end - off), (char *) &end_data, last_size);
	}

	check_read_content(buf, size, off);
}

class cleanup_callback: public callback
{
	rand_buf *buf;
	ssize_t read_bytes;
	int thread_id;
	thread_private *thread;
public:
	cleanup_callback(rand_buf *buf, int idx, thread_private *thread) {
		this->buf = buf;
		read_bytes = 0;
		this->thread_id = idx;
		this->thread = thread;
	}

	int invoke(io_request *rqs[], int num) {
		for (int i = 0; i < num; i++) {
			io_request *rq = rqs[i];
			extern bool verify_read_content;
			if (rq->get_access_method() == READ && verify_read_content) {
				off_t off = rq->get_offset();
				for (int i = 0; i < rq->get_num_bufs(); i++) {
					check_read_content(rq->get_buf(i), rq->get_buf_size(i), off);
					off += rq->get_buf_size(i);
				}
			}
			for (int i = 0; i < rq->get_num_bufs(); i++)
				buf->free_entry(rq->get_buf(i));
			read_bytes += rq->get_size();
		}
#ifdef STATISTICS
		thread->num_completes.inc(num);
		thread->num_pending.dec(num);
#endif
		return 0;
	}

	ssize_t get_size() {
		return read_bytes;
	}
};

ssize_t thread_private::get_read_bytes() {
	if (cb)
		return cb->get_size();
	else
		return read_bytes;
}

int thread_private::thread_init() {
	attach2cpu();
	io->init();

	extern int buf_size;
	rand_buf *buf = new rand_buf(NUM_PAGES / (nthreads
				// TODO maybe I should set the right entry size for a buffer.
				// If each access size is irregular, I'll break each access
				// into pages so each access is no larger than a page, so it
				// should workl fine.
				/ NUM_NODES) * PAGE_SIZE, buf_size);
	this->buf = buf;
	if (io->support_aio()) {
		cb = new cleanup_callback(buf, idx, this);
		io->set_callback(cb);
	}
	return 0;
}

int thread_private::run()
{
	int node_id = io->get_node_id();
	gettimeofday(&start_time, NULL);
	io_request reqs[NUM_REQS_BY_USER];
	char *entry = NULL;
	if (!io->support_aio())
		use_aio = false;
	if (!use_aio) {
		extern int buf_size;
		entry = (char *) valloc(buf_size);
	}
	while (gen->has_next()) {
		if (use_aio) {
			int i;
			for (i = 0; i < NUM_REQS_BY_USER && gen->has_next(); ) {
				workload_t workload = gen->next();
				int access_method = workload.read ? READ : WRITE;
				off_t off = workload.off;
				int size = workload.size;
				if (align_req) {
					off = ROUND(off, align_size);
					size = ROUNDUP(off + size, align_size)
						- ROUND(off, align_size);
				}
				/*
				 * If the size of the request is larger than a page size,
				 * and the user explicitly wants to use multibuf requests.
				 */
				if (buf_type == MULTI_BUF) {
					throw unsupported_exception();
#if 0
					assert(off % PAGE_SIZE == 0);
					int num_vecs = size / PAGE_SIZE;
					reqs[i].init(off, io, access_method, node_id);
					assert(buf->get_entry_size() >= PAGE_SIZE);
					for (int k = 0; k < num_vecs; k++) {
						reqs[i].add_buf(buf->next_entry(PAGE_SIZE), PAGE_SIZE);
					}
					i++;
#endif
				}
				else if (buf_type == SINGLE_SMALL_BUF) {
again:
					while (size > 0 && i < NUM_REQS_BY_USER) {
						off_t next_off = ROUNDUP_PAGE(off + 1);
						if (next_off > off + size)
							next_off = off + size;
						char *p = buf->next_entry(next_off - off);
						if (p == NULL) {
							fprintf(stderr, "there is no empty buffer left\n");
							break;
						}
						if (access_method == WRITE && verify_read_content)
							create_write_data(p, next_off - off, off);
						reqs[i].init(p, off, next_off - off, access_method,
								io, node_id);
						size -= next_off - off;
						off = next_off;
						i++;
					}
					if (size > 0) {
						io->access(reqs, i);
#ifdef STATISTICS
						num_pending.inc(i);
#endif
						num_accesses += i;
						i = 0;
						goto again;
					}
				}
				else {
					char *p = buf->next_entry(size);
					if (p == NULL) {
						fprintf(stderr, "allocate LARGE: there is no empty buffer left\n");
						break;
					}
					if (access_method == WRITE && verify_read_content)
						create_write_data(p, size, off);
					reqs[i++].init(p, off, size, access_method, io, node_id);
				}
			}
			io->access(reqs, i);
			num_accesses += i;
#ifdef STATISTICS
			int curr = num_pending.inc(i);
			if (max_num_pending < curr)
				max_num_pending = curr;
			if (num_accesses % 100 == 0) {
				num_sampling++;
				tot_num_pending += curr;
			}
#endif
		}
		else {
			int ret = 0;
			workload_t workload = gen->next();
			off_t off = workload.off;
			int access_method = workload.read ? READ : WRITE;
			int entry_size = workload.size;
			if (align_req) {
				off = ROUND(off, align_size);
				entry_size = ROUNDUP(off + entry_size, align_size)
					- ROUND(off, align_size);
			}

			if (buf_type == SINGLE_SMALL_BUF) {
				while (entry_size > 0) {
					/*
					 * generate the data for writing the file,
					 * so the data in the file isn't changed.
					 */
					if (access_method == WRITE && verify_read_content) {
						create_write_data(entry, entry_size, off);
					}
					// There is at least one byte we need to access in the page.
					// By adding 1 and rounding up the offset, we'll get the next page
					// behind the current offset.
					off_t next_off = ROUNDUP_PAGE(off + 1);
					if (next_off > off + entry_size)
						next_off = off + entry_size;
					io_status status = io->access(entry, off, next_off - off,
							access_method);
					if (status == IO_OK) {
						num_accesses++;
						if (access_method == READ && verify_read_content) {
							check_read_content(entry, next_off - off, off);
						}
						read_bytes += ret;
					}
					if (status == IO_FAIL) {
						perror("access");
						exit(1);
					}
					entry_size -= next_off - off;
					off = next_off;
				}
			}
			else {
				if (access_method == WRITE && verify_read_content) {
					create_write_data(entry, entry_size, off);
				}
				io_status status = io->access(entry, off, entry_size,
						access_method);
				if (status == IO_OK) {
					num_accesses++;
					if (access_method == READ && verify_read_content) {
						check_read_content(entry, entry_size, off);
					}
					read_bytes += ret;
				}
				if (status == IO_FAIL) {
					perror("access");
					exit(1);
				}
			}
		}
	}
	io->cleanup();
	printf("thread %d exits\n", idx);
	gettimeofday(&end_time, NULL);
	return 0;
}

int thread_private::attach2cpu()
{
#if NCPUS > 0
	cpu_set_t cpuset;
	pthread_t thread = pthread_self();
	CPU_ZERO(&cpuset);
	int cpu_num = idx % NCPUS;
	CPU_SET(cpu_num, &cpuset);
	int ret = pthread_setaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
	if (ret != 0) {
		perror("pthread_setaffinity_np");
		exit(1);
	}
	printf("attach thread %d to CPU %d\n", idx, cpu_num);
	return ret;
#else
	return -1;
#endif
}

static void *rand_read(void *arg)
{
	thread_private *priv = (thread_private *) arg;

	// We put the thread at the specified NUMA node at the very beginning
	// to make sure all data created in this thread will be on the specified
	// node.
	int node_id = priv->get_io()->get_node_id();
	time_t curr_time = time(NULL);
	printf("run thread rand_read: pid: %d, tid: %ld, on node %d at %s",
			getpid(), gettid(), node_id, ctime(&curr_time));
	bind2node_id(node_id);

	priv->thread_init();
	priv->run();
	return NULL;
}

#ifdef USE_PROCESS
static int process_create(pid_t *pid, void (*func)(void *), void *priv)
{
	pid_t id = fork();

	if (id < 0)
		return -1;

	if (id == 0) {	// child
		func(priv);
		exit(0);
	}

	if (id > 0)
		*pid = id;
	return 0;
}

static int process_join(pid_t pid)
{
	int status;
	pid_t ret = waitpid(pid, &status, 0);
	return ret < 0 ? ret : 0;
}
#endif

int thread_private::start_thread()
{
	int ret;
#ifdef USE_PROCESS
	ret = process_create(&id, rand_read, (void *) this);
#else
	ret = pthread_create(&id, NULL, rand_read, (void *) this);
#endif
	return ret;
}

int thread_private::wait_thread_end()
{
	int ret;
#ifdef USE_PROCESS
	ret = process_join(id);
#else
	ret = pthread_join(id, NULL);
#endif
	return ret;
}
<|endoftext|>


<commit_before><commit_msg>Sync default colors with actual default colors of render windows<commit_after><|endoftext|>


<commit_before>#include "P4Objects.h"
#include "behavioral_utils/json.h"
#include <iostream>

void P4Objects::init_objects(std::istream &is) {
  Json::Value cfg_root;
  is >> cfg_root;

  header_type_id_t header_type_id = 0;

  // header types

  const Json::Value cfg_header_types = cfg_root["header_types"];
  for (const auto &cfg_header_type : cfg_header_types) {
    const string header_type_name = cfg_header_type["name"].asString();
    HeaderType *header_type = new HeaderType(header_type_id++,
					     header_type_name);
    add_header_type(header_type_name, header_type);

    const Json::Value cfg_fields = cfg_header_type["fields"];
    for (auto it = cfg_fields.begin(); it != cfg_fields.end(); it++) {
      const string field_name = it.key().asString();
      int field_bit_width = (*it).asInt();
      header_type->push_back_field(field_name, field_bit_width);
    }
  }

  // headers

  const Json::Value cfg_headers = cfg_root["headers"];
  for (const auto &cfg_header : cfg_headers) {

    const string header_name = cfg_header["name"].asString();
    const string header_type_name = cfg_header["header_type"].asString();

    HeaderType *header_type = get_header_type(header_type_name);

    header_id_t header_id = phv.push_back_header(header_name, *header_type);
    add_header_id(header_name, header_id);
  }

  // parsers

  const Json::Value cfg_parsers = cfg_root["parsers"];
  for (const auto &cfg_parser : cfg_parsers) {

    const string parser_name = cfg_parser["name"].asString();

    Parser *parser = new Parser();
    add_parser(parser_name, parser);

    unordered_map<string, ParseState *> current_parse_states;

    // parse states

    const Json::Value cfg_parse_states = cfg_parser["parse_states"];
    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = new ParseState(parse_state_name);

      const Json::Value cfg_extracts = cfg_parse_state["extracts"];
      for(const auto &cfg_extract : cfg_extracts) {
	const string header_name = cfg_extract.asString();
	header_id_t header_id = get_header_id(header_name);
	parse_state->add_extract(header_id);
      }

      // we do not support parser set ops for now

      ParseSwitchKeyBuilder key_builder;
      const Json::Value cfg_transition_key = cfg_parse_state["transition_key"];
      for (const auto &cfg_key_field : cfg_transition_key) {

	const string header_name = cfg_key_field[0].asString();
	const string field_name = cfg_key_field[1].asString();
	header_id_t header_id = get_header_id(header_name);
	const HeaderType &header_type =
	  phv.get_header(header_id).get_header_type();
	int field_offset = header_type.get_field_offset(field_name);
	key_builder.push_back_field(header_id, field_offset);
      }

      parse_state->set_key_builder(key_builder);

      parse_states.push_back(parse_state);
      current_parse_states[parse_state_name] = parse_state;
    }

    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = current_parse_states[parse_state_name];
      const Json::Value cfg_transitions = cfg_parse_state["transitions"];
      for(const auto &cfg_transition : cfg_transitions) {

      	const string value_hexstr = cfg_transition["value"].asString();
      	// ignore mask for now
	const string next_state_name = cfg_transition["next_state"].asString();
      	const ParseState *next_state = current_parse_states[next_state_name];
	parse_state->add_switch_case(ByteContainer(value_hexstr),
				     next_state);
      }
    }

    const string init_state_name = cfg_parser["init_state"].asString();
    const ParseState *init_state = current_parse_states[init_state_name];
    parser->set_init_state(init_state);
  }

  // deparsers

  const Json::Value cfg_deparsers = cfg_root["deparsers"];
  for (const auto &cfg_deparser : cfg_deparsers) {

    const string deparser_name = cfg_deparser["name"].asString();
    Deparser *deparser = new Deparser();
    add_deparser(deparser_name, deparser);

    const Json::Value cfg_ordered_headers = cfg_deparser["order"];
    for (const auto &cfg_header : cfg_ordered_headers) {

      const string header_name = cfg_header.asString();
      deparser->push_back_header(get_header_id(header_name));
    }
  }
}

/* use unique pointers to get rid of this code ?, it is not really important
   anyway, this is config only, and is only allocated once */

void P4Objects::destroy_objects() {
  for(auto it = header_types_map.begin(); it != header_types_map.end(); ++it)
    delete it->second;
  for(auto it = exact_tables_map.begin(); it != exact_tables_map.end(); ++it)
    delete it->second;
  for(auto it = lpm_tables_map.begin(); it != lpm_tables_map.end(); ++it)
    delete it->second;
  for(auto it = ternary_tables_map.begin(); it != ternary_tables_map.end(); ++it)
    delete it->second;
  for(auto it = parsers.begin(); it != parsers.end(); ++it)
    delete it->second;
  for(auto it = deparsers.begin(); it != deparsers.end(); ++it)
    delete it->second;
  for(auto it : parse_states)
    delete it;
}
<commit_msg>started adding actions to json parser, commit before improving action engine<commit_after>#include "P4Objects.h"
#include "behavioral_utils/json.h"
#include <iostream>

typedef unsigned char opcode_t;

void P4Objects::init_objects(std::istream &is) {
  Json::Value cfg_root;
  is >> cfg_root;

  header_type_id_t header_type_id = 0;

  // header types

  const Json::Value cfg_header_types = cfg_root["header_types"];
  for (const auto &cfg_header_type : cfg_header_types) {
    const string header_type_name = cfg_header_type["name"].asString();
    HeaderType *header_type = new HeaderType(header_type_id++,
					     header_type_name);
    add_header_type(header_type_name, header_type);

    const Json::Value cfg_fields = cfg_header_type["fields"];
    for (auto it = cfg_fields.begin(); it != cfg_fields.end(); it++) {
      const string field_name = it.key().asString();
      int field_bit_width = (*it).asInt();
      header_type->push_back_field(field_name, field_bit_width);
    }
  }

  // headers

  const Json::Value cfg_headers = cfg_root["headers"];
  for (const auto &cfg_header : cfg_headers) {

    const string header_name = cfg_header["name"].asString();
    const string header_type_name = cfg_header["header_type"].asString();

    HeaderType *header_type = get_header_type(header_type_name);

    header_id_t header_id = phv.push_back_header(header_name, *header_type);
    add_header_id(header_name, header_id);
  }

  // parsers

  const Json::Value cfg_parsers = cfg_root["parsers"];
  for (const auto &cfg_parser : cfg_parsers) {

    const string parser_name = cfg_parser["name"].asString();

    Parser *parser = new Parser();
    add_parser(parser_name, parser);

    unordered_map<string, ParseState *> current_parse_states;

    // parse states

    const Json::Value cfg_parse_states = cfg_parser["parse_states"];
    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = new ParseState(parse_state_name);

      const Json::Value cfg_extracts = cfg_parse_state["extracts"];
      for(const auto &cfg_extract : cfg_extracts) {
	const string header_name = cfg_extract.asString();
	header_id_t header_id = get_header_id(header_name);
	parse_state->add_extract(header_id);
      }

      // we do not support parser set ops for now

      ParseSwitchKeyBuilder key_builder;
      const Json::Value cfg_transition_key = cfg_parse_state["transition_key"];
      for (const auto &cfg_key_field : cfg_transition_key) {

	const string header_name = cfg_key_field[0].asString();
	const string field_name = cfg_key_field[1].asString();
	header_id_t header_id = get_header_id(header_name);
	const HeaderType &header_type =
	  phv.get_header(header_id).get_header_type();
	int field_offset = header_type.get_field_offset(field_name);
	key_builder.push_back_field(header_id, field_offset);
      }

      parse_state->set_key_builder(key_builder);

      parse_states.push_back(parse_state);
      current_parse_states[parse_state_name] = parse_state;
    }

    for (const auto &cfg_parse_state : cfg_parse_states) {

      const string parse_state_name = cfg_parse_state["name"].asString();
      ParseState *parse_state = current_parse_states[parse_state_name];
      const Json::Value cfg_transitions = cfg_parse_state["transitions"];
      for(const auto &cfg_transition : cfg_transitions) {

      	const string value_hexstr = cfg_transition["value"].asString();
      	// ignore mask for now
	const string next_state_name = cfg_transition["next_state"].asString();
      	const ParseState *next_state = current_parse_states[next_state_name];
	parse_state->add_switch_case(ByteContainer(value_hexstr),
				     next_state);
      }
    }

    const string init_state_name = cfg_parser["init_state"].asString();
    const ParseState *init_state = current_parse_states[init_state_name];
    parser->set_init_state(init_state);
  }

  // deparsers

  const Json::Value cfg_deparsers = cfg_root["deparsers"];
  for (const auto &cfg_deparser : cfg_deparsers) {

    const string deparser_name = cfg_deparser["name"].asString();
    Deparser *deparser = new Deparser();
    add_deparser(deparser_name, deparser);

    const Json::Value cfg_ordered_headers = cfg_deparser["order"];
    for (const auto &cfg_header : cfg_ordered_headers) {

      const string header_name = cfg_header.asString();
      deparser->push_back_header(get_header_id(header_name));
    }
  }

  // action primitives' opcodes

  unordered_map<string, opcode_t> primitive_opcodes;
  const Json::Value cfg_primitive_opcodes = cfg_root["primitive_opcodes"];
  for (auto it = cfg_primitive_opcodes.begin();
       it != cfg_primitive_opcodes.end(); it++) {
    const string primitive_name = it.key().asString();
    opcode_t opcode = (*it).asInt();
    primitive_opcodes[primitive_name] = opcode;
  }

  // actions

  // const Json::Value cfg_actions = cfg_root["actions"];
  // for (const auto &cfg_actions : cfg_actions) {

  //   const string action_name = cfg_action["name"].asString();
  //   ActionFn *action_fn = new ActionFn();

  //   add_action(action_name, action);

  //   const Json::Value cfg_parameters = cfg_action["parameters"];
  //   for (const auto &cfg_parameter : cfg_parameters) {

  //     const string parameter_type = cfg_parameter["type"].asString();

  //     if(parameter_type == "field") {
  // 	const Json::Value cfg_value = cfg_parameter["value"];
  // 	const string header_name = cfg_value[0].asString();
  // 	header_id_t header_id = get_header_id(header_name);
  // 	const HeaderType &header_type =
  // 	  phv.get_header(header_id).get_header_type();
  // 	int field_offset = header_type.get_field_offset(field_name);
  //     }
  //   }

  // }
}

/* use unique pointers to get rid of this code ?, it is not really important
   anyway, this is config only, and is only allocated once */

void P4Objects::destroy_objects() {
  for(auto it = header_types_map.begin(); it != header_types_map.end(); ++it)
    delete it->second;
  for(auto it = exact_tables_map.begin(); it != exact_tables_map.end(); ++it)
    delete it->second;
  for(auto it = lpm_tables_map.begin(); it != lpm_tables_map.end(); ++it)
    delete it->second;
  for(auto it = ternary_tables_map.begin(); it != ternary_tables_map.end(); ++it)
    delete it->second;
  for(auto it = parsers.begin(); it != parsers.end(); ++it)
    delete it->second;
  for(auto it = deparsers.begin(); it != deparsers.end(); ++it)
    delete it->second;
  for(auto it : parse_states)
    delete it;
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/SimpleTextDrawer.hpp>
#include <memory>
#include <Nazara/Utility/Debug.hpp>

namespace Nz
{
	SimpleTextDrawer::SimpleTextDrawer() :
	m_color(Color::White),
	m_style(TextStyle_Regular),
	m_colorUpdated(true),
	m_glyphUpdated(true),
	m_characterSize(24)
	{
		SetFont(Font::GetDefault());
	}

	SimpleTextDrawer::SimpleTextDrawer(const SimpleTextDrawer& drawer) :
	m_color(drawer.m_color),
	m_text(drawer.m_text),
	m_style(drawer.m_style),
	m_colorUpdated(false),
	m_glyphUpdated(false),
	m_characterSize(drawer.m_characterSize)
	{
		SetFont(drawer.m_font);
	}

	SimpleTextDrawer::SimpleTextDrawer(SimpleTextDrawer&& drawer)
	{
		operator=(std::move(drawer));
	}

	SimpleTextDrawer::~SimpleTextDrawer() = default;

	void SimpleTextDrawer::AppendText(const String& str)
	{
		m_text.Append(str);
		if (m_glyphUpdated)
			GenerateGlyphs(str);
	}

	void SimpleTextDrawer::Clear()
	{
		m_text.Clear(true);
		ClearGlyphs();
	}

	const Recti& SimpleTextDrawer::GetBounds() const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		return m_bounds;
	}

	unsigned int SimpleTextDrawer::GetCharacterSize() const
	{
		return m_characterSize;
	}

	const Color& SimpleTextDrawer::GetColor() const
	{
		return m_color;
	}

	Font* SimpleTextDrawer::GetFont() const
	{
		return m_font;
	}

	Font* SimpleTextDrawer::GetFont(std::size_t index) const
	{
		NazaraAssert(index == 0, "Font index out of range");
		NazaraUnused(index);

		return m_font;
	}

	std::size_t SimpleTextDrawer::GetFontCount() const
	{
		return 1;
	}

	const AbstractTextDrawer::Glyph& SimpleTextDrawer::GetGlyph(std::size_t index) const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();
		else if (!m_colorUpdated)
			UpdateGlyphColor();

		return m_glyphs[index];
	}

	std::size_t SimpleTextDrawer::GetGlyphCount() const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		return m_glyphs.size();
	}

	const AbstractTextDrawer::Line& SimpleTextDrawer::GetLine(std::size_t index) const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		NazaraAssert(index < m_lines.size(), "Line index out of range");
		return m_lines[index];
	}

	std::size_t SimpleTextDrawer::GetLineCount() const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		return m_lines.size();
	}

	UInt32 SimpleTextDrawer::GetStyle() const
	{
		return m_style;
	}

	const String& SimpleTextDrawer::GetText() const
	{
		return m_text;
	}

	void SimpleTextDrawer::SetCharacterSize(unsigned int characterSize)
	{
		m_characterSize = characterSize;

		m_glyphUpdated = false;
	}

	void SimpleTextDrawer::SetColor(const Color& color)
	{
		m_color = color;

		m_colorUpdated = false;
	}

	void SimpleTextDrawer::SetFont(Font* font)
	{
		if (m_font != font)
		{
			m_font = font;

			if (m_font)
				ConnectFontSlots();
			else
				DisconnectFontSlots();

			m_glyphUpdated = false;
		}
	}

	void SimpleTextDrawer::SetStyle(UInt32 style)
	{
		m_style = style;

		m_glyphUpdated = false;
	}

	void SimpleTextDrawer::SetText(const String& str)
	{
		m_text = str;

		m_glyphUpdated = false;
	}

	SimpleTextDrawer& SimpleTextDrawer::operator=(const SimpleTextDrawer& drawer)
	{
		m_characterSize = drawer.m_characterSize;
		m_color = drawer.m_color;
		m_style = drawer.m_style;
		m_text = drawer.m_text;

		m_colorUpdated = false;
		m_glyphUpdated = false;
		SetFont(drawer.m_font);

		return *this;
	}

	SimpleTextDrawer& SimpleTextDrawer::operator=(SimpleTextDrawer&& drawer)
	{
		DisconnectFontSlots();

		m_bounds = std::move(drawer.m_bounds);
		m_colorUpdated = std::move(drawer.m_colorUpdated);
		m_characterSize = std::move(drawer.m_characterSize);
		m_color = std::move(drawer.m_color);
		m_glyphs = std::move(drawer.m_glyphs);
		m_glyphUpdated = std::move(drawer.m_glyphUpdated);
		m_font = std::move(drawer.m_font);
		m_style = std::move(drawer.m_style);
		m_text = std::move(drawer.m_text);

		// Update slot pointers (TODO: Improve the way of doing this)
		ConnectFontSlots();

		return *this;
	}

	SimpleTextDrawer SimpleTextDrawer::Draw(const String& str, unsigned int characterSize, UInt32 style, const Color& color)
	{
		SimpleTextDrawer drawer;
		drawer.SetCharacterSize(characterSize);
		drawer.SetColor(color);
		drawer.SetStyle(style);
		drawer.SetText(str);

		return drawer;
	}

	SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, UInt32 style, const Color& color)
	{
		SimpleTextDrawer drawer;
		drawer.SetCharacterSize(characterSize);
		drawer.SetColor(color);
		drawer.SetFont(font);
		drawer.SetStyle(style);
		drawer.SetText(str);

		return drawer;
	}

	void SimpleTextDrawer::ClearGlyphs() const
	{
		m_bounds.MakeZero();
		m_colorUpdated = true;
		m_drawPos.Set(0, m_characterSize); //< Our draw "cursor"
		m_lines.clear();
		m_glyphs.clear();
		m_glyphUpdated = true;
		m_previousCharacter = 0;
		m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly)

		if (m_font)
			m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, float(m_font->GetSizeInfo(m_characterSize).lineHeight)), 0});
		else
			m_lines.emplace_back(Line{Rectf::Zero(), 0});
	}

	void SimpleTextDrawer::ConnectFontSlots()
	{
		m_atlasChangedSlot.Connect(m_font->OnFontAtlasChanged, this, &SimpleTextDrawer::OnFontInvalidated);
		m_atlasLayerChangedSlot.Connect(m_font->OnFontAtlasLayerChanged, this, &SimpleTextDrawer::OnFontAtlasLayerChanged);
		m_fontReleaseSlot.Connect(m_font->OnFontRelease, this, &SimpleTextDrawer::OnFontRelease);
		m_glyphCacheClearedSlot.Connect(m_font->OnFontGlyphCacheCleared, this, &SimpleTextDrawer::OnFontInvalidated);
	}

	void SimpleTextDrawer::DisconnectFontSlots()
	{
		m_atlasChangedSlot.Disconnect();
		m_atlasLayerChangedSlot.Disconnect();
		m_fontReleaseSlot.Disconnect();
		m_glyphCacheClearedSlot.Disconnect();
	}

	void SimpleTextDrawer::GenerateGlyphs(const String& text) const
	{
		if (text.IsEmpty())
			return;

		///TODO: Allow iteration on Unicode characters without allocating any buffer
		std::u32string characters = text.GetUtf32String();
		if (characters.empty())
		{
			NazaraError("Invalid character set");
			return;
		}

		const Font::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize);

		m_glyphs.reserve(m_glyphs.size() + characters.size());
		for (char32_t character : characters)
		{
			if (m_previousCharacter != 0)
				m_drawPos.x += m_font->GetKerning(m_characterSize, m_previousCharacter, character);

			m_previousCharacter = character;

			bool whitespace = true;
			int advance = 0;
			switch (character)
			{
				case ' ':
				case '\n':
					advance = sizeInfo.spaceAdvance;
					break;

				case '\t':
					advance = sizeInfo.spaceAdvance * 4;
					break;

				default:
					whitespace = false;
					break;
			}

			Glyph glyph;
			if (!whitespace)
			{
				const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, character);
				if (!fontGlyph.valid)
					continue; // Glyph failed to load, just skip it (can't do much)

				advance = fontGlyph.advance;

				glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex);
				glyph.atlasRect = fontGlyph.atlasRect;
				glyph.color = m_color;
				glyph.flipped = fontGlyph.flipped;

				glyph.bounds.Set(fontGlyph.aabb);
				glyph.bounds.x += m_drawPos.x;
				glyph.bounds.y += m_drawPos.y;

				if (fontGlyph.requireFauxBold)
				{
					// Let's simulate bold by enlarging the glyph (not a neat idea, but should work)
					Vector2f center = glyph.bounds.GetCenter();

					// Enlarge by 10%
					glyph.bounds.width *= 1.1f;
					glyph.bounds.height *= 1.1f;

					// Replace it at the correct height
					Vector2f offset(glyph.bounds.GetCenter() - center);
					glyph.bounds.x -= offset.x;
					glyph.bounds.y -= offset.y;

					// Adjust advance (+10%)
					advance += advance / 10;
				}

				// We "lean" the glyph to simulate italics style
				float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f;
				float italicTop = italic * glyph.bounds.y;
				float italicBottom = italic * glyph.bounds.GetMaximum().y;

				glyph.corners[0].Set(glyph.bounds.x - italicTop, glyph.bounds.y);
				glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop, glyph.bounds.y);
				glyph.corners[2].Set(glyph.bounds.x - italicBottom, glyph.bounds.y + glyph.bounds.height);
				glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom, glyph.bounds.y + glyph.bounds.height);
			}
			else
			{
				glyph.atlas = nullptr;

				glyph.bounds.Set(float(m_drawPos.x), float(m_drawPos.y), float(advance), float(sizeInfo.lineHeight));

				glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop));
				glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
				glyph.corners[2].Set(glyph.bounds.GetCorner(RectCorner_LeftBottom));
				glyph.corners[3].Set(glyph.bounds.GetCorner(RectCorner_RightBottom));

				switch (character)
				{
					case '\n':
					{
						// Extend the line bounding rect to the last glyph it contains, thus extending upon all glyphs of the line
						if (!m_glyphs.empty())
						{
							Glyph& lastGlyph = m_glyphs.back();
							m_lines.back().bounds.ExtendTo(lastGlyph.bounds);
						}

						// Reset cursor
						advance = 0;
						m_drawPos.x = 0;
						m_drawPos.y += sizeInfo.lineHeight;

						m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1});
						break;
					}
				}
			}

			m_lines.back().bounds.ExtendTo(glyph.bounds);

			if (!m_workingBounds.IsValid())
				m_workingBounds.Set(glyph.bounds);
			else
				m_workingBounds.ExtendTo(glyph.bounds);

			m_drawPos.x += advance;
			m_glyphs.push_back(glyph);
		}
		m_lines.back().bounds.ExtendTo(m_glyphs.back().bounds);

		m_bounds.Set(Rectf(std::floor(m_workingBounds.x), std::floor(m_workingBounds.y), std::ceil(m_workingBounds.width), std::ceil(m_workingBounds.height)));
	}

	void SimpleTextDrawer::OnFontAtlasLayerChanged(const Font* font, AbstractImage* oldLayer, AbstractImage* newLayer)
	{
		NazaraUnused(font);

		#ifdef NAZARA_DEBUG
		if (m_font != font)
		{
			NazaraInternalError("Not listening to " + String::Pointer(font));
			return;
		}
		#endif

		// Update atlas layer pointer
		// Note: This can happen while updating
		for (Glyph& glyph : m_glyphs)
		{
			if (glyph.atlas == oldLayer)
				glyph.atlas = newLayer;
		}
	}

	void SimpleTextDrawer::OnFontInvalidated(const Font* font)
	{
		NazaraUnused(font);

		#ifdef NAZARA_DEBUG
		if (m_font != font)
		{
			NazaraInternalError("Not listening to " + String::Pointer(font));
			return;
		}
		#endif

		m_glyphUpdated = false;
	}

	void SimpleTextDrawer::OnFontRelease(const Font* font)
	{
		NazaraUnused(font);
		NazaraUnused(font);

		#ifdef NAZARA_DEBUG
		if (m_font != font)
		{
			NazaraInternalError("Not listening to " + String::Pointer(font));
			return;
		}
		#endif

		SetFont(nullptr);
	}

	void SimpleTextDrawer::UpdateGlyphColor() const
	{
		for (Glyph& glyph : m_glyphs)
			glyph.color = m_color;

		m_colorUpdated = true;
	}

	void SimpleTextDrawer::UpdateGlyphs() const
	{
		NazaraAssert(m_font && m_font->IsValid(), "Invalid font");

		ClearGlyphs();
		GenerateGlyphs(m_text);
	}
}
<commit_msg>Utility/SimpleTextDrawer: Fix drawer regenerating glyphs everytime<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/SimpleTextDrawer.hpp>
#include <memory>
#include <Nazara/Utility/Debug.hpp>

namespace Nz
{
	SimpleTextDrawer::SimpleTextDrawer() :
	m_color(Color::White),
	m_style(TextStyle_Regular),
	m_colorUpdated(true),
	m_glyphUpdated(true),
	m_characterSize(24)
	{
		SetFont(Font::GetDefault());
	}

	SimpleTextDrawer::SimpleTextDrawer(const SimpleTextDrawer& drawer) :
	m_color(drawer.m_color),
	m_text(drawer.m_text),
	m_style(drawer.m_style),
	m_colorUpdated(false),
	m_glyphUpdated(false),
	m_characterSize(drawer.m_characterSize)
	{
		SetFont(drawer.m_font);
	}

	SimpleTextDrawer::SimpleTextDrawer(SimpleTextDrawer&& drawer)
	{
		operator=(std::move(drawer));
	}

	SimpleTextDrawer::~SimpleTextDrawer() = default;

	void SimpleTextDrawer::AppendText(const String& str)
	{
		m_text.Append(str);
		if (m_glyphUpdated)
			GenerateGlyphs(str);
	}

	void SimpleTextDrawer::Clear()
	{
		m_text.Clear(true);
		ClearGlyphs();
	}

	const Recti& SimpleTextDrawer::GetBounds() const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		return m_bounds;
	}

	unsigned int SimpleTextDrawer::GetCharacterSize() const
	{
		return m_characterSize;
	}

	const Color& SimpleTextDrawer::GetColor() const
	{
		return m_color;
	}

	Font* SimpleTextDrawer::GetFont() const
	{
		return m_font;
	}

	Font* SimpleTextDrawer::GetFont(std::size_t index) const
	{
		NazaraAssert(index == 0, "Font index out of range");
		NazaraUnused(index);

		return m_font;
	}

	std::size_t SimpleTextDrawer::GetFontCount() const
	{
		return 1;
	}

	const AbstractTextDrawer::Glyph& SimpleTextDrawer::GetGlyph(std::size_t index) const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();
		else if (!m_colorUpdated)
			UpdateGlyphColor();

		return m_glyphs[index];
	}

	std::size_t SimpleTextDrawer::GetGlyphCount() const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		return m_glyphs.size();
	}

	const AbstractTextDrawer::Line& SimpleTextDrawer::GetLine(std::size_t index) const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		NazaraAssert(index < m_lines.size(), "Line index out of range");
		return m_lines[index];
	}

	std::size_t SimpleTextDrawer::GetLineCount() const
	{
		if (!m_glyphUpdated)
			UpdateGlyphs();

		return m_lines.size();
	}

	UInt32 SimpleTextDrawer::GetStyle() const
	{
		return m_style;
	}

	const String& SimpleTextDrawer::GetText() const
	{
		return m_text;
	}

	void SimpleTextDrawer::SetCharacterSize(unsigned int characterSize)
	{
		m_characterSize = characterSize;

		m_glyphUpdated = false;
	}

	void SimpleTextDrawer::SetColor(const Color& color)
	{
		m_color = color;

		m_colorUpdated = false;
	}

	void SimpleTextDrawer::SetFont(Font* font)
	{
		if (m_font != font)
		{
			m_font = font;

			if (m_font)
				ConnectFontSlots();
			else
				DisconnectFontSlots();

			m_glyphUpdated = false;
		}
	}

	void SimpleTextDrawer::SetStyle(UInt32 style)
	{
		m_style = style;

		m_glyphUpdated = false;
	}

	void SimpleTextDrawer::SetText(const String& str)
	{
		m_text = str;

		m_glyphUpdated = false;
	}

	SimpleTextDrawer& SimpleTextDrawer::operator=(const SimpleTextDrawer& drawer)
	{
		m_characterSize = drawer.m_characterSize;
		m_color = drawer.m_color;
		m_style = drawer.m_style;
		m_text = drawer.m_text;

		m_colorUpdated = false;
		m_glyphUpdated = false;
		SetFont(drawer.m_font);

		return *this;
	}

	SimpleTextDrawer& SimpleTextDrawer::operator=(SimpleTextDrawer&& drawer)
	{
		DisconnectFontSlots();

		m_bounds = std::move(drawer.m_bounds);
		m_colorUpdated = std::move(drawer.m_colorUpdated);
		m_characterSize = std::move(drawer.m_characterSize);
		m_color = std::move(drawer.m_color);
		m_glyphs = std::move(drawer.m_glyphs);
		m_glyphUpdated = std::move(drawer.m_glyphUpdated);
		m_font = std::move(drawer.m_font);
		m_style = std::move(drawer.m_style);
		m_text = std::move(drawer.m_text);

		// Update slot pointers (TODO: Improve the way of doing this)
		ConnectFontSlots();

		return *this;
	}

	SimpleTextDrawer SimpleTextDrawer::Draw(const String& str, unsigned int characterSize, UInt32 style, const Color& color)
	{
		SimpleTextDrawer drawer;
		drawer.SetCharacterSize(characterSize);
		drawer.SetColor(color);
		drawer.SetStyle(style);
		drawer.SetText(str);

		return drawer;
	}

	SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, UInt32 style, const Color& color)
	{
		SimpleTextDrawer drawer;
		drawer.SetCharacterSize(characterSize);
		drawer.SetColor(color);
		drawer.SetFont(font);
		drawer.SetStyle(style);
		drawer.SetText(str);

		return drawer;
	}

	void SimpleTextDrawer::ClearGlyphs() const
	{
		m_bounds.MakeZero();
		m_colorUpdated = true;
		m_drawPos.Set(0, m_characterSize); //< Our draw "cursor"
		m_lines.clear();
		m_glyphs.clear();
		m_glyphUpdated = true;
		m_previousCharacter = 0;
		m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly)

		if (m_font)
			m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, float(m_font->GetSizeInfo(m_characterSize).lineHeight)), 0});
		else
			m_lines.emplace_back(Line{Rectf::Zero(), 0});
	}

	void SimpleTextDrawer::ConnectFontSlots()
	{
		m_atlasChangedSlot.Connect(m_font->OnFontAtlasChanged, this, &SimpleTextDrawer::OnFontInvalidated);
		m_atlasLayerChangedSlot.Connect(m_font->OnFontAtlasLayerChanged, this, &SimpleTextDrawer::OnFontAtlasLayerChanged);
		m_fontReleaseSlot.Connect(m_font->OnFontRelease, this, &SimpleTextDrawer::OnFontRelease);
		m_glyphCacheClearedSlot.Connect(m_font->OnFontGlyphCacheCleared, this, &SimpleTextDrawer::OnFontInvalidated);
	}

	void SimpleTextDrawer::DisconnectFontSlots()
	{
		m_atlasChangedSlot.Disconnect();
		m_atlasLayerChangedSlot.Disconnect();
		m_fontReleaseSlot.Disconnect();
		m_glyphCacheClearedSlot.Disconnect();
	}

	void SimpleTextDrawer::GenerateGlyphs(const String& text) const
	{
		if (text.IsEmpty())
			return;

		///TODO: Allow iteration on Unicode characters without allocating any buffer
		std::u32string characters = text.GetUtf32String();
		if (characters.empty())
		{
			NazaraError("Invalid character set");
			return;
		}

		const Font::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize);

		m_glyphs.reserve(m_glyphs.size() + characters.size());
		for (char32_t character : characters)
		{
			if (m_previousCharacter != 0)
				m_drawPos.x += m_font->GetKerning(m_characterSize, m_previousCharacter, character);

			m_previousCharacter = character;

			bool whitespace = true;
			int advance = 0;
			switch (character)
			{
				case ' ':
				case '\n':
					advance = sizeInfo.spaceAdvance;
					break;

				case '\t':
					advance = sizeInfo.spaceAdvance * 4;
					break;

				default:
					whitespace = false;
					break;
			}

			Glyph glyph;
			if (!whitespace)
			{
				const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, character);
				if (!fontGlyph.valid)
					continue; // Glyph failed to load, just skip it (can't do much)

				advance = fontGlyph.advance;

				glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex);
				glyph.atlasRect = fontGlyph.atlasRect;
				glyph.color = m_color;
				glyph.flipped = fontGlyph.flipped;

				glyph.bounds.Set(fontGlyph.aabb);
				glyph.bounds.x += m_drawPos.x;
				glyph.bounds.y += m_drawPos.y;

				if (fontGlyph.requireFauxBold)
				{
					// Let's simulate bold by enlarging the glyph (not a neat idea, but should work)
					Vector2f center = glyph.bounds.GetCenter();

					// Enlarge by 10%
					glyph.bounds.width *= 1.1f;
					glyph.bounds.height *= 1.1f;

					// Replace it at the correct height
					Vector2f offset(glyph.bounds.GetCenter() - center);
					glyph.bounds.x -= offset.x;
					glyph.bounds.y -= offset.y;

					// Adjust advance (+10%)
					advance += advance / 10;
				}

				// We "lean" the glyph to simulate italics style
				float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f;
				float italicTop = italic * glyph.bounds.y;
				float italicBottom = italic * glyph.bounds.GetMaximum().y;

				glyph.corners[0].Set(glyph.bounds.x - italicTop, glyph.bounds.y);
				glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop, glyph.bounds.y);
				glyph.corners[2].Set(glyph.bounds.x - italicBottom, glyph.bounds.y + glyph.bounds.height);
				glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom, glyph.bounds.y + glyph.bounds.height);
			}
			else
			{
				glyph.atlas = nullptr;

				glyph.bounds.Set(float(m_drawPos.x), float(m_drawPos.y), float(advance), float(sizeInfo.lineHeight));

				glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop));
				glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
				glyph.corners[2].Set(glyph.bounds.GetCorner(RectCorner_LeftBottom));
				glyph.corners[3].Set(glyph.bounds.GetCorner(RectCorner_RightBottom));

				switch (character)
				{
					case '\n':
					{
						// Extend the line bounding rect to the last glyph it contains, thus extending upon all glyphs of the line
						if (!m_glyphs.empty())
						{
							Glyph& lastGlyph = m_glyphs.back();
							m_lines.back().bounds.ExtendTo(lastGlyph.bounds);
						}

						// Reset cursor
						advance = 0;
						m_drawPos.x = 0;
						m_drawPos.y += sizeInfo.lineHeight;

						m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1});
						break;
					}
				}
			}

			m_lines.back().bounds.ExtendTo(glyph.bounds);

			if (!m_workingBounds.IsValid())
				m_workingBounds.Set(glyph.bounds);
			else
				m_workingBounds.ExtendTo(glyph.bounds);

			m_drawPos.x += advance;
			m_glyphs.push_back(glyph);
		}
		m_lines.back().bounds.ExtendTo(m_glyphs.back().bounds);

		m_bounds.Set(Rectf(std::floor(m_workingBounds.x), std::floor(m_workingBounds.y), std::ceil(m_workingBounds.width), std::ceil(m_workingBounds.height)));

		m_colorUpdated = true;
		m_glyphUpdated = true;
	}

	void SimpleTextDrawer::OnFontAtlasLayerChanged(const Font* font, AbstractImage* oldLayer, AbstractImage* newLayer)
	{
		NazaraUnused(font);

		#ifdef NAZARA_DEBUG
		if (m_font != font)
		{
			NazaraInternalError("Not listening to " + String::Pointer(font));
			return;
		}
		#endif

		// Update atlas layer pointer
		// Note: This can happen while updating
		for (Glyph& glyph : m_glyphs)
		{
			if (glyph.atlas == oldLayer)
				glyph.atlas = newLayer;
		}
	}

	void SimpleTextDrawer::OnFontInvalidated(const Font* font)
	{
		NazaraUnused(font);

		#ifdef NAZARA_DEBUG
		if (m_font != font)
		{
			NazaraInternalError("Not listening to " + String::Pointer(font));
			return;
		}
		#endif

		m_glyphUpdated = false;
	}

	void SimpleTextDrawer::OnFontRelease(const Font* font)
	{
		NazaraUnused(font);
		NazaraUnused(font);

		#ifdef NAZARA_DEBUG
		if (m_font != font)
		{
			NazaraInternalError("Not listening to " + String::Pointer(font));
			return;
		}
		#endif

		SetFont(nullptr);
	}

	void SimpleTextDrawer::UpdateGlyphColor() const
	{
		for (Glyph& glyph : m_glyphs)
			glyph.color = m_color;

		m_colorUpdated = true;
	}

	void SimpleTextDrawer::UpdateGlyphs() const
	{
		NazaraAssert(m_font && m_font->IsValid(), "Invalid font");

		ClearGlyphs();
		GenerateGlyphs(m_text);
	}
}
<|endoftext|>


<commit_before>// The first run checks that the correct errors are generated,
// implicitly checking the order of default argument parsing:
// RUN: %clang_cc1 -fsyntax-only -verify %s
// The second run checks the order of inline method definitions:
// RUN: not %clang_cc1 -fsyntax-only %s 2> %t
// RUN: FileCheck %s < %t

class A {
public:
  void a1() {
    B b = B();
  }

  class B;
  void a2(B b = B()); // expected-error{{use of default argument to function 'B' that is declared later in class 'B'}}

  void a3(int a = 42);

  // CHEKC: error: use of undeclared identifier 'first'
  void a4(int a = first); // expected-error{{use of undeclared identifier 'first'}}

  class B {
  public:
    B(int b = 42) { // expected-note{{default argument declared here}}
      A a;
      a.a3();
      a.a6();
    }

    void b1(A a = A()); // expected-error{{use of default argument to function 'A' that is declared later in class 'A'}}

    // CHECK: error: use of undeclared identifier 'second'
    void b2(int a = second); // expected-error{{use of undeclared identifier 'second'}}
  };

  void a5() {
    B b = B();
  }

  void a6(B b = B());

  A(int a = 42); // expected-note{{default argument declared here}}

  // CHECK: error: use of undeclared identifier 'third'
  void a7(int a = third); // expected-error{{use of undeclared identifier 'third'}}
};
<commit_msg>Fix a typo in a test. CHEKC -> CHECK<commit_after>// The first run checks that the correct errors are generated,
// implicitly checking the order of default argument parsing:
// RUN: %clang_cc1 -fsyntax-only -verify %s
// The second run checks the order of inline method definitions:
// RUN: not %clang_cc1 -fsyntax-only %s 2> %t
// RUN: FileCheck %s < %t

class A {
public:
  void a1() {
    B b = B();
  }

  class B;
  void a2(B b = B()); // expected-error{{use of default argument to function 'B' that is declared later in class 'B'}}

  void a3(int a = 42);

  // CHECK: error: use of undeclared identifier 'first'
  void a4(int a = first); // expected-error{{use of undeclared identifier 'first'}}

  class B {
  public:
    B(int b = 42) { // expected-note{{default argument declared here}}
      A a;
      a.a3();
      a.a6();
    }

    void b1(A a = A()); // expected-error{{use of default argument to function 'A' that is declared later in class 'A'}}

    // CHECK: error: use of undeclared identifier 'second'
    void b2(int a = second); // expected-error{{use of undeclared identifier 'second'}}
  };

  void a5() {
    B b = B();
  }

  void a6(B b = B());

  A(int a = 42); // expected-note{{default argument declared here}}

  // CHECK: error: use of undeclared identifier 'third'
  void a7(int a = third); // expected-error{{use of undeclared identifier 'third'}}
};
<|endoftext|>


<commit_before><commit_msg>Added WR VREF latch command<commit_after><|endoftext|>