<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: typemanager.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: vg $ $Date: 2007-10-15 12:24:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "unodevtools/typemanager.hxx"

#include "rtl/alloc.h"
#include "registry/reader.hxx"
#include "cppuhelper/bootstrap.hxx"

#include "com/sun/star/container/XSet.hpp"
#include "com/sun/star/reflection/XTypeDescription.hpp"
#include "com/sun/star/registry/XSimpleRegistry.hpp"
#include "com/sun/star/uno/XComponentContext.hpp"

using namespace ::rtl;
using namespace ::cppu;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::registry;
using namespace ::com::sun::star::reflection;

namespace unodevtools {

static RTTypeClass mapTypeClass(TypeClass typeclass) {
    switch(typeclass) {
    case TypeClass_ENUM:
        return RT_TYPE_ENUM;
    case TypeClass_TYPEDEF:
        return RT_TYPE_TYPEDEF;
    case TypeClass_STRUCT:
        return RT_TYPE_STRUCT;
    case TypeClass_UNION:
        return RT_TYPE_UNION;
    case TypeClass_EXCEPTION:
        return RT_TYPE_EXCEPTION;
    case TypeClass_INTERFACE:
        return RT_TYPE_INTERFACE;
    case TypeClass_SERVICE:
        return RT_TYPE_SERVICE;
    case TypeClass_MODULE:
        return RT_TYPE_MODULE;
    case TypeClass_CONSTANTS:
        return RT_TYPE_CONSTANTS;
    case TypeClass_SINGLETON:
        return RT_TYPE_SINGLETON;
    default:
        break;
    }
    return RT_TYPE_INVALID;
}

UnoTypeManager::UnoTypeManager()
{
    m_pImpl = new UnoTypeManagerImpl();
    acquire();
}

UnoTypeManager::~UnoTypeManager()
{
    release();
}

void UnoTypeManager::release()
{
    if (0 == TypeManager::release())
        delete m_pImpl;
}

sal_Bool UnoTypeManager::init(
    const ::std::vector< ::rtl::OUString > registries)
{
    Reference< XComponentContext > xContext=
        defaultBootstrap_InitialComponentContext();

    if ( !xContext.is() ) {
        OUString msg(RTL_CONSTASCII_USTRINGPARAM(
            "internal UNO problem, can't create initial UNO component context"));
        throw RuntimeException( msg, Reference< XInterface >());
    }
    Any a = xContext->getValueByName(
        OUString(RTL_CONSTASCII_USTRINGPARAM(
            "/singletons/com.sun.star.reflection.theTypeDescriptionManager")));

    a >>= m_pImpl->m_tdmgr;

    if ( !m_pImpl->m_tdmgr.is() ) {
        OUString msg(RTL_CONSTASCII_USTRINGPARAM(
            "internal UNO problem, can't get TypeDescriptionManager"));
        throw RuntimeException( msg, Reference< XInterface >());
    }

    if ( !registries.empty() ) {

        Reference< XMultiComponentFactory > xServiceManager(
            xContext->getServiceManager() );
        if ( !xServiceManager.is() ) {
            OUString msg(RTL_CONSTASCII_USTRINGPARAM(
                             "internal UNO problem, can't get ServiceManager"));
            throw RuntimeException( msg, Reference< XInterface >());
        }

        Sequence<Any> seqArgs(registries.size());

        std::vector< OUString >::const_iterator iter = registries.begin();
        int i = 0;
        while ( iter != registries.end() )
        {
            Reference< XSimpleRegistry > xReg(
                xServiceManager->createInstanceWithContext(
                    OUString(RTL_CONSTASCII_USTRINGPARAM(
                             "com.sun.star.registry.SimpleRegistry")),
                    xContext), UNO_QUERY);
            xReg->open(convertToFileUrl(
                           OUStringToOString(*iter, RTL_TEXTENCODING_UTF8)),
                           sal_True, sal_False);

            seqArgs[i++] = makeAny(xReg);
            iter++;
        }

        Reference< XHierarchicalNameAccess > xTDProvider(
            xServiceManager->createInstanceWithArgumentsAndContext(
                OUString(RTL_CONSTASCII_USTRINGPARAM(
                             "com.sun.star.reflection.TypeDescriptionProvider")),
                seqArgs, xContext),
            UNO_QUERY);
        if ( !xTDProvider.is() ) {
            OUString msg(RTL_CONSTASCII_USTRINGPARAM(
                             "internal UNO problem, can't create local"
                             " type description provider"));
            throw RuntimeException( msg, Reference< XInterface >());
        }

        a = makeAny(xTDProvider);
        Reference< XSet > xSet(m_pImpl->m_tdmgr, UNO_QUERY);
        xSet->insert(a);
    }

    return sal_True;
}

sal_Bool UnoTypeManager::isValidType(const ::rtl::OString& name) const
{
    return m_pImpl->m_tdmgr->hasByHierarchicalName(
        OStringToOUString(name, RTL_TEXTENCODING_UTF8));
}

OString UnoTypeManager::getTypeName(RegistryKey& rTypeKey) const
{
    OString typeName = OUStringToOString(rTypeKey.getName(), RTL_TEXTENCODING_UTF8);
    static OString sBase("/UCR");
    if (typeName.indexOf(sBase) == 0) {
        typeName = typeName.copy(typeName.indexOf('/', 1) + 1);
    } else {
        typeName = typeName.copy(1);
    }
    return typeName;
}

// extern
void* getTypeBlob(Reference< XHierarchicalNameAccess > xTDmgr,
                  const OString& typeName, sal_uInt32* pBlob);

typereg::Reader UnoTypeManager::getTypeReader(
    const OString& name, sal_Bool * /*pIsExtraType*/ ) const
{
    typereg::Reader reader;

    void* pBlob = NULL;
    sal_uInt32 blobsize = 0;

    if ( (pBlob = getTypeBlob(m_pImpl->m_tdmgr, name, &blobsize)) != NULL )
        reader = typereg::Reader(pBlob, blobsize, sal_True, TYPEREG_VERSION_1);

    if ( pBlob )
        rtl_freeMemory(pBlob);

    return reader;
}

typereg::Reader UnoTypeManager::getTypeReader(RegistryKey& rTypeKey) const
{
    typereg::Reader reader;

    if (rTypeKey.isValid()) {
        RegValueType    valueType;
        sal_uInt32      valueSize;

        if (!rTypeKey.getValueInfo(OUString(), &valueType, &valueSize)) {
            sal_uInt8*  pBuffer = (sal_uInt8*)rtl_allocateMemory(valueSize);
            if ( !rTypeKey.getValue(OUString(), pBuffer) ) {
                reader = typereg::Reader(
                    pBuffer, valueSize, true, TYPEREG_VERSION_1);
            }
            rtl_freeMemory(pBuffer);
        }
    }
    return reader;
}

RTTypeClass UnoTypeManager::getTypeClass(const OString& name) const
{
    if ( m_pImpl->m_t2TypeClass.count(name) > 0 ) {
        return m_pImpl->m_t2TypeClass[name];
    } else {
        Reference< XTypeDescription > xTD;
        Any a = m_pImpl->m_tdmgr->getByHierarchicalName(
            OStringToOUString(name, RTL_TEXTENCODING_UTF8));
        a >>= xTD;

        if ( xTD.is() ) {
            RTTypeClass tc = mapTypeClass(xTD->getTypeClass());
            if (tc != RT_TYPE_INVALID)
                m_pImpl->m_t2TypeClass[name] = tc;
            return tc;
        }
    }

    return RT_TYPE_INVALID;
}

RTTypeClass UnoTypeManager::getTypeClass(RegistryKey& rTypeKey) const
{
    OString name = getTypeName(rTypeKey);

    if ( m_pImpl->m_t2TypeClass.count(name) > 0 ) {
        return m_pImpl->m_t2TypeClass[name];
    } else {
        if ( rTypeKey.isValid() ) {
            RegValueType    valueType;
            sal_uInt32      valueSize;

            if ( !rTypeKey.getValueInfo(OUString(), &valueType, &valueSize) ) {
                sal_uInt8*  pBuffer = (sal_uInt8*)rtl_allocateMemory(valueSize);
                if ( !rTypeKey.getValue(OUString(), pBuffer) ) {
                    typereg::Reader reader(
                        pBuffer, valueSize, false, TYPEREG_VERSION_1);

                    RTTypeClass ret = reader.getTypeClass();

                    rtl_freeMemory(pBuffer);

                    m_pImpl->m_t2TypeClass[name] = ret;
                    return ret;
                }
                rtl_freeMemory(pBuffer);
            }
        }
    }

    return RT_TYPE_INVALID;
}

} // end of namespace unodevtools
<commit_msg>INTEGRATION: CWS changefileheader (1.7.10); FILE MERGED 2008/03/28 15:51:24 rt 1.7.10.1: #i87441# Change license header to LPGL v3.<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: typemanager.cxx,v $
 * $Revision: 1.8 $
 *
 * 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.
 *
 ************************************************************************/

#include "unodevtools/typemanager.hxx"

#include "rtl/alloc.h"
#include "registry/reader.hxx"
#include "cppuhelper/bootstrap.hxx"

#include "com/sun/star/container/XSet.hpp"
#include "com/sun/star/reflection/XTypeDescription.hpp"
#include "com/sun/star/registry/XSimpleRegistry.hpp"
#include "com/sun/star/uno/XComponentContext.hpp"

using namespace ::rtl;
using namespace ::cppu;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::registry;
using namespace ::com::sun::star::reflection;

namespace unodevtools {

static RTTypeClass mapTypeClass(TypeClass typeclass) {
    switch(typeclass) {
    case TypeClass_ENUM:
        return RT_TYPE_ENUM;
    case TypeClass_TYPEDEF:
        return RT_TYPE_TYPEDEF;
    case TypeClass_STRUCT:
        return RT_TYPE_STRUCT;
    case TypeClass_UNION:
        return RT_TYPE_UNION;
    case TypeClass_EXCEPTION:
        return RT_TYPE_EXCEPTION;
    case TypeClass_INTERFACE:
        return RT_TYPE_INTERFACE;
    case TypeClass_SERVICE:
        return RT_TYPE_SERVICE;
    case TypeClass_MODULE:
        return RT_TYPE_MODULE;
    case TypeClass_CONSTANTS:
        return RT_TYPE_CONSTANTS;
    case TypeClass_SINGLETON:
        return RT_TYPE_SINGLETON;
    default:
        break;
    }
    return RT_TYPE_INVALID;
}

UnoTypeManager::UnoTypeManager()
{
    m_pImpl = new UnoTypeManagerImpl();
    acquire();
}

UnoTypeManager::~UnoTypeManager()
{
    release();
}

void UnoTypeManager::release()
{
    if (0 == TypeManager::release())
        delete m_pImpl;
}

sal_Bool UnoTypeManager::init(
    const ::std::vector< ::rtl::OUString > registries)
{
    Reference< XComponentContext > xContext=
        defaultBootstrap_InitialComponentContext();

    if ( !xContext.is() ) {
        OUString msg(RTL_CONSTASCII_USTRINGPARAM(
            "internal UNO problem, can't create initial UNO component context"));
        throw RuntimeException( msg, Reference< XInterface >());
    }
    Any a = xContext->getValueByName(
        OUString(RTL_CONSTASCII_USTRINGPARAM(
            "/singletons/com.sun.star.reflection.theTypeDescriptionManager")));

    a >>= m_pImpl->m_tdmgr;

    if ( !m_pImpl->m_tdmgr.is() ) {
        OUString msg(RTL_CONSTASCII_USTRINGPARAM(
            "internal UNO problem, can't get TypeDescriptionManager"));
        throw RuntimeException( msg, Reference< XInterface >());
    }

    if ( !registries.empty() ) {

        Reference< XMultiComponentFactory > xServiceManager(
            xContext->getServiceManager() );
        if ( !xServiceManager.is() ) {
            OUString msg(RTL_CONSTASCII_USTRINGPARAM(
                             "internal UNO problem, can't get ServiceManager"));
            throw RuntimeException( msg, Reference< XInterface >());
        }

        Sequence<Any> seqArgs(registries.size());

        std::vector< OUString >::const_iterator iter = registries.begin();
        int i = 0;
        while ( iter != registries.end() )
        {
            Reference< XSimpleRegistry > xReg(
                xServiceManager->createInstanceWithContext(
                    OUString(RTL_CONSTASCII_USTRINGPARAM(
                             "com.sun.star.registry.SimpleRegistry")),
                    xContext), UNO_QUERY);
            xReg->open(convertToFileUrl(
                           OUStringToOString(*iter, RTL_TEXTENCODING_UTF8)),
                           sal_True, sal_False);

            seqArgs[i++] = makeAny(xReg);
            iter++;
        }

        Reference< XHierarchicalNameAccess > xTDProvider(
            xServiceManager->createInstanceWithArgumentsAndContext(
                OUString(RTL_CONSTASCII_USTRINGPARAM(
                             "com.sun.star.reflection.TypeDescriptionProvider")),
                seqArgs, xContext),
            UNO_QUERY);
        if ( !xTDProvider.is() ) {
            OUString msg(RTL_CONSTASCII_USTRINGPARAM(
                             "internal UNO problem, can't create local"
                             " type description provider"));
            throw RuntimeException( msg, Reference< XInterface >());
        }

        a = makeAny(xTDProvider);
        Reference< XSet > xSet(m_pImpl->m_tdmgr, UNO_QUERY);
        xSet->insert(a);
    }

    return sal_True;
}

sal_Bool UnoTypeManager::isValidType(const ::rtl::OString& name) const
{
    return m_pImpl->m_tdmgr->hasByHierarchicalName(
        OStringToOUString(name, RTL_TEXTENCODING_UTF8));
}

OString UnoTypeManager::getTypeName(RegistryKey& rTypeKey) const
{
    OString typeName = OUStringToOString(rTypeKey.getName(), RTL_TEXTENCODING_UTF8);
    static OString sBase("/UCR");
    if (typeName.indexOf(sBase) == 0) {
        typeName = typeName.copy(typeName.indexOf('/', 1) + 1);
    } else {
        typeName = typeName.copy(1);
    }
    return typeName;
}

// extern
void* getTypeBlob(Reference< XHierarchicalNameAccess > xTDmgr,
                  const OString& typeName, sal_uInt32* pBlob);

typereg::Reader UnoTypeManager::getTypeReader(
    const OString& name, sal_Bool * /*pIsExtraType*/ ) const
{
    typereg::Reader reader;

    void* pBlob = NULL;
    sal_uInt32 blobsize = 0;

    if ( (pBlob = getTypeBlob(m_pImpl->m_tdmgr, name, &blobsize)) != NULL )
        reader = typereg::Reader(pBlob, blobsize, sal_True, TYPEREG_VERSION_1);

    if ( pBlob )
        rtl_freeMemory(pBlob);

    return reader;
}

typereg::Reader UnoTypeManager::getTypeReader(RegistryKey& rTypeKey) const
{
    typereg::Reader reader;

    if (rTypeKey.isValid()) {
        RegValueType    valueType;
        sal_uInt32      valueSize;

        if (!rTypeKey.getValueInfo(OUString(), &valueType, &valueSize)) {
            sal_uInt8*  pBuffer = (sal_uInt8*)rtl_allocateMemory(valueSize);
            if ( !rTypeKey.getValue(OUString(), pBuffer) ) {
                reader = typereg::Reader(
                    pBuffer, valueSize, true, TYPEREG_VERSION_1);
            }
            rtl_freeMemory(pBuffer);
        }
    }
    return reader;
}

RTTypeClass UnoTypeManager::getTypeClass(const OString& name) const
{
    if ( m_pImpl->m_t2TypeClass.count(name) > 0 ) {
        return m_pImpl->m_t2TypeClass[name];
    } else {
        Reference< XTypeDescription > xTD;
        Any a = m_pImpl->m_tdmgr->getByHierarchicalName(
            OStringToOUString(name, RTL_TEXTENCODING_UTF8));
        a >>= xTD;

        if ( xTD.is() ) {
            RTTypeClass tc = mapTypeClass(xTD->getTypeClass());
            if (tc != RT_TYPE_INVALID)
                m_pImpl->m_t2TypeClass[name] = tc;
            return tc;
        }
    }

    return RT_TYPE_INVALID;
}

RTTypeClass UnoTypeManager::getTypeClass(RegistryKey& rTypeKey) const
{
    OString name = getTypeName(rTypeKey);

    if ( m_pImpl->m_t2TypeClass.count(name) > 0 ) {
        return m_pImpl->m_t2TypeClass[name];
    } else {
        if ( rTypeKey.isValid() ) {
            RegValueType    valueType;
            sal_uInt32      valueSize;

            if ( !rTypeKey.getValueInfo(OUString(), &valueType, &valueSize) ) {
                sal_uInt8*  pBuffer = (sal_uInt8*)rtl_allocateMemory(valueSize);
                if ( !rTypeKey.getValue(OUString(), pBuffer) ) {
                    typereg::Reader reader(
                        pBuffer, valueSize, false, TYPEREG_VERSION_1);

                    RTTypeClass ret = reader.getTypeClass();

                    rtl_freeMemory(pBuffer);

                    m_pImpl->m_t2TypeClass[name] = ret;
                    return ret;
                }
                rtl_freeMemory(pBuffer);
            }
        }
    }

    return RT_TYPE_INVALID;
}

} // end of namespace unodevtools
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dp_resource.cxx,v $
 *
 *  $Revision: 1.14 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 09:42:02 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "dp_misc.h"
#include "dp_resource.h"
#include "osl/module.hxx"
#include "osl/mutex.hxx"
#include "cppuhelper/implbase1.hxx"
#include "unotools/configmgr.hxx"

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

namespace dp_misc {
namespace {

struct OfficeLocale :
        public rtl::StaticWithInit<const lang::Locale, OfficeLocale> {
    const lang::Locale operator () () {
        OUString slang;
        if (! (::utl::ConfigManager::GetDirectConfigProperty(
                   ::utl::ConfigManager::LOCALE ) >>= slang))
            throw RuntimeException( OUSTR("Cannot determine language!"), 0 );
        return toLocale(slang);
    }
};

void dummy() {}
struct DeploymentResMgr : public rtl::StaticWithInit<
    ResMgr *, DeploymentResMgr> {
    ResMgr * operator () () {
        return ResMgr::CreateResMgr( "deployment" LIBRARY_SOLARUPD(),
                                     OfficeLocale::get() );
    }
};

osl::Mutex s_mutex;

} // anon namespace

//==============================================================================
ResId getResId( USHORT id )
{
    const osl::MutexGuard guard( s_mutex );
    return ResId( id, DeploymentResMgr::get() );
}

//==============================================================================
String getResourceString( USHORT id )
{
    const osl::MutexGuard guard( s_mutex );
    String ret( ResId( id, DeploymentResMgr::get() ) );
    if (ret.SearchAscii( "%PRODUCTNAME" ) != STRING_NOTFOUND) {
        static String s_brandName;
        if (s_brandName.Len() == 0) {
            OUString brandName(
                ::utl::ConfigManager::GetDirectConfigProperty(
                    ::utl::ConfigManager::PRODUCTNAME ).get<OUString>() );
            s_brandName = brandName;
        }
        ret.SearchAndReplaceAllAscii( "%PRODUCTNAME", s_brandName );
    }
    return ret;
}

//throws an Exception on failure
//primary subtag 2 or three letters(A-Z, a-z), i or x
void checkPrimarySubtag(::rtl::OUString const & tag)
{
    sal_Int32 len = tag.getLength();
    sal_Unicode const * arLang = tag.getStr();
    if (len < 1 || len > 3)
        throw Exception(OUSTR("Invalid language string."), 0);

    if (len == 1
        && (arLang[0] != 'i' && arLang[0] != 'x'))
        throw Exception(OUSTR("Invalid language string."), 0);

    if (len == 2 || len == 3)
    {
        for (sal_Int32 i = 0; i < len; i++)
        {
            if ( !((arLang[i] >= 'A' && arLang[i] <= 'Z')
                || (arLang[i] >= 'a' && arLang[i] <= 'z')))
            {
                throw Exception(OUSTR("Invalid language string."), 0);
            }
        }
    }
}

//throws an Exception on failure
//second subtag 2 letter country code or 3-8 letter other code(A-Z, a-z, 0-9)
void checkSecondSubtag(::rtl::OUString const & tag, bool & bIsCountry)
{
    sal_Int32 len = tag.getLength();
    sal_Unicode const * arLang = tag.getStr();
    if (len < 2 || len > 8)
        throw Exception(OUSTR("Invalid language string."), 0);
    //country code
    bIsCountry = false;
    if (len == 2)
    {
        for (sal_Int32 i = 0; i < 2; i++)
        {
            if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z')
                || (arLang[i] >= 'a' && arLang[i] <= 'z')))
            {
                throw Exception(OUSTR("Invalid language string."), 0);
            }
        }
        bIsCountry = true;
    }

    if (len > 2)
    {
        for (sal_Int32 i = 0; i < len; i++)
        {
            if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z')
                || (arLang[i] >= 'a' && arLang[i] <= 'z')
                || (arLang[i] >= '0' && arLang[i] <= '9') ))
            {
                throw Exception(OUSTR("Invalid language string."), 0);
            }
        }
    }
}

void checkThirdSubtag(::rtl::OUString const & tag)
{
    sal_Int32 len = tag.getLength();
    sal_Unicode const * arLang = tag.getStr();
    if (len < 1 || len > 8)
        throw Exception(OUSTR("Invalid language string."), 0);

    for (sal_Int32 i = 0; i < len; i++)
    {
        if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z')
            || (arLang[i] >= 'a' && arLang[i] <= 'z')
            || (arLang[i] >= '0' && arLang[i] <= '9') ))
        {
            throw Exception(OUSTR("Invalid language string."), 0);
        }
    }
}

//=============================================================================

//We parse the string acording to RFC 3066
//We only use the primary sub-tag and two subtags. That is lang-country-variant
//We do some simple tests if the string is correct. Actually this should do a
//validating parser
//We may have the case that there is no country tag, for example en-welsh
::com::sun::star::lang::Locale toLocale( ::rtl::OUString const & slang )
{
    OUString _sLang = slang.trim();
    ::com::sun::star::lang::Locale locale;
    sal_Int32 nIndex = 0;
    OUString lang = _sLang.getToken( 0, '-', nIndex );
    checkPrimarySubtag(lang);
    locale.Language = lang;
    OUString country = _sLang.getToken( 0, '-', nIndex );
    if (country.getLength() > 0)
    {
        bool bIsCountry = false;
        checkSecondSubtag(country, bIsCountry);
        if (bIsCountry)
        {
            locale.Country = country;
        }
        else
        {
             locale.Variant = country;
        }
    }
    if (locale.Variant.getLength() == 0)
    {
        OUString variant = _sLang.getToken( 0, '-', nIndex );
        if (variant.getLength() > 0)
        {
            checkThirdSubtag(variant);
            locale.Variant = variant;
        }
    }

    return locale;
}

//==============================================================================
lang::Locale const & getOfficeLocale()
{
    return OfficeLocale::get();
}

}

<commit_msg>INTEGRATION: CWS jl47_SRC680 (1.12.84.1.6); FILE MERGED 2006/09/20 11:48:32 jl 1.12.84.1.6.1: #i69642# added default language in case there is no user installation<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dp_resource.cxx,v $
 *
 *  $Revision: 1.15 $
 *
 *  last change: $Author: vg $ $Date: 2006-09-26 14:21:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "dp_misc.h"
#include "dp_resource.h"
#include "osl/module.hxx"
#include "osl/mutex.hxx"
#include "rtl/ustring.h"
#include "cppuhelper/implbase1.hxx"
#include "unotools/configmgr.hxx"

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

namespace dp_misc {
namespace {

struct OfficeLocale :
        public rtl::StaticWithInit<const lang::Locale, OfficeLocale> {
    const lang::Locale operator () () {
        OUString slang;
        if (! (::utl::ConfigManager::GetDirectConfigProperty(
                   ::utl::ConfigManager::LOCALE ) >>= slang))
            throw RuntimeException( OUSTR("Cannot determine language!"), 0 );
        //fallback, the locale is currently only set when the user starts the
        //office for the first time.
        if (slang.getLength() == 0)
            slang =  rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en-US"));
        return toLocale(slang);
    }
};

void dummy() {}
struct DeploymentResMgr : public rtl::StaticWithInit<
    ResMgr *, DeploymentResMgr> {
    ResMgr * operator () () {
        return ResMgr::CreateResMgr( "deployment" LIBRARY_SOLARUPD(),
                                     OfficeLocale::get() );
    }
};

osl::Mutex s_mutex;

} // anon namespace

//==============================================================================
ResId getResId( USHORT id )
{
    const osl::MutexGuard guard( s_mutex );
    return ResId( id, DeploymentResMgr::get() );
}

//==============================================================================
String getResourceString( USHORT id )
{
    const osl::MutexGuard guard( s_mutex );
    String ret( ResId( id, DeploymentResMgr::get() ) );
    if (ret.SearchAscii( "%PRODUCTNAME" ) != STRING_NOTFOUND) {
        static String s_brandName;
        if (s_brandName.Len() == 0) {
            OUString brandName(
                ::utl::ConfigManager::GetDirectConfigProperty(
                    ::utl::ConfigManager::PRODUCTNAME ).get<OUString>() );
            s_brandName = brandName;
        }
        ret.SearchAndReplaceAllAscii( "%PRODUCTNAME", s_brandName );
    }
    return ret;
}

//throws an Exception on failure
//primary subtag 2 or three letters(A-Z, a-z), i or x
void checkPrimarySubtag(::rtl::OUString const & tag)
{
    sal_Int32 len = tag.getLength();
    sal_Unicode const * arLang = tag.getStr();
    if (len < 1 || len > 3)
        throw Exception(OUSTR("Invalid language string."), 0);

    if (len == 1
        && (arLang[0] != 'i' && arLang[0] != 'x'))
        throw Exception(OUSTR("Invalid language string."), 0);

    if (len == 2 || len == 3)
    {
        for (sal_Int32 i = 0; i < len; i++)
        {
            if ( !((arLang[i] >= 'A' && arLang[i] <= 'Z')
                || (arLang[i] >= 'a' && arLang[i] <= 'z')))
            {
                throw Exception(OUSTR("Invalid language string."), 0);
            }
        }
    }
}

//throws an Exception on failure
//second subtag 2 letter country code or 3-8 letter other code(A-Z, a-z, 0-9)
void checkSecondSubtag(::rtl::OUString const & tag, bool & bIsCountry)
{
    sal_Int32 len = tag.getLength();
    sal_Unicode const * arLang = tag.getStr();
    if (len < 2 || len > 8)
        throw Exception(OUSTR("Invalid language string."), 0);
    //country code
    bIsCountry = false;
    if (len == 2)
    {
        for (sal_Int32 i = 0; i < 2; i++)
        {
            if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z')
                || (arLang[i] >= 'a' && arLang[i] <= 'z')))
            {
                throw Exception(OUSTR("Invalid language string."), 0);
            }
        }
        bIsCountry = true;
    }

    if (len > 2)
    {
        for (sal_Int32 i = 0; i < len; i++)
        {
            if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z')
                || (arLang[i] >= 'a' && arLang[i] <= 'z')
                || (arLang[i] >= '0' && arLang[i] <= '9') ))
            {
                throw Exception(OUSTR("Invalid language string."), 0);
            }
        }
    }
}

void checkThirdSubtag(::rtl::OUString const & tag)
{
    sal_Int32 len = tag.getLength();
    sal_Unicode const * arLang = tag.getStr();
    if (len < 1 || len > 8)
        throw Exception(OUSTR("Invalid language string."), 0);

    for (sal_Int32 i = 0; i < len; i++)
    {
        if (!( (arLang[i] >= 'A' && arLang[i] <= 'Z')
            || (arLang[i] >= 'a' && arLang[i] <= 'z')
            || (arLang[i] >= '0' && arLang[i] <= '9') ))
        {
            throw Exception(OUSTR("Invalid language string."), 0);
        }
    }
}

//=============================================================================

//We parse the string acording to RFC 3066
//We only use the primary sub-tag and two subtags. That is lang-country-variant
//We do some simple tests if the string is correct. Actually this should do a
//validating parser
//We may have the case that there is no country tag, for example en-welsh
::com::sun::star::lang::Locale toLocale( ::rtl::OUString const & slang )
{
    OUString _sLang = slang.trim();
    ::com::sun::star::lang::Locale locale;
    sal_Int32 nIndex = 0;
    OUString lang = _sLang.getToken( 0, '-', nIndex );
    checkPrimarySubtag(lang);
    locale.Language = lang;
    OUString country = _sLang.getToken( 0, '-', nIndex );
    if (country.getLength() > 0)
    {
        bool bIsCountry = false;
        checkSecondSubtag(country, bIsCountry);
        if (bIsCountry)
        {
            locale.Country = country;
        }
        else
        {
             locale.Variant = country;
        }
    }
    if (locale.Variant.getLength() == 0)
    {
        OUString variant = _sLang.getToken( 0, '-', nIndex );
        if (variant.getLength() > 0)
        {
            checkThirdSubtag(variant);
            locale.Variant = variant;
        }
    }

    return locale;
}

//==============================================================================
lang::Locale const & getOfficeLocale()
{
    return OfficeLocale::get();
}

}

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include "sqlite_datasource.hpp"
#include "sqlite_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>

using std::clog;
using std::endl;

using boost::lexical_cast;
using boost::bad_lexical_cast;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(sqlite_datasource)

using mapnik::Envelope;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;

std::string table_from_sql(std::string const& sql)
{
   std::string table_name = boost::algorithm::to_lower_copy(sql);
   boost::algorithm::replace_all(table_name,"\n"," ");

   std::string::size_type idx = table_name.rfind("from");
   if (idx!=std::string::npos)
   {

      idx=table_name.find_first_not_of(" ",idx+4);
      if (idx != std::string::npos)
      {
         table_name=table_name.substr(idx);
      }
      idx=table_name.find_first_of(" ),");
      if (idx != std::string::npos)
      {
         table_name = table_name.substr(0,idx);
      }
   }
   return table_name;
}

sqlite_datasource::sqlite_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     extent_initialized_(false),
     type_(datasource::Vector),
     table_(*params.get<std::string>("table","")),
     metadata_(*params.get<std::string>("metadata","")),
     geometry_field_(*params.get<std::string>("geometry_field","the_geom")),
     key_field_(*params.get<std::string>("key_field","OGC_FID")),
     row_offset_(*params_.get<int>("row_offset",0)),
     row_limit_(*params_.get<int>("row_limit",0)),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8")),
     format_(mapnik::wkbGeneric)
{
    boost::optional<std::string> file = params.get<std::string>("file");
    if (!file) throw datasource_exception("missing <file> paramater");

    boost::optional<std::string> wkb = params.get<std::string>("wkb_format");
    if (wkb)
    {
        if (*wkb == "spatialite")
            format_ = mapnik::wkbSpatiaLite;
    }

    multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);
    use_spatial_index_ = *params_.get<mapnik::boolean>("use_spatial_index",true);

    dataset_ = new sqlite_connection (*file);

    boost::optional<std::string> ext  = params_.get<std::string>("extent");
    if (ext)
    {
        boost::char_separator<char> sep(",");
        boost::tokenizer<boost::char_separator<char> > tok(*ext,sep);
        unsigned i = 0;
        bool success = false;
        double d[4];
        for (boost::tokenizer<boost::char_separator<char> >::iterator beg=tok.begin();
             beg!=tok.end();++beg)
        {
            try
            {
                d[i] = boost::lexical_cast<double>(*beg);
            }
            catch (boost::bad_lexical_cast & ex)
            {
                std::clog << ex.what() << "\n";
                break;
            }
            if (i==3)
            {
                success = true;
                break;
            }
            ++i;
        }

        if (success)
        {
            extent_.init(d[0],d[1],d[2],d[3]);
            extent_initialized_ = true;
        }
    }

    std::string table_name = table_from_sql(table_);

    if (metadata_ != "" && ! extent_initialized_)
    {
        std::ostringstream s;
        s << "select xmin, ymin, xmax, ymax from " << metadata_;
        s << " where lower(f_table_name) = lower('" << table_name << "')";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            double xmin = rs->column_double (0);
            double ymin = rs->column_double (1);
            double xmax = rs->column_double (2);
            double ymax = rs->column_double (3);

            extent_.init (xmin,ymin,xmax,ymax);
            extent_initialized_ = true;
        }
    }

    if (use_spatial_index_)
    {
        std::ostringstream s;
        s << "select count (*) from sqlite_master";
        s << " where lower(name) = lower('idx_" << table_name << "_" << geometry_field_ << "')";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            use_spatial_index_ = rs->column_integer (0) == 1;
        }

#ifdef MAPNIK_DEBUG
        if (! use_spatial_index_)
           clog << "cannot use the spatial index " << endl;
#endif
    }

    {
        /*
            XXX - This is problematic, if we don't have at least a row,
                  we cannot determine the right columns types and names
                  as all column_type are SQLITE_NULL
        */
        std::ostringstream s;
        s << "select * from " << table_ << " limit 0";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            for (int i = 0; i < rs->column_count (); ++i)
            {
               const int type_oid = rs->column_type (i);
               const char* fld_name = rs->column_name (i);
               switch (type_oid)
               {
                  case SQLITE_INTEGER:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
                     break;

                  case SQLITE_FLOAT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
                     break;

                  case SQLITE_TEXT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
                     break;

                  case SQLITE_NULL:
                  case SQLITE_BLOB:
                     break;

                  default:
#ifdef MAPNIK_DEBUG
                     clog << "unknown type_oid="<<type_oid<<endl;
#endif
                     break;
                }
            }
        }
    }
}

sqlite_datasource::~sqlite_datasource()
{
    delete dataset_;
}

std::string const sqlite_datasource::name_="sqlite";

std::string sqlite_datasource::name()
{
   return name_;
}

int sqlite_datasource::type() const
{
   return type_;
}

Envelope<double> sqlite_datasource::envelope() const
{
   return extent_;
}

layer_descriptor sqlite_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr sqlite_datasource::features(query const& q) const
{
   if (dataset_)
   {
        mapnik::Envelope<double> const& e = q.get_bbox();

        std::ostringstream s;

        s << "select " << geometry_field_ << "," << key_field_;
        std::set<std::string> const& props = q.property_names();
        std::set<std::string>::const_iterator pos = props.begin();
        std::set<std::string>::const_iterator end = props.end();
        while (pos != end)
        {
           s << "," << *pos << "";
           ++pos;
        }

        s << " from ";

        std::string query (table_);

        if (use_spatial_index_)
        {
           std::string table_name = table_from_sql(query);
           std::ostringstream spatial_sql;
           spatial_sql << std::setprecision(16);
           spatial_sql << " where rowid in (select pkid from idx_" << table_name << "_" << geometry_field_;
           spatial_sql << " where xmax>=" << e.minx() << " and xmin<=" << e.maxx() ;
           spatial_sql << " and ymax>=" << e.miny() << " and ymin<=" << e.maxy() << ")";
           if (boost::algorithm::ifind_first(query,"where"))
           {
              boost::algorithm::ireplace_first(query, "where", spatial_sql.str() + " and");
           }
           else if (boost::algorithm::find_first(query,table_name))
           {
              boost::algorithm::ireplace_first(query, table_name , table_name + " " + spatial_sql.str());
           }
        }

        s << query ;

        if (row_limit_ > 0) {
            s << " limit " << row_limit_;
        }

        if (row_offset_ > 0) {
            s << " offset " << row_offset_;
        }

#ifdef MAPNIK_DEBUG
        std::cerr << s.str() << "\n";
#endif

        boost::shared_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));

        return featureset_ptr (new sqlite_featureset(rs, desc_.get_encoding(), format_, multiple_geometries_));
   }

   return featureset_ptr();
}

featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const
{
#if 0
   if (dataset_ && layer_)
   {
        OGRPoint point;
        point.setX (pt.x);
        point.setY (pt.y);

        layer_->SetSpatialFilter (&point);

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
#endif

   return featureset_ptr();
}

<commit_msg>+ revert to "limit 1" logic + discard everything after table name when building    table descriptor to avoid seq scan<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2007 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
// $Id$

#include "sqlite_datasource.hpp"
#include "sqlite_featureset.hpp"

// mapnik
#include <mapnik/ptree_helpers.hpp>

// boost
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>

using std::clog;
using std::endl;

using boost::lexical_cast;
using boost::bad_lexical_cast;

using mapnik::datasource;
using mapnik::parameters;

DATASOURCE_PLUGIN(sqlite_datasource)

using mapnik::Envelope;
using mapnik::coord2d;
using mapnik::query;
using mapnik::featureset_ptr;
using mapnik::layer_descriptor;
using mapnik::attribute_descriptor;
using mapnik::datasource_exception;

std::string table_from_sql(std::string const& sql)
{
   std::string table_name = boost::algorithm::to_lower_copy(sql);
   boost::algorithm::replace_all(table_name,"\n"," ");

   std::string::size_type idx = table_name.rfind("from");
   if (idx!=std::string::npos)
   {

      idx=table_name.find_first_not_of(" ",idx+4);
      if (idx != std::string::npos)
      {
         table_name=table_name.substr(idx);
      }
      idx=table_name.find_first_of(" ),");
      if (idx != std::string::npos)
      {
         table_name = table_name.substr(0,idx);
      }
   }
   return table_name;
}

sqlite_datasource::sqlite_datasource(parameters const& params)
   : datasource(params),
     extent_(),
     extent_initialized_(false),
     type_(datasource::Vector),
     table_(*params.get<std::string>("table","")),
     metadata_(*params.get<std::string>("metadata","")),
     geometry_field_(*params.get<std::string>("geometry_field","the_geom")),
     key_field_(*params.get<std::string>("key_field","OGC_FID")),
     row_offset_(*params_.get<int>("row_offset",0)),
     row_limit_(*params_.get<int>("row_limit",0)),
     desc_(*params.get<std::string>("type"), *params.get<std::string>("encoding","utf-8")),
     format_(mapnik::wkbGeneric)
{
    boost::optional<std::string> file = params.get<std::string>("file");
    if (!file) throw datasource_exception("missing <file> paramater");

    boost::optional<std::string> wkb = params.get<std::string>("wkb_format");
    if (wkb)
    {
        if (*wkb == "spatialite")
            format_ = mapnik::wkbSpatiaLite;
    }

    multiple_geometries_ = *params_.get<mapnik::boolean>("multiple_geometries",false);
    use_spatial_index_ = *params_.get<mapnik::boolean>("use_spatial_index",true);

    dataset_ = new sqlite_connection (*file);

    boost::optional<std::string> ext  = params_.get<std::string>("extent");
    if (ext)
    {
        boost::char_separator<char> sep(",");
        boost::tokenizer<boost::char_separator<char> > tok(*ext,sep);
        unsigned i = 0;
        bool success = false;
        double d[4];
        for (boost::tokenizer<boost::char_separator<char> >::iterator beg=tok.begin();
             beg!=tok.end();++beg)
        {
            try
            {
                d[i] = boost::lexical_cast<double>(*beg);
            }
            catch (boost::bad_lexical_cast & ex)
            {
                std::clog << ex.what() << "\n";
                break;
            }
            if (i==3)
            {
                success = true;
                break;
            }
            ++i;
        }

        if (success)
        {
            extent_.init(d[0],d[1],d[2],d[3]);
            extent_initialized_ = true;
        }
    }

    std::string table_name = table_from_sql(table_);

    if (metadata_ != "" && ! extent_initialized_)
    {
        std::ostringstream s;
        s << "select xmin, ymin, xmax, ymax from " << metadata_;
        s << " where lower(f_table_name) = lower('" << table_name << "')";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            double xmin = rs->column_double (0);
            double ymin = rs->column_double (1);
            double xmax = rs->column_double (2);
            double ymax = rs->column_double (3);

            extent_.init (xmin,ymin,xmax,ymax);
            extent_initialized_ = true;
        }
    }

    if (use_spatial_index_)
    {
        std::ostringstream s;
        s << "select count (*) from sqlite_master";
        s << " where lower(name) = lower('idx_" << table_name << "_" << geometry_field_ << "')";
        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            use_spatial_index_ = rs->column_integer (0) == 1;
        }

#ifdef MAPNIK_DEBUG
        if (! use_spatial_index_)
           clog << "cannot use the spatial index " << endl;
#endif
    }

    {
        /*
            XXX - This is problematic, if we don't have at least a row,
                  we cannot determine the right columns types and names
                  as all column_type are SQLITE_NULL
        */

        std::string::size_type idx = table_.find(table_name);
        std::ostringstream s;
        s << "select * from (" <<  table_.substr(0,idx + table_name.length()) << ") limit 1";

        boost::scoped_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));
        if (rs->is_valid () && rs->step_next())
        {
            for (int i = 0; i < rs->column_count (); ++i)
            {
               const int type_oid = rs->column_type (i);
               const char* fld_name = rs->column_name (i);
               switch (type_oid)
               {
                  case SQLITE_INTEGER:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Integer));
                     break;

                  case SQLITE_FLOAT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::Double));
                     break;

                  case SQLITE_TEXT:
                     desc_.add_descriptor(attribute_descriptor(fld_name,mapnik::String));
                     break;

                  case SQLITE_NULL:
                  case SQLITE_BLOB:
                     break;

                  default:
#ifdef MAPNIK_DEBUG
                     clog << "unknown type_oid="<<type_oid<<endl;
#endif
                     break;
                }
            }
        }
    }
}

sqlite_datasource::~sqlite_datasource()
{
    delete dataset_;
}

std::string const sqlite_datasource::name_="sqlite";

std::string sqlite_datasource::name()
{
   return name_;
}

int sqlite_datasource::type() const
{
   return type_;
}

Envelope<double> sqlite_datasource::envelope() const
{
   return extent_;
}

layer_descriptor sqlite_datasource::get_descriptor() const
{
   return desc_;
}

featureset_ptr sqlite_datasource::features(query const& q) const
{
   if (dataset_)
   {
        mapnik::Envelope<double> const& e = q.get_bbox();

        std::ostringstream s;

        s << "select " << geometry_field_ << "," << key_field_;
        std::set<std::string> const& props = q.property_names();
        std::set<std::string>::const_iterator pos = props.begin();
        std::set<std::string>::const_iterator end = props.end();
        while (pos != end)
        {
           s << "," << *pos << "";
           ++pos;
        }

        s << " from ";

        std::string query (table_);

        if (use_spatial_index_)
        {
           std::string table_name = table_from_sql(query);
           std::ostringstream spatial_sql;
           spatial_sql << std::setprecision(16);
           spatial_sql << " where rowid in (select pkid from idx_" << table_name << "_" << geometry_field_;
           spatial_sql << " where xmax>=" << e.minx() << " and xmin<=" << e.maxx() ;
           spatial_sql << " and ymax>=" << e.miny() << " and ymin<=" << e.maxy() << ")";
           if (boost::algorithm::ifind_first(query,"where"))
           {
              boost::algorithm::ireplace_first(query, "where", spatial_sql.str() + " and");
           }
           else if (boost::algorithm::find_first(query,table_name))
           {
              boost::algorithm::ireplace_first(query, table_name , table_name + " " + spatial_sql.str());
           }
        }

        s << query ;

        if (row_limit_ > 0) {
            s << " limit " << row_limit_;
        }

        if (row_offset_ > 0) {
            s << " offset " << row_offset_;
        }

#ifdef MAPNIK_DEBUG
        std::cerr << s.str() << "\n";
#endif

        boost::shared_ptr<sqlite_resultset> rs (dataset_->execute_query (s.str()));

        return featureset_ptr (new sqlite_featureset(rs, desc_.get_encoding(), format_, multiple_geometries_));
   }

   return featureset_ptr();
}

featureset_ptr sqlite_datasource::features_at_point(coord2d const& pt) const
{
#if 0
   if (dataset_ && layer_)
   {
        OGRPoint point;
        point.setX (pt.x);
        point.setY (pt.y);

        layer_->SetSpatialFilter (&point);

        return featureset_ptr(new ogr_featureset(*dataset_, *layer_, desc_.get_encoding(), multiple_geometries_));
   }
#endif

   return featureset_ptr();
}

<|endoftext|>


<commit_before><commit_msg>Fix MC 2<commit_after><|endoftext|>


<commit_before>/*
 Flexisip, a flexible SIP proxy server with media capabilities.
 Copyright (C) 2012  Belledonne Communications SARL.

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

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "forkcallcontext.hh"
#include "common.hh"
#include <algorithm>
#include <sofia-sip/sip_status.h>

using namespace ::std;

ForkCallContext::ForkCallContext(Agent *agent, const std::shared_ptr<RequestSipEvent> &event, shared_ptr<ForkContextConfig> cfg, ForkContextListener* listener) :
		ForkContext(agent, event,cfg, listener), mFinal(0),mCancelled(false) {
	LOGD("New ForkCallContext %p", this);

}

ForkCallContext::~ForkCallContext() {
	LOGD("Destroy ForkCallContext %p", this);
}

void ForkCallContext::cancel() {
	mCancelled=true;
	cancelOthers();
}

void ForkCallContext::forward(const shared_ptr<SipEvent> &ev, bool force) {
	sip_t *sip = ev->getMsgSip()->getSip();
	bool fakeSipEvent = (mFinal > 0 && !force) || mIncoming == NULL;

	if (mCfg->mForkOneResponse) { // TODO: respect RFC 3261 16.7.5
		if (sip->sip_status->st_status == 183 || sip->sip_status->st_status == 180) {
			auto it = find(mForwardResponses.begin(), mForwardResponses.end(), sip->sip_status->st_status);
			if (it != mForwardResponses.end()) {
				fakeSipEvent = true;
			} else {
				mForwardResponses.push_back(sip->sip_status->st_status);
			}
		}
	}

	if (fakeSipEvent) {
		ev->setIncomingAgent(shared_ptr<IncomingAgent>());
	}

	if (sip->sip_status->st_status >= 200 && sip->sip_status->st_status < 700) {
		++mFinal;
	}
}

void ForkCallContext::decline(const shared_ptr<OutgoingTransaction> &transaction, shared_ptr<ResponseSipEvent> &ev) {
	if (!mCfg->mForkNoGlobalDecline) {
		cancelOthers(transaction);

		forward(ev);
	} else {
		if (mOutgoings.size() != 1) {
			ev->setIncomingAgent(shared_ptr<IncomingAgent>());
		} else {
			forward(ev);
		}
	}
}

void ForkCallContext::cancelOthers(const shared_ptr<OutgoingTransaction> &transaction) {
	if (mFinal == 0) {
		for (list<shared_ptr<OutgoingTransaction>>::iterator it = mOutgoings.begin(); it != mOutgoings.end();) {
			if (*it != transaction) {
				shared_ptr<OutgoingTransaction> tr = (*it);
				it = mOutgoings.erase(it);
				tr->cancel();
			} else {
				++it;
			}
		}
	}
}

void ForkCallContext::onRequest(const shared_ptr<IncomingTransaction> &transaction, shared_ptr<RequestSipEvent> &event) {
	event->setOutgoingAgent(shared_ptr<OutgoingAgent>());
	const shared_ptr<MsgSip> &ms = event->getMsgSip();
	sip_t *sip = ms->getSip();
	if (sip != NULL && sip->sip_request != NULL) {
		if (sip->sip_request->rq_method == sip_method_cancel) {
			LOGD("Fork: incomingCallback cancel");
			cancel();
		}
	}
}

void ForkCallContext::store(shared_ptr<ResponseSipEvent> &event) {
	bool best = true;

	if (mBestResponse != NULL) {
		if (mBestResponse->getMsgSip()->getSip()->sip_status->st_status < event->getMsgSip()->getSip()->sip_status->st_status) {
			best = false;
		}
	}

	// Save
	if (best) {
		mBestResponse = make_shared<ResponseSipEvent>(event); // Copy event
		mBestResponse->suspendProcessing();
	}

	// Don't forward
	event->setIncomingAgent(shared_ptr<IncomingAgent>());
}

void ForkCallContext::onResponse(const shared_ptr<OutgoingTransaction> &transaction, shared_ptr<ResponseSipEvent> &event) {
	event->setIncomingAgent(mIncoming);
	const shared_ptr<MsgSip> &ms = event->getMsgSip();
	sip_via_remove(ms->getMsg(), ms->getSip()); // remove via
	sip_t *sip = ms->getSip();
	if (sip != NULL && sip->sip_status != NULL) {
		LOGD("Fork: outgoingCallback %d", sip->sip_status->st_status);
		if (sip->sip_status->st_status > 100 && sip->sip_status->st_status < 200) {
			forward(event);
			return;
		} else if (sip->sip_status->st_status >= 200 && sip->sip_status->st_status < 300) {
			if (mCfg->mForkOneResponse) // TODO: respect RFC 3261 16.7.5
				cancelOthers(transaction);
			forward(event, true);
			return;
		} else if (sip->sip_status->st_status >= 600 && sip->sip_status->st_status < 700) {
			decline(transaction, event);
			return;
		} else {
			if (!mCancelled)
				store(event);
			else forward(event,true);
			return;
		}
	}

	LOGW("Outgoing transaction: ignore message");
}

void ForkCallContext::onNew(const shared_ptr<IncomingTransaction> &transaction) {
	ForkContext::onNew(transaction);
}

void ForkCallContext::onDestroy(const shared_ptr<IncomingTransaction> &transaction) {
	return ForkContext::onDestroy(transaction);
}

void ForkCallContext::onNew(const shared_ptr<OutgoingTransaction> &transaction) {
	ForkContext::onNew(transaction);
}

void ForkCallContext::checkFinished(){
	if (mOutgoings.size() == 0 && (mLateTimerExpired || mLateTimer==NULL)) {
		if (mIncoming != NULL && mFinal == 0) {
			if (mBestResponse == NULL) {
				// Create response
				shared_ptr<MsgSip> msgsip(mIncoming->createResponse(SIP_408_REQUEST_TIMEOUT));
				shared_ptr<ResponseSipEvent> ev(new ResponseSipEvent(dynamic_pointer_cast<OutgoingAgent>(mAgent->shared_from_this()), msgsip));
				ev->setIncomingAgent(mIncoming);
				mAgent->sendResponseEvent(ev);
			} else {
				mAgent->injectResponseEvent(mBestResponse); // Reply
			}
			++mFinal;
		}
		mBestResponse.reset();
		mIncoming.reset();
		mListener->onForkContextFinished(shared_from_this());
	}
}

void ForkCallContext::onDestroy(const shared_ptr<OutgoingTransaction> &transaction) {

	ForkContext::onDestroy(transaction);
}

bool ForkCallContext::hasFinalResponse(){
	return mFinal>0 || mCancelled;
}
<commit_msg>After cancel, don't send 408 in Fork call context finished.<commit_after>/*
 Flexisip, a flexible SIP proxy server with media capabilities.
 Copyright (C) 2012  Belledonne Communications SARL.

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

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "forkcallcontext.hh"
#include "common.hh"
#include <algorithm>
#include <sofia-sip/sip_status.h>

using namespace ::std;

ForkCallContext::ForkCallContext(Agent *agent, const std::shared_ptr<RequestSipEvent> &event, shared_ptr<ForkContextConfig> cfg, ForkContextListener* listener) :
		ForkContext(agent, event,cfg, listener), mFinal(0),mCancelled(false) {
	LOGD("New ForkCallContext %p", this);

}

ForkCallContext::~ForkCallContext() {
	LOGD("Destroy ForkCallContext %p", this);
}

void ForkCallContext::cancel() {
	mCancelled=true;
	cancelOthers();
}

void ForkCallContext::forward(const shared_ptr<SipEvent> &ev, bool force) {
	sip_t *sip = ev->getMsgSip()->getSip();
	bool fakeSipEvent = (mFinal > 0 && !force) || mIncoming == NULL;

	if (mCfg->mForkOneResponse) { // TODO: respect RFC 3261 16.7.5
		if (sip->sip_status->st_status == 183 || sip->sip_status->st_status == 180) {
			auto it = find(mForwardResponses.begin(), mForwardResponses.end(), sip->sip_status->st_status);
			if (it != mForwardResponses.end()) {
				fakeSipEvent = true;
			} else {
				mForwardResponses.push_back(sip->sip_status->st_status);
			}
		}
	}

	if (fakeSipEvent) {
		ev->setIncomingAgent(shared_ptr<IncomingAgent>());
	}

	if (sip->sip_status->st_status >= 200 && sip->sip_status->st_status < 700) {
		++mFinal;
	}
}

void ForkCallContext::decline(const shared_ptr<OutgoingTransaction> &transaction, shared_ptr<ResponseSipEvent> &ev) {
	if (!mCfg->mForkNoGlobalDecline) {
		cancelOthers(transaction);

		forward(ev);
	} else {
		if (mOutgoings.size() != 1) {
			ev->setIncomingAgent(shared_ptr<IncomingAgent>());
		} else {
			forward(ev);
		}
	}
}

void ForkCallContext::cancelOthers(const shared_ptr<OutgoingTransaction> &transaction) {
	if (mFinal == 0) {
		for (list<shared_ptr<OutgoingTransaction>>::iterator it = mOutgoings.begin(); it != mOutgoings.end();) {
			if (*it != transaction) {
				shared_ptr<OutgoingTransaction> tr = (*it);
				it = mOutgoings.erase(it);
				tr->cancel();
			} else {
				++it;
			}
		}
	}
}

void ForkCallContext::onRequest(const shared_ptr<IncomingTransaction> &transaction, shared_ptr<RequestSipEvent> &event) {
	event->setOutgoingAgent(shared_ptr<OutgoingAgent>());
	const shared_ptr<MsgSip> &ms = event->getMsgSip();
	sip_t *sip = ms->getSip();
	if (sip != NULL && sip->sip_request != NULL) {
		if (sip->sip_request->rq_method == sip_method_cancel) {
			LOGD("Fork: incomingCallback cancel");
			cancel();
		}
	}
}

void ForkCallContext::store(shared_ptr<ResponseSipEvent> &event) {
	bool best = true;

	if (mBestResponse != NULL) {
		if (mBestResponse->getMsgSip()->getSip()->sip_status->st_status < event->getMsgSip()->getSip()->sip_status->st_status) {
			best = false;
		}
	}

	// Save
	if (best) {
		mBestResponse = make_shared<ResponseSipEvent>(event); // Copy event
		mBestResponse->suspendProcessing();
	}

	// Don't forward
	event->setIncomingAgent(shared_ptr<IncomingAgent>());
}

void ForkCallContext::onResponse(const shared_ptr<OutgoingTransaction> &transaction, shared_ptr<ResponseSipEvent> &event) {
	event->setIncomingAgent(mIncoming);
	const shared_ptr<MsgSip> &ms = event->getMsgSip();
	sip_via_remove(ms->getMsg(), ms->getSip()); // remove via
	sip_t *sip = ms->getSip();
	if (sip != NULL && sip->sip_status != NULL) {
		LOGD("Fork: outgoingCallback %d", sip->sip_status->st_status);
		if (sip->sip_status->st_status > 100 && sip->sip_status->st_status < 200) {
			forward(event);
			return;
		} else if (sip->sip_status->st_status >= 200 && sip->sip_status->st_status < 300) {
			if (mCfg->mForkOneResponse) // TODO: respect RFC 3261 16.7.5
				cancelOthers(transaction);
			forward(event, true);
			return;
		} else if (sip->sip_status->st_status >= 600 && sip->sip_status->st_status < 700) {
			decline(transaction, event);
			return;
		} else {
			if (!mCancelled)
				store(event);
			else forward(event,true);
			return;
		}
	}

	LOGW("Outgoing transaction: ignore message");
}

void ForkCallContext::onNew(const shared_ptr<IncomingTransaction> &transaction) {
	ForkContext::onNew(transaction);
}

void ForkCallContext::onDestroy(const shared_ptr<IncomingTransaction> &transaction) {
	return ForkContext::onDestroy(transaction);
}

void ForkCallContext::onNew(const shared_ptr<OutgoingTransaction> &transaction) {
	ForkContext::onNew(transaction);
}

void ForkCallContext::checkFinished(){
	if (mOutgoings.size() == 0 && (mLateTimerExpired || mLateTimer==NULL)) {
		if (mIncoming != NULL && !hasFinalResponse()) {
			if (mBestResponse == NULL) {
				// Create response
				shared_ptr<MsgSip> msgsip(mIncoming->createResponse(SIP_408_REQUEST_TIMEOUT));
				shared_ptr<ResponseSipEvent> ev(new ResponseSipEvent(dynamic_pointer_cast<OutgoingAgent>(mAgent->shared_from_this()), msgsip));
				ev->setIncomingAgent(mIncoming);
				mAgent->sendResponseEvent(ev);
			} else {
				mAgent->injectResponseEvent(mBestResponse); // Reply
			}
			++mFinal;
		}
		mBestResponse.reset();
		mIncoming.reset();
		mListener->onForkContextFinished(shared_from_this());
	}
}

void ForkCallContext::onDestroy(const shared_ptr<OutgoingTransaction> &transaction) {

	ForkContext::onDestroy(transaction);
}

bool ForkCallContext::hasFinalResponse(){
	return mFinal>0 || mCancelled;
}
<|endoftext|>


<commit_before>// Time:  O(n^2)
// Space: O(n)

/**
 * // This is the Master's API interface.
 * // You should not implement it, or speculate about its implementation
 * class Master {
 *   public:
 *     int guess(string word);
 * };
 */
class Solution {
public:
    void findSecretWord(vector<string>& wordlist, Master& master) {
        vector<vector<int>> H(wordlist.size(), vector<int>(wordlist.size()));
        for (int i = 0; i < wordlist.size(); ++i) {
            for (int j = 0; j < wordlist.size(); ++j) {
                H[i][j] = match(wordlist[i], wordlist[j]);
            }
        }

        vector<int> possible(wordlist.size());
        iota(possible.begin(), possible.end(), 0);
        int n = 0;
        while (!possible.empty() && n < 6) {
            auto guess = solve(H, possible);
            n = master.guess(wordlist[guess]);
            vector<int> new_possible;
            for (const auto& j : possible) {
                if (H[guess][j] == n) {
                    new_possible.emplace_back(j);
                }
            }
            possible = new_possible;
        }
    }

private:
    int solve(const vector<vector<int>>& H,
              const vector<int>& possible) {

        vector<int> min_max_group = possible;
        int best_guess = -1;
        for (const auto& guess : possible) {
            vector<vector<int>> groups(7);
            for (const auto& j : possible) {
                if (j != guess) {
                    groups[H[guess][j]].emplace_back(j);
                }
            }
            int max_group_i = 0;
            for (int i = 0; i < groups.size(); ++i) {
                if (groups[i].size() > groups[max_group_i].size()) {
                    max_group_i = i;
                }
            }
            if (groups[max_group_i].size() < min_max_group.size()) {
                min_max_group = groups[max_group_i];
                best_guess = guess;
            }
        }
        return best_guess;
    }

    int match(const string& a, const string& b) {
        int matches = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] == b[i]) {
                ++matches;
            }
        }
        return matches;
    }
};

// Time:  O(n^2)
// Space: O(n)
class Solution2 {
public:
    void findSecretWord(vector<string>& wordlist, Master& master) {
        for (int i = 0, n = 0; i < 10 && n < 6; ++i) {
            unordered_map<string, int> count;
            for (const auto& w1 : wordlist) {
                for (const auto& w2 : wordlist) {
                    if (match(w1, w2) == 0) {
                        ++count[w1];
                    }
                }
            }
            string guess;
            for (const auto& w : wordlist) {
                if (guess.empty() ||
                    count[w] < count[guess]) {
                    guess = w;
                }
            }
            n = master.guess(guess);
            vector<string> new_wordlist;
            for (const auto& w : wordlist) {
                if (match(w, guess) == n) {
                    new_wordlist.emplace_back(w);
                }
            }
            wordlist = new_wordlist;
        }
    }

private:
    int match(const string& a, const string& b) {
        int matches = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] == b[i]) {
                ++matches;
            }
        }
        return matches;
    }
};
<commit_msg>Update guess-the-word.cpp<commit_after>// Time:  O(n^2)
// Space: O(n)

/**
 * // This is the Master's API interface.
 * // You should not implement it, or speculate about its implementation
 * class Master {
 *   public:
 *     int guess(string word);
 * };
 */
class Solution {
public:
    void findSecretWord(vector<string>& wordlist, Master& master) {
        vector<vector<int>> H(wordlist.size(), vector<int>(wordlist.size()));
        for (int i = 0; i < wordlist.size(); ++i) {
            for (int j = 0; j < wordlist.size(); ++j) {
                H[i][j] = match(wordlist[i], wordlist[j]);
            }
        }

        vector<int> possible(wordlist.size());
        iota(possible.begin(), possible.end(), 0);
        int n = 0;
        while (n < 6) {
            auto guess = solve(H, possible);
            n = master.guess(wordlist[guess]);
            vector<int> new_possible;
            for (const auto& j : possible) {
                if (H[guess][j] == n) {
                    new_possible.emplace_back(j);
                }
            }
            possible = new_possible;
        }
    }

private:
    int solve(const vector<vector<int>>& H,
              const vector<int>& possible) {

        vector<int> min_max_group = possible;
        int best_guess = -1;
        for (const auto& guess : possible) {
            vector<vector<int>> groups(7);
            for (const auto& j : possible) {
                if (j != guess) {
                    groups[H[guess][j]].emplace_back(j);
                }
            }
            int max_group_i = 0;
            for (int i = 0; i < groups.size(); ++i) {
                if (groups[i].size() > groups[max_group_i].size()) {
                    max_group_i = i;
                }
            }
            if (groups[max_group_i].size() < min_max_group.size()) {
                min_max_group = groups[max_group_i];
                best_guess = guess;
            }
        }
        return best_guess;
    }

    int match(const string& a, const string& b) {
        int matches = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] == b[i]) {
                ++matches;
            }
        }
        return matches;
    }
};

// Time:  O(n^2)
// Space: O(n)
class Solution2 {
public:
    void findSecretWord(vector<string>& wordlist, Master& master) {
        vector<vector<int>> H(wordlist.size(), vector<int>(wordlist.size()));
        for (int i = 0; i < wordlist.size(); ++i) {
            for (int j = 0; j < wordlist.size(); ++j) {
                H[i][j] = match(wordlist[i], wordlist[j]);
            }
        }

        vector<int> possible(wordlist.size());
        iota(possible.begin(), possible.end(), 0);
        int n = 0;
        while (n < 6) {
            auto guess = solve(H, possible);
            n = master.guess(wordlist[guess]);
            vector<int> new_possible;
            for (const auto& j : possible) {
                if (H[guess][j] == n) {
                    new_possible.emplace_back(j);
                }
            }
            possible = new_possible;
        }
    }

private:
    int solve(const vector<vector<int>>& H,
              const vector<int>& possible) {

        vector<int> min_max_group = possible;
        int best_guess = -1;
        for (const auto& guess : possible) {
            vector<vector<int>> groups(7);
            for (const auto& j : possible) {
                if (j != guess) {
                    groups[H[guess][j]].emplace_back(j);
                }
            }
            int max_group_i = 0;
            if (groups[max_group_i].size() < min_max_group.size()) {
                min_max_group = groups[max_group_i];
                best_guess = guess;
            }
        }
        return best_guess;
    }

    int match(const string& a, const string& b) {
        int matches = 0;
        for (int i = 0; i < a.length(); ++i) {
            if (a[i] == b[i]) {
                ++matches;
            }
        }
        return matches;
    }
};
<|endoftext|>